unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Emacs's set-frame-size can not work well with gnome-shell?
@ 2020-01-10  2:34 tumashu
  2020-01-10  9:56 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: tumashu @ 2020-01-10  2:34 UTC (permalink / raw)
  To: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 839 bytes --]

Hello:


When I use child-frame with gnome-shell, I find that set-frame-size is very slow and can not resize at all.
Is it emacs's problem or gnome problem?


```
(defun open-test (buffer)
  (display-buffer-in-child-frame
   buffer '((child-frame-parameters
             . ((width . 40)
                (height . 10)
                (top . 50)
                (left . 50)
                )))))

(defun resize-test (frame)
  (set-frame-height frame 20))

(setq-local test-buffer (get-buffer-create "test child-frame"))
(setq-local test-frame (window-frame (open-test test-buffer)))

(resize-test test-frame)
```
The below links are relate infos of this problem:

1. https://gitlab.gnome.org/GNOME/gnome-shell/issues/1733

2. https://github.com/tumashu/company-posframe/issues/17

3. https://github.com/tumashu/company-posframe/issues/2





[-- Attachment #2: Type: text/html, Size: 1765 bytes --]

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-10  2:34 Emacs's set-frame-size can not work well with gnome-shell? tumashu
@ 2020-01-10  9:56 ` martin rudalics
  2020-01-11  1:29   ` tumashu
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-10  9:56 UTC (permalink / raw)
  To: tumashu, emacs-devel@gnu.org

 > When I use child-frame with gnome-shell, I find that set-frame-size is very slow and can not resize at all.
 > Is it emacs's problem or gnome problem?
 >
 >
 > ```
 > (defun open-test (buffer)
 >    (display-buffer-in-child-frame
 >     buffer '((child-frame-parameters
 >               . ((width . 40)
 >                  (height . 10)
 >                  (top . 50)
 >                  (left . 50)
 >                  )))))
 >
 > (defun resize-test (frame)
 >    (set-frame-height frame 20))
 >
 > (setq-local test-buffer (get-buffer-create "test child-frame"))
 > (setq-local test-frame (window-frame (open-test test-buffer)))
 >
 > (resize-test test-frame)
 > ```
 > The below links are relate infos of this problem:
 >
 > 1. https://gitlab.gnome.org/GNOME/gnome-shell/issues/1733
 >
 > 2. https://github.com/tumashu/company-posframe/issues/17
 >
 > 3. https://github.com/tumashu/company-posframe/issues/2

Both, 'display-buffer-in-child-frame' and 'set-frame-height', should
be written in a way that the child frame surely fits into its parent.
If you don't, the window manager might do strange things.

Also, I would disable all decorations that are not strictly needed.
For example, with a GTK build using your parameters I get a tool bar
on the child frame as soon as I type some character into it (which
might be an Emacs bug in one or the other way).  That tool bar is
truncated and GTK may not behave well with truncated tool bars.  See
section 29.14 of the Elisp manual for what better not to do on child
frames.

If neither of these helps, we would have to look into how Gnome-shell
treats child windows.  Gnome-shell seems particular (see Bug#38452).

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re:Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-10  9:56 ` martin rudalics
@ 2020-01-11  1:29   ` tumashu
  2020-01-11  7:50     ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: tumashu @ 2020-01-11  1:29 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 2229 bytes --]







--
发自我的网易邮箱手机智能版
<br/><br/><br/>


----- Original Message -----
From: "martin rudalics" <rudalics@gmx.at>
To: tumashu <tumashu@163.com>, "emacs-devel@gnu.org" <emacs-devel@gnu.org>
Sent: Fri, 10 Jan 2020 10:56:39 +0100
Subject: Re: Emacs's set-frame-size can not work well with gnome-shell?

 > When I use child-frame with gnome-shell, I find that set-frame-size is very slow and can not resize at all.
 > Is it emacs's problem or gnome problem?
 >
 >
 > ```
 > (defun open-test (buffer)
 >    (display-buffer-in-child-frame
 >     buffer '((child-frame-parameters
 >               . ((width . 40)
 >                  (height . 10)
 >                  (top . 50)
 >                  (left . 50)
 >                  )))))
 >
 > (defun resize-test (frame)
 >    (set-frame-height frame 20))
 >
 > (setq-local test-buffer (get-buffer-create "test child-frame"))
 > (setq-local test-frame (window-frame (open-test test-buffer)))
 >
 > (resize-test test-frame)
 > ```
 > The below links are relate infos of this problem:
 >
 > 1. https://gitlab.gnome.org/GNOME/gnome-shell/issues/1733
 >
 > 2. https://github.com/tumashu/company-posframe/issues/17
 >
 > 3. https://github.com/tumashu/company-posframe/issues/2

Both, 'display-buffer-in-child-frame' and 'set-frame-height', should
be written in a way that the child frame surely fits into its parent.
If you don't, the window manager might do strange things.

Sorry, i do not understand this, more detail or an example?

Also, I would disable all decorations that are not strictly needed.
For example, with a GTK build using your parameters I get a tool bar
on the child frame as soon as I type some character into it (which
might be an Emacs bug in one or the other way).  That tool bar is
truncated and GTK may not behave well with truncated tool bars.  See
section 29.14 of the Elisp manual for what better not to do on child
frames.

i think it is not toolbar's problem,posframe use childframe without toolbar, has resize problem too,



If neither of these helps, we would have to look into how Gnome-shell
treats child windows.  Gnome-shell seems particular (see Bug#38452). 


i think it may be gnome-shell problem, for other wm has no this problem

martin

[-- Attachment #2: Type: text/html, Size: 4412 bytes --]

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-11  1:29   ` tumashu
@ 2020-01-11  7:50     ` martin rudalics
  2020-01-11  9:56       ` Dmitry Gutov
  2020-01-11 10:36       ` tumashu
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-11  7:50 UTC (permalink / raw)
  To: tumashu; +Cc: emacs-devel@gnu.org

 >   > (defun open-test (buffer)
 >   >    (display-buffer-in-child-frame
 >   >     buffer '((child-frame-parameters
 >   >               . ((width . 40)
 >   >                  (height . 10)
 >   >                  (top . 50)
 >   >                  (left . 50)
 >   >                  )))))
 >   >
 >   > (defun resize-test (frame)
 >   >    (set-frame-height frame 20))
 >   >
 >   > (setq-local test-buffer (get-buffer-create "test child-frame"))
 >   > (setq-local test-frame (window-frame (open-test test-buffer)))
 >   >
 >   > (resize-test test-frame)
[...]
 > Both, 'display-buffer-in-child-frame' and 'set-frame-height', should
 > be written in a way that the child frame surely fits into its parent.
 > If you don't, the window manager might do strange things.
 >
 > Sorry, i do not understand this, more detail or an example?

I meant that resizing the child frame from 10 to 20 lines with the
given (50, 50) position might make edges of the child frame exceed the
edges of its parent and the window manager might not like that.  In
particular, a program like GNOME-shell that, as we've seen in
Bug#38452, seems to have its own interpretation of coordinates (I have
no idea what GNOME-shell is and does).

 > Also, I would disable all decorations that are not strictly needed.
 > For example, with a GTK build using your parameters I get a tool bar
 > on the child frame as soon as I type some character into it (which
 > might be an Emacs bug in one or the other way).  That tool bar is
 > truncated and GTK may not behave well with truncated tool bars.  See
 > section 29.14 of the Elisp manual for what better not to do on child
 > frames.
 >
 > i think it is not toolbar's problem,posframe use childframe without toolbar, has resize problem too,

Is it resizing only or moving the frame too?

 > i think it may be gnome-shell problem, for other wm has no this problem

Maybe we should contact their developers.  Here, moving and sizing
child frames seems noticeably smoother with my Windows builds than
with my Debian builds.

martin




^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-11  7:50     ` martin rudalics
@ 2020-01-11  9:56       ` Dmitry Gutov
  2020-01-11 10:19         ` martin rudalics
  2020-01-11 10:36       ` tumashu
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-11  9:56 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 11.01.2020 9:50, martin rudalics wrote:
> Maybe we should contact their developers.

Will you do that?

The first message in this thread has a link to a bug report to 
gnome-shell (redirected to 
https://gitlab.gnome.org/GNOME/mutter/issues/840). With no responses.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-11  9:56       ` Dmitry Gutov
@ 2020-01-11 10:19         ` martin rudalics
  2020-01-11 10:21           ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-11 10:19 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> Maybe we should contact their developers.
 >
 > Will you do that?

I don't have GNOME-shell installed and cannot really test anything.
So please someone else step up.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-11 10:19         ` martin rudalics
@ 2020-01-11 10:21           ` Dmitry Gutov
  2020-01-11 10:35             ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-11 10:21 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 11.01.2020 12:19, martin rudalics wrote:
> 
> I don't have GNOME-shell installed and cannot really test anything.
> So please someone else step up.

OK, so how do you recommend we proceed? There is already a bug report.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-11 10:21           ` Dmitry Gutov
@ 2020-01-11 10:35             ` martin rudalics
  2020-01-11 11:21               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-11 10:35 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > OK, so how do you recommend we proceed? There is already a bug report.

No idea.  Is there even a common agreement that the people who see
this are actually using mutter?  Do you use it?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re:Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-11  7:50     ` martin rudalics
  2020-01-11  9:56       ` Dmitry Gutov
@ 2020-01-11 10:36       ` tumashu
  2020-01-11 13:45         ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: tumashu @ 2020-01-11 10:36 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel@gnu.org


>I meant that resizing the child frame from 10 to 20 lines with the
>given (50, 50) position might make edges of the child frame exceed the
>edges of its parent and the window manager might not like that.  In
>particular, a program like GNOME-shell that, as we've seen in
>Bug#38452, seems to have its own interpretation of coordinates (I have
>no idea what GNOME-shell is and does).

I think resizing problem is not this reason.

>Is it resizing only or moving the frame too?

I think resizing only,  moving works well.

>
> > i think it may be gnome-shell problem, for other wm has no this problem
>
>Maybe we should contact their developers.  Here, moving and sizing
>child frames seems noticeably smoother with my Windows builds than
>with my Debian builds.
>
>martin
>

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-11 10:35             ` martin rudalics
@ 2020-01-11 11:21               ` Dmitry Gutov
  2020-01-11 13:45                 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-11 11:21 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 11.01.2020 12:35, martin rudalics wrote:
> 
> No idea.  Is there even a common agreement that the people who see
> this are actually using mutter?  Do you use it?

Yes, of course. Mutter and GNOME 3.32.1.

BTW, the problem with set-frame-size seems to affect child frames only, 
the regular frames get resized all right. So maybe there's something we 
can troubleshoot ourselves here.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-11 10:36       ` tumashu
@ 2020-01-11 13:45         ` martin rudalics
  0 siblings, 0 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-11 13:45 UTC (permalink / raw)
  To: tumashu; +Cc: emacs-devel@gnu.org

 >> In
 >> particular, a program like GNOME-shell that, as we've seen in
 >> Bug#38452, seems to have its own interpretation of coordinates (I have
 >> no idea what GNOME-shell is and does).
 >
 > I think resizing problem is not this reason.

Unless mutter decides that it may have to move the child frame because
resizing would clash with some of its internal positioning constraints.

 >> Is it resizing only or moving the frame too?
 >
 > I think resizing only,  moving works well.

Does resizing fail always?  Even with 'frame-resize-pixelwise' non-nil
and shrinking or increasing an edge by one pixel only?

Please look also at the questions I asked Dmitry.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-11 11:21               ` Dmitry Gutov
@ 2020-01-11 13:45                 ` martin rudalics
  2020-01-14  2:09                   ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-11 13:45 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > BTW, the problem with set-frame-size seems to affect child frames
 > only, the regular frames get resized all right. So maybe there's
 > something we can troubleshoot ourselves here.

We can try:

- Does setting the 'height' and 'width' frame parameter fail the same
   way?  Does setting 'user-size' change anything?

- Are the arguments we pass to gtk_window_resize (around line 1004 of
   xg_frame_set_char_size in gtkutil.c) OK in your opinion?

- Do you see any special messages when running Emacs from a console?

- What does (frame-geometry) return for the frame before and after the
   failed resizing attempt?

- What does (frame-geometry) return when you create that child frame
   right away with the parameters it should have after resizing?

- Can you reproduce Bug#38452?

Thanks, martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-11 13:45                 ` martin rudalics
@ 2020-01-14  2:09                   ` Dmitry Gutov
  2020-01-14 15:50                     ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-14  2:09 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 11.01.2020 16:45, martin rudalics wrote:
>  > BTW, the problem with set-frame-size seems to affect child frames
>  > only, the regular frames get resized all right. So maybe there's
>  > something we can troubleshoot ourselves here.
> 
> We can try:
> 
> - Does setting the 'height' and 'width' frame parameter fail the same
>    way?  Does setting 'user-size' change anything?

No change. Hopefully I'm testing it right.

> - Are the arguments we pass to gtk_window_resize (around line 1004 of
>    xg_frame_set_char_size in gtkutil.c) OK in your opinion?

Umm, I'd really have to study the code to answer. I don't know this part 
of Emacs at all.

Or do you want be to run it in debugger?

> - Do you see any special messages when running Emacs from a console?

None.

And so far, my only guess is: GNOME doesn't resize non-decorated 
windows. Or our code doesn't. Because set-frame-size likewise fails for 
fullscreen (or even half-screen) windows, and they lack most of the 
decorations as well (aside from one window border).

> - What does (frame-geometry) return for the frame before and after the
>    failed resizing attempt?

It's unchanged, and returns e.g.

((outer-position 2037 . 183)
  (outer-size 768 . 360)
  (external-border-size 0 . 0)
  (outer-border-width . 0)
  (title-bar-size 0 . 0)
  (menu-bar-external . t)
  (menu-bar-size 0 . 0)
  (tab-bar-size 0 . 0)
  (tool-bar-external . t)
  (tool-bar-position . top)
  (tool-bar-size 0 . 0)
  (internal-border-width . 0))

> - What does (frame-geometry) return when you create that child frame
>    right away with the parameters it should have after resizing?

((outer-position 2037 . 183)
  (outer-size 768 . 720)
  (external-border-size 0 . 0)
  (outer-border-width . 0)
  (title-bar-size 0 . 0)
  (menu-bar-external . t)
  (menu-bar-size 0 . 0)
  (tab-bar-size 0 . 0)
  (tool-bar-external . t)
  (tool-bar-position . top)
  (tool-bar-size 0 . 0)
  (internal-border-width . 0))

> - Can you reproduce Bug#38452?

Yes. Every evaluation of the form in the first message shifts a simple, 
non-maximized frame a bit up-left by (24 . 22).



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-14  2:09                   ` Dmitry Gutov
@ 2020-01-14 15:50                     ` martin rudalics
  2020-01-15  1:31                       ` Dmitry Gutov
  2020-01-16  0:04                       ` Dmitry Gutov
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-14 15:50 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

  the arguments we pass to gtk_window_resize (around line 1004 of
 >>    xg_frame_set_char_size in gtkutil.c) OK in your opinion?
 >
 > Umm, I'd really have to study the code to answer. I don't know this part of Emacs at all.
 >
 > Or do you want be to run it in debugger?

Run it under gdb with a breakpoint like

break gtkutil.c:1004

and continue until it is hit by tumashu's 'resize-test' invocation.
Then do p totalwidth and p totalheight (here they are 390 and 360).

 > And so far, my only guess is: GNOME doesn't resize non-decorated windows. Or our code doesn't. Because set-frame-size likewise fails for fullscreen (or even half-screen) windows, and they lack most of the decorations as well (aside from one window border).

That's easy to check: Just create a new undecorated, non-child frame and
see whether you can resize it.

 >> - What does (frame-geometry) return for the frame before and after the
 >>    failed resizing attempt?
 >
 > It's unchanged, and returns e.g.
 >
 > ((outer-position 2037 . 183)
 >   (outer-size 768 . 360)
[...]
 >> - What does (frame-geometry) return when you create that child frame
 >>    right away with the parameters it should have after resizing?
 >
 > ((outer-position 2037 . 183)
 >   (outer-size 768 . 720)
[...]

These look fishy to me.  Here the resized child frame has

((outer-position 55 . 141)
  (outer-size 390 . 402)
  (external-border-size 0 . 0)
  (outer-border-width . 0)
  (title-bar-size 0 . 0)
  (menu-bar-external . t)
  (menu-bar-size 0 . 0)
  (tab-bar-size 0 . 0)
  (tool-bar-external . t)
  (tool-bar-position . top)
  (tool-bar-size 390 . 42)
  (internal-border-width . 0))

I doubt that at a position of 2037 much resizing can be done.  In either
case, the outer height of your child frame _has_ changed from 360 to 720
or at least 'frame-geometry' is told so.  What position do you get when
you put the child frame at (0, 0) of its parent?  Is yours by chance a
high-resolution display?

 >> - Can you reproduce Bug#38452?
 >
 > Yes. Every evaluation of the form in the first message shifts a simple, non-maximized frame a bit up-left by (24 . 22).

Maybe that's the core of our problem.  Either mutter doesn't want to
put the frame where Emacs asks to put it or we don't understand where
mutter has put it.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-14 15:50                     ` martin rudalics
@ 2020-01-15  1:31                       ` Dmitry Gutov
  2020-01-15  8:08                         ` martin rudalics
  2020-01-16  0:04                       ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-15  1:31 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 14.01.2020 18:50, martin rudalics wrote:

> Run it under gdb with a breakpoint like
> 
> break gtkutil.c:1004
> 
> and continue until it is hit by tumashu's 'resize-test' invocation.
> Then do p totalwidth and p totalheight (here they are 390 and 360).

Will do, tomorrow.

>  > And so far, my only guess is: GNOME doesn't resize non-decorated 
> windows. Or our code doesn't. Because set-frame-size likewise fails for 
> fullscreen (or even half-screen) windows, and they lack most of the 
> decorations as well (aside from one window border).
> 
> That's easy to check: Just create a new undecorated, non-child frame and
> see whether you can resize it.

Any code I can try?

> These look fishy to me.  Here the resized child frame has
> 
> ((outer-position 55 . 141)
>   (outer-size 390 . 402)
>   (external-border-size 0 . 0)
>   (outer-border-width . 0)
>   (title-bar-size 0 . 0)
>   (menu-bar-external . t)
>   (menu-bar-size 0 . 0)
>   (tab-bar-size 0 . 0)
>   (tool-bar-external . t)
>   (tool-bar-position . top)
>   (tool-bar-size 390 . 42)
>   (internal-border-width . 0))
> 
> I doubt that at a position of 2037 much resizing can be done.  In either
> case, the outer height of your child frame _has_ changed from 360 to 720
> or at least 'frame-geometry' is told so.

When I created it with the appropriate size, frame-geometry reflected 
it, yes.

> What position do you get when
> you put the child frame at (0, 0) of its parent?

((outer-position 1987 . 50)
  (outer-size 736 . 390)
  (external-border-size 0 . 0)
  (outer-border-width . 0)
  (title-bar-size 0 . 0)
  (menu-bar-external . t)
  (menu-bar-size 0 . 0)
  (tab-bar-size 0 . 0)
  (tool-bar-external . t)
  (tool-bar-position . top)
  (tool-bar-size 0 . 0)
  (internal-border-width . 0))

> Is yours by chance a
> high-resolution display?

Yes, HiDPI. 3840x2160. And I also moved the window to the right side of 
the screen for convenience. So the numbers should be right, and there's 
certainly enough space for the child frame to be resized (it's much 
smaller than the parent frame).

>  >> - Can you reproduce Bug#38452?
>  >
>  > Yes. Every evaluation of the form in the first message shifts a 
> simple, non-maximized frame a bit up-left by (24 . 22).
> 
> Maybe that's the core of our problem.  Either mutter doesn't want to
> put the frame where Emacs asks to put it or we don't understand where
> mutter has put it.

But that other bug report is about positioning, isn't it? And this 
discussion is about resizing.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-15  1:31                       ` Dmitry Gutov
@ 2020-01-15  8:08                         ` martin rudalics
  2020-01-15 23:53                           ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-15  8:08 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> That's easy to check: Just create a new undecorated, non-child frame and
 >> see whether you can resize it.
 >
 > Any code I can try?

(setq frame (make-frame '((undecorated . t))))

to make such a frame and for example

(set-frame-size frame 40 40)

to resize it.  Try other values as well to verify.

 >> I doubt that at a position of 2037 much resizing can be done.  In either
 >> case, the outer height of your child frame _has_ changed from 360 to 720
 >> or at least 'frame-geometry' is told so.
 >
 > When I created it with the appropriate size, frame-geometry reflected it, yes.

Sorry, I misread your message and thought the second 'frame-geometry'
call reflected the frame's state after the failed resizing attempt.  And
I also thought that the outer position returned by 'frame-geometry' is
relative to its parent.  It isn't (correctly so).  Only 'frame-position'
returns the parent-relative value.

 >> Is yours by chance a
 >> high-resolution display?
 >
 > Yes, HiDPI. 3840x2160. And I also moved the window to the right side of the screen for convenience. So the numbers should be right, and there's certainly enough space for the child frame to be resized (it's much smaller than the parent frame).
 >
 >>  >> - Can you reproduce Bug#38452?
 >>  >
 >>  > Yes. Every evaluation of the form in the first message shifts a simple, non-maximized frame a bit up-left by (24 . 22).
 >>
 >> Maybe that's the core of our problem.  Either mutter doesn't want to
 >> put the frame where Emacs asks to put it or we don't understand where
 >> mutter has put it.
 >
 > But that other bug report is about positioning, isn't it? And this discussion is about resizing.

Maybe it's the same issue and maybe the effect multiplies on HiDPI
displays.  Here (no HiDPI) I can use the following, slightly modified,
version of tumashu's test case:


(defun open-test (buffer)
   (display-buffer-in-child-frame
    buffer '((child-frame-parameters
              . ((width . 40)
                 (height . 10)
                 (top . 50)
                 (left . 50)
		(drag-with-mode-line . t)
                 )))))

(defun resize-test (frame)
   (set-frame-height frame 20))

(defun move-test (frame)
   (set-frame-position frame 0 0))

(setq-local test-buffer (get-buffer-create "*test child-frame*"))
(setq-local test-frame (window-frame (open-test test-buffer)))

(resize-test test-frame)
;(move-test test-frame)


Does it move 'test-frame'  when you evaluate the last (commented out) form?
Can you move around 'test-frame' by mouse-dragging its mode line?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-15  8:08                         ` martin rudalics
@ 2020-01-15 23:53                           ` Dmitry Gutov
  2020-01-16  8:03                             ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-15 23:53 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 15.01.2020 11:08, martin rudalics wrote:
>  >> That's easy to check: Just create a new undecorated, non-child frame 
> and
>  >> see whether you can resize it.
>  >
>  > Any code I can try?
> 
> (setq frame (make-frame '((undecorated . t))))
> 
> to make such a frame and for example
> 
> (set-frame-size frame 40 40)
> 
> to resize it.  Try other values as well to verify.

This works just fine, with various values. So that's it for the 
"undecorated" idea.

> Maybe it's the same issue and maybe the effect multiplies on HiDPI
> displays.  Here (no HiDPI) I can use the following, slightly modified,
> version of tumashu's test case:
> 
> 
> (defun open-test (buffer)
>    (display-buffer-in-child-frame
>     buffer '((child-frame-parameters
>               . ((width . 40)
>                  (height . 10)
>                  (top . 50)
>                  (left . 50)
>          (drag-with-mode-line . t)
>                  )))))
> 
> (defun resize-test (frame)
>    (set-frame-height frame 20))
> 
> (defun move-test (frame)
>    (set-frame-position frame 0 0))
> 
> (setq-local test-buffer (get-buffer-create "*test child-frame*"))
> (setq-local test-frame (window-frame (open-test test-buffer)))
> 
> (resize-test test-frame)
> ;(move-test test-frame)
> 
> 
> Does it move 'test-frame'  when you evaluate the last (commented out) form?

Yes. And I can evaluate (set-frame-position test-frame x y) with 
different arguments. All are honored (positive or negative). The child 
frame moves.

And if it moves so far that it doesn't fit the bounds of the parent 
frame, the extra area is cut off by the WM. Which is probably the 
expected behavior.

> Can you move around 'test-frame' by mouse-dragging its mode line?

I can't make it work at all, neither in the child frame, nor in any 
normal frame, independent of how the frame parameter was set.

Moving the mode-line with the mouse to resize windows (when e.g. 
minibuffer is active) totally works, but moving the frame this way when 
minibuffer is inactive doesn't work anywhere.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-14 15:50                     ` martin rudalics
  2020-01-15  1:31                       ` Dmitry Gutov
@ 2020-01-16  0:04                       ` Dmitry Gutov
  2020-01-16  8:04                         ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-16  0:04 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 14.01.2020 18:50, martin rudalics wrote:
> 
> Run it under gdb with a breakpoint like
> 
> break gtkutil.c:1004
> 
> and continue until it is hit by tumashu's 'resize-test' invocation.
> Then do p totalwidth and p totalheight (here they are 390 and 360).

Here are the last hits. The first two during the frame's creation:

Thread 1 "emacs" hit Breakpoint 1, xg_frame_set_char_size 
(f=f@entry=0x55555719fae0, width=width@entry=720, 
height=height@entry=360) at gtkutil.c:1004
1004	      gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
(gdb) p totalwidth
$3 = 368
(gdb) p totalheight
$4 = 180
(gdb) c
Continuing.

Thread 1 "emacs" hit Breakpoint 1, xg_frame_set_char_size 
(f=f@entry=0x55555719fae0, width=width@entry=720, 
height=height@entry=390) at gtkutil.c:1004
1004	      gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
(gdb) p totalwidth
$5 = 368
(gdb) p totalheight
$6 = 195
(gdb) c
Continuing.

And the last one during the attempt to resize it.

Thread 1 "emacs" hit Breakpoint 1, xg_frame_set_char_size 
(f=f@entry=0x5555572f1c60, width=width@entry=720, 
height=height@entry=780) at gtkutil.c:1004
1004	      gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
(gdb) p totalwidth
$1 = 368
(gdb) p totalheight
$2 = 390

I repeated the scenario a few times, the values are stable.

The above was when using a custom configuration. With 'emacs -Q', the 
values are just slightly different (384 and 360).



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-15 23:53                           ` Dmitry Gutov
@ 2020-01-16  8:03                             ` martin rudalics
  2020-01-16  8:15                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-16  8:03 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> Can you move around 'test-frame' by mouse-dragging its mode line?
 >
 > I can't make it work at all, neither in the child frame, nor in any normal frame, independent of how the frame parameter was set.

Sorry, it works only for minibuffer-less (or minibuffer-only) child
frames.  The following snippet should work:


(custom-set-faces
  '(internal-border ((t (:background "red")))))

(defun open-test (buffer)
   (display-buffer-in-child-frame
    buffer '((child-frame-parameters
              . ((width . 40)
                 (height . 10)
                 (top . 50)
                 (left . 50)
		(minibuffer . nil)
		(internal-border-width . 10)
		(drag-internal-border . t)
		(drag-with-mode-line . t)
                 )))))

(setq-local test-buffer (get-buffer-create "*test child-frame*"))
(setq-local test-frame (window-frame (open-test test-buffer)))


This should allow to (1) drag the frame around with mouse-1 down on the
mode line and (2) draw a 10 pixel wide red internal border (color
visible only after a redisplay, maybe) I can use here to resize the
frame with mouse-1 (Emacs resizing natively).  Both work quite snappy
here with an optimized build running under Xfce on an old-stable Debian.
Feedback from other (not necessarily company-) users welcome.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-16  0:04                       ` Dmitry Gutov
@ 2020-01-16  8:04                         ` martin rudalics
  2020-01-16  8:25                           ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-16  8:04 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > And the last one during the attempt to resize it.
 >
 > Thread 1 "emacs" hit Breakpoint 1, xg_frame_set_char_size (f=f@entry=0x5555572f1c60, width=width@entry=720, height=height@entry=780) at gtkutil.c:1004
 > 1004          gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 > (gdb) p totalwidth
 > $1 = 368
 > (gdb) p totalheight
 > $2 = 390
 >
 > I repeated the scenario a few times, the values are stable.
 >
 > The above was when using a custom configuration. With 'emacs -Q', the values are just slightly different (384 and 360).

These correspond to what I see here.  One more thing: Could you try
to turn off scaling and look whether anything changes?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-16  8:03                             ` martin rudalics
@ 2020-01-16  8:15                               ` Dmitry Gutov
  2020-01-16  9:18                                 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-16  8:15 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 16.01.2020 11:03, martin rudalics wrote:
> This should allow to (1) drag the frame around with mouse-1 down on the
> mode line and (2) draw a 10 pixel wide red internal border (color
> visible only after a redisplay, maybe) I can use here to resize the
> frame with mouse-1 (Emacs resizing natively).  Both work quite snappy
> here with an optimized build running under Xfce on an old-stable Debian. 

Yup, that's working fine on my GNOME desktop. No obvious slowdown, at least.

> Feedback from other (not necessarily company-) users welcome.

FWIW, posframe is used by various other packages now.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-16  8:04                         ` martin rudalics
@ 2020-01-16  8:25                           ` Dmitry Gutov
  0 siblings, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-16  8:25 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 16.01.2020 11:04, martin rudalics wrote:
> These correspond to what I see here.  One more thing: Could you try
> to turn off scaling and look whether anything changes?

Tried it. Not much changed. Tumashu's scenario still fails.

The values shows by GDB this way are 392 and 360.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-16  8:15                               ` Dmitry Gutov
@ 2020-01-16  9:18                                 ` martin rudalics
  2020-01-16  9:27                                   ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-16  9:18 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> This should allow to (1) drag the frame around with mouse-1 down on the
 >> mode line and (2) draw a 10 pixel wide red internal border (color
 >> visible only after a redisplay, maybe) I can use here to resize the
 >> frame with mouse-1 (Emacs resizing natively).  Both work quite snappy
 >> here with an optimized build running under Xfce on an old-stable Debian.
 >
 > Yup, that's working fine on my GNOME desktop. No obvious slowdown, at least.

I'm confused now.  Does (2) really work in the sense that you can resize
the frame by dragging its internal border?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-16  9:18                                 ` martin rudalics
@ 2020-01-16  9:27                                   ` Dmitry Gutov
  2020-01-16  9:44                                     ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-16  9:27 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 16.01.2020 12:18, martin rudalics wrote:
>  >> This should allow to (1) drag the frame around with mouse-1 down on the
>  >> mode line and (2) draw a 10 pixel wide red internal border (color
>  >> visible only after a redisplay, maybe) I can use here to resize the
>  >> frame with mouse-1 (Emacs resizing natively).  Both work quite snappy
>  >> here with an optimized build running under Xfce on an old-stable 
> Debian.
>  >
>  > Yup, that's working fine on my GNOME desktop. No obvious slowdown, at 
> least.
> 
> I'm confused now.  Does (2) really work in the sense that you can resize
> the frame by dragging its internal border?

Ah! No, sorry.

I can drag it around no problem. As for resizing, it doesn't work. The 
cursor shows the appropriate shapes when near the window borders, but 
dragging it by the border can only move it (i.e. dragging the top or 
left border moves the child frame, but does not resize it).

Dragging it by the border is not as snappy as dragging it by the 
mode-line, BTW.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-16  9:27                                   ` Dmitry Gutov
@ 2020-01-16  9:44                                     ` martin rudalics
  2020-01-16 10:12                                       ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-16  9:44 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> I'm confused now.  Does (2) really work in the sense that you can resize
 >> the frame by dragging its internal border?
 >
 > Ah! No, sorry.
 >
 > I can drag it around no problem. As for resizing, it doesn't work. The cursor shows the appropriate shapes when near the window borders, but dragging it by the border can only move it (i.e. dragging the top or left border moves the child frame, but does not resize it).
 >
 > Dragging it by the border is not as snappy as dragging it by the mode-line, BTW.

Dragging the frame by dragging the border shouldn't have happened in the
first place.  Please try again with:


(custom-set-faces
  '(internal-border ((t (:background "red")))))

(defun open-test (buffer)
   (display-buffer-in-child-frame
    buffer '((child-frame-parameters
              . ((width . 40)
                 (height . 10)
                 (top . 50)
                 (left . 50)
         (minibuffer . nil)
         (border-width . 0)
         (internal-border-width . 10)
         (drag-internal-border . t)
         (drag-with-mode-line . t)
                 )))))

(setq-local test-buffer (get-buffer-create "*test child-frame*"))
(setq-local test-frame (window-frame (open-test test-buffer)))


martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-16  9:44                                     ` martin rudalics
@ 2020-01-16 10:12                                       ` Dmitry Gutov
  2020-01-16 10:22                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-16 10:12 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 16.01.2020 12:44, martin rudalics wrote:
> 
> Dragging the frame by dragging the border shouldn't have happened in the
> first place.  Please try again with:
> 
> 
> (custom-set-faces
>   '(internal-border ((t (:background "red")))))
> 
> (defun open-test (buffer)
>    (display-buffer-in-child-frame
>     buffer '((child-frame-parameters
>               . ((width . 40)
>                  (height . 10)
>                  (top . 50)
>                  (left . 50)
>          (minibuffer . nil)
>          (border-width . 0)
>          (internal-border-width . 10)
>          (drag-internal-border . t)
>          (drag-with-mode-line . t)
>                  )))))
> 
> (setq-local test-buffer (get-buffer-create "*test child-frame*"))
> (setq-local test-frame (window-frame (open-test test-buffer)))

The behavior seems to be the same (dragging, not resizing; including 
dragging by the borders).

BTW, somewhat curiously the red border only shows up after I click on 
the child frame.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-16 10:12                                       ` Dmitry Gutov
@ 2020-01-16 10:22                                         ` martin rudalics
  2020-01-16 15:03                                           ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-16 10:22 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > The behavior seems to be the same (dragging, not resizing; including dragging by the borders).

Earlier your 'frame-geometry' reported that the child frame has no
borders.  So there should be no dragging by the borders, only resizing
via the internal borders.  Hence this behavior sounds strange.

 > BTW, somewhat curiously the red border only shows up after I click on the child frame.

Happens here as well, sometimes.  It appears right away with an
optimized GTK build, though.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-16 10:22                                         ` martin rudalics
@ 2020-01-16 15:03                                           ` Dmitry Gutov
  2020-01-16 18:33                                             ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-16 15:03 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 16.01.2020 13:22, martin rudalics wrote:
>  > The behavior seems to be the same (dragging, not resizing; including 
> dragging by the borders).
> 
> Earlier your 'frame-geometry' reported that the child frame has no
> borders.  So there should be no dragging by the borders, only resizing
> via the internal borders.  Hence this behavior sounds strange.

My intuitive understanding is that the WM considers this frame 
fixed-size for some reason. And when mouse dragging of the top border is 
initiated, it is indeed resized by moving the top border.

And then some other piece of code somewhere sees that and thinks, hey, 
this window must be X height! And fixes the situation by resizing it 
back (but moving the bottom border). Which makes the frame move.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-16 15:03                                           ` Dmitry Gutov
@ 2020-01-16 18:33                                             ` martin rudalics
       [not found]                                               ` <15405719-d58d-44db-f1df-ad3bb272b2fc@yandex.ru>
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-16 18:33 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > My intuitive understanding is that the WM considers this frame
 > fixed-size for some reason. And when mouse dragging of the top border
 > is initiated, it is indeed resized by moving the top border.
 >
 > And then some other piece of code somewhere sees that and thinks, hey,
 > this window must be X height! And fixes the situation by resizing it
 > back (but moving the bottom border). Which makes the frame move.

Tracking that red border is something Emacs internal and is eventually
translated to gtk_window_resize calls just like 'set-frame-size' and
setting the 'height' or 'width' frame parameters.  Hence, all your
earlier attempts to resize the frame would then have resulted in frame
movements as well.

What I'm more concerned about here is that mutter actually _moves_ the
frame although there should not be any decorations that would make such
movement possible and not that dragging the red border does not resize
the frame because I already knew from your earlier observations that
resizing child frames is not supported.

You could try one more thing: Set the frame's 'override-redirect'
parameter to bypass the WM like


(custom-set-faces
  '(internal-border ((t (:background "red")))))

(defun open-test (buffer)
   (display-buffer-in-child-frame
    buffer '((child-frame-parameters
              . ((width . 40)
                 (height . 10)
                 (top . 50)
                 (left . 50)
         (minibuffer . nil)
	(override-redirect . t)
         (border-width . 0)
         (internal-border-width . 10)
         (drag-internal-border . t)
         (drag-with-mode-line . t)
                 )))))

(setq-local test-buffer (get-buffer-create "*test child-frame*"))
(setq-local test-frame (window-frame (open-test test-buffer)))


And also make sure that 'frame-resize-pixelwise' is t although I doubt
that this would make any difference.  I've tried to read the mutter
source code but hardly found anything revealing.  BTW, did you ever try
shrinking the initial frame instead of growing it?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
       [not found]                                                 ` <aba0683f-466c-76cf-9024-e18bfc9fdc94@gmx.at>
@ 2020-01-18  2:05                                                   ` Dmitry Gutov
  2020-01-18  2:29                                                     ` Dmitry Gutov
  2020-01-18  8:32                                                     ` martin rudalics
  0 siblings, 2 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-18  2:05 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 17.01.2020 2:53, martin rudalics wrote:
> Then I'm at my wits' end ..

This is really unfortunate, because the users have been asking, 
repeatedly, for a (popup-based) interface for completion, "M-x", and 
other features. And the overlay-based approach has had known problems 
and limitations for years.

As we can see, posframe is kind of working okay for some users:

https://i.redd.it/cwaq7dsrny941.png

But somewhat ironically, it only mostly works on non-free OSes (GNOME is 
the most popular Free DE still).

(Also see 
https://www.reddit.com/r/emacs/comments/ejzwz7/wilmersdorf_theme_v050_also_featured_in/)

Is there anything more I can do to facilitate fixing this? Helping you 
set up a VM, or renting one in the Cloud, for instance.

So far my research says that we're maybe doing something unusual. 
Because there are few hits mentioning any problems with "child windows 
resize" on Goog, but something similar also comes up in relation to X 
Server implementations for MS Windows:

https://superuser.com/questions/300555/problem-with-resizing-subwindows-in-eclipse-xming-combination

https://github.com/sebastiencs/company-box/issues/76#event-2935078315

The latter is a report on somewhat similar problem our users have with 
childframe-based packages (company-box and company-posframe) when using 
VcXsrv or Xming. In this environment, resizing happens, but with heavy 
graphical artefacts. Fixed by switching to "MobaXTerm", apparently.

Alternatively, if we can't make resizing child frames work reliably, 
maybe prohibit it on the API level? And then work on making sure that 
deleting and re-creating a new child frame, and showing a buffer there, 
is fast enough.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-18  2:05                                                   ` Dmitry Gutov
@ 2020-01-18  2:29                                                     ` Dmitry Gutov
  2020-01-18  8:34                                                       ` martin rudalics
  2020-01-18  8:32                                                     ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-18  2:29 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 18.01.2020 5:05, Dmitry Gutov wrote:
> Alternatively, if we can't make resizing child frames work reliably, 
> maybe prohibit it on the API level? And then work on making sure that 
> deleting and re-creating a new child frame, and showing a buffer there, 
> is fast enough.

BTW, this already gives me a bit better performance than the original 
resize-test (0.7s for 10 iterations vs 1.0s for the same, and a lot of 
that 0.7 is spent in GC):

(defun open-test (buffer width height)
   (display-buffer-in-child-frame
    buffer `((child-frame-parameters
              . ((width . ,width)
                 (height . ,height)
                 (top . 50)
                 (left . 50)
                 )))))

(defun resize-test (frame height)
   (let ((width (frame-width))
         (buf (window-buffer (frame-first-window frame))))
     (delete-frame frame)
     (open-test buf width height)))

(setq-local test-buffer (get-buffer-create "test child-frame"))
(setq-local test-frame (window-frame (open-test test-buffer 40 10)))

(benchmark 10 '(setq-local test-frame (window-frame (resize-test 
test-frame 10))))

But an overlay-based popup is an order of magnitude faster still. And 
that's important because we really can't make the user wait for 70-100ms 
for Emacs to react to input.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-18  2:05                                                   ` Dmitry Gutov
  2020-01-18  2:29                                                     ` Dmitry Gutov
@ 2020-01-18  8:32                                                     ` martin rudalics
  2020-01-20 13:37                                                       ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-18  8:32 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > Is there anything more I can do to facilitate fixing this?

We'd first need a somewhat wider audience here.  Are all the colleagues
running into these problems on GNOME or tunneling into it, do they all
use a HiDPI display?  Could one of them try to change the WM for
experimenting so we can at least determine that this is a mutter-only
problem?  Could we find at least one guru able to build mutter so she or
he can debug it - I don't have the faintest idea how to do that.  Maybe
there's also someone still running Metacity who could tell us whether
the same problems exist there already.

Here with Xfce on Debian I'm using a minibuffer child frame that moves
along with the selected window, resizes exactly like the normal
minibuffer window and disappears whenever it's not active.  So child
frames work reliably here.

OTOH, as we've seen with Bug#38452, mutter also seems to have problems
processing calls for normal Emacs frames as requested.  So we really
should try to contact Florian Müllner (fmuellner@gnome.org) - maybe he
could give us at least some hints on how to proceed or what to test.
But this means that at least two or three people using Emacs on GNOME
shell should participate, so this doesn't look like some sort of stray
issue, occasionally encountered by one or two users as with
https://gitlab.gnome.org/GNOME/mutter/issues/840.

martin




^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-18  2:29                                                     ` Dmitry Gutov
@ 2020-01-18  8:34                                                       ` martin rudalics
  2020-01-18 12:27                                                         ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-18  8:34 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> Alternatively, if we can't make resizing child frames work reliably,
 > maybe prohibit it on the API level? And then work on making sure that
 > deleting and re-creating a new child frame, and showing a buffer
 > there, is fast enough.

Impossible.  See, for example, ...

https://lists.gnu.org/archive/html/help-gnu-emacs/2020-01/msg00053.html

 > BTW, this already gives me a bit better performance than the original
 > resize-test (0.7s for 10 iterations vs 1.0s for the same, and a lot of
 > that 0.7 is spent in GC):

... and my motivation for introducing 'tooltip-reuse-hidden-frame'.  The
apparent necessity to look up all fonts whenever making a new frame will
defy any such delete/re-create strategy.

 > But an overlay-based popup is an order of magnitude faster still. And
 > that's important because we really can't make the user wait for
 > 70-100ms for Emacs to react to input.

Agreed.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-18  8:34                                                       ` martin rudalics
@ 2020-01-18 12:27                                                         ` Dmitry Gutov
  2020-01-18 13:48                                                           ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-18 12:27 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 18.01.2020 11:34, martin rudalics wrote:
> ... and my motivation for introducing 'tooltip-reuse-hidden-frame'.  The
> apparent necessity to look up all fonts whenever making a new frame will
> defy any such delete/re-create strategy.

Speaking of hidden frames.

Changing 'resize-test' in the original scenario to

   (defun resize-test (frame)
     (make-frame-invisible frame)
     (set-frame-height frame 20)
     (make-frame-visible frame))

makes it both work and execute much faster: around 1ms for one iteration.

If it's at all possible, I was also looking for a solution that would 
minimize flickering. Any ideas?



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-18 12:27                                                         ` Dmitry Gutov
@ 2020-01-18 13:48                                                           ` martin rudalics
  2020-01-19  2:45                                                             ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-18 13:48 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > Changing 'resize-test' in the original scenario to
 >
 >    (defun resize-test (frame)
 >      (make-frame-invisible frame)
 >      (set-frame-height frame 20)
 >      (make-frame-visible frame))
 >
 > makes it both work and execute much faster: around 1ms for one iteration.

This at least seems to prove that the resize bug is not on our side.

 > If it's at all possible, I was also looking for a solution that would minimize flickering. Any ideas?

The above doesn't flicker here, or at least I can't notice any flicker
here.  You could try to play around with 'x-wait-for-event-timeout'.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-18 13:48                                                           ` martin rudalics
@ 2020-01-19  2:45                                                             ` Dmitry Gutov
  2020-01-19  8:52                                                               ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-19  2:45 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 18.01.2020 16:48, martin rudalics wrote:
>  > Changing 'resize-test' in the original scenario to
>  >
>  >    (defun resize-test (frame)
>  >      (make-frame-invisible frame)
>  >      (set-frame-height frame 20)
>  >      (make-frame-visible frame))
>  >
>  > makes it both work and execute much faster: around 1ms for one 
> iteration.
> 
> This at least seems to prove that the resize bug is not on our side.

Maybe. But it might also mean that it's possible to provide some hint to 
the window manager that resizing is indeed allowed.

>  > If it's at all possible, I was also looking for a solution that would 
> minimize flickering. Any ideas?
> 
> The above doesn't flicker here, or at least I can't notice any flicker
> here.

Do you have a compositing window manager (on your GNU/Linux system)?

It doesn't flicker always, but like 3 out of 4 times is does. And 
running resize-test in a loop always shows 1-2 flickers, at least.

> You could try to play around with 'x-wait-for-event-timeout'.

You mean to bind it to a larger value around the body of resize-test?

I tried 1, as well as 10. No change.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-19  2:45                                                             ` Dmitry Gutov
@ 2020-01-19  8:52                                                               ` martin rudalics
  2020-01-20 14:14                                                                 ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-19  8:52 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > Maybe. But it might also mean that it's possible to provide some hint
 > to the window manager that resizing is indeed allowed.

Maybe.  But how would we find out?  Did others try your "fix" already?

 > Do you have a compositing window manager (on your GNU/Linux system)?

Xfce comes with compositing capabilities but my graphic card might not
comply.  Setting an 'alpha' parameter for a child frame effectively does
not work (it seemed to work on my Windows machine but that is broken now
so I can't check).  Mostly I don't care because normal Emacs frames
always flicker during resizing anyway.

 > It doesn't flicker always, but like 3 out of 4 times is does. And running resize-test in a loop always shows 1-2 flickers, at least.

So when you now resize a child frame by dragging its corners, it usually
flickers.  It does not flicker at all here.  Probably because its buffer
is empty, possibly because certain compositing effects are ignored or
not implemented.

 >> You could try to play around with 'x-wait-for-event-timeout'.
 >
 > You mean to bind it to a larger value around the body of resize-test?
 >
 > I tried 1, as well as 10. No change.

A floating point value less than 0.1.  Non-floating point values stand
for 0 ("no wait").  It stands for waiting that many seconds for a
configure notify event that would confirm that your frame has really
become visible or invisible.  So IIUC (Noam might correct me) you may
have to wait twice that time with WMs that don't send such events.


BTW: I just found out that with emacs -Q my latest code samples produce
a red border when I do 'eval-buffer' via M-x but don't produce that red
border when I put an

; (eval-buffer)

line into *scratch* and hit C-x C-e with point after the ")".  So much
about the reproducibility of experiments here.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-18  8:32                                                     ` martin rudalics
@ 2020-01-20 13:37                                                       ` Dmitry Gutov
  2020-01-20 15:57                                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-20 13:37 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 18.01.2020 11:32, martin rudalics wrote:
>  > Is there anything more I can do to facilitate fixing this?
> 
> We'd first need a somewhat wider audience here.  Are all the colleagues
> running into these problems on GNOME or tunneling into it, do they all
> use a HiDPI display?

The reports are here:

https://github.com/tumashu/company-posframe/issues/2

Mutter is singled out as a cause, HiDPI or not.

> Could one of them try to change the WM for
> experimenting so we can at least determine that this is a mutter-only
> problem? Maybe
> there's also someone still running Metacity who could tell us whether
> the same problems exist there already.

Andrey Orst said that he tried it with Mate desktop (using a fork of 
Metacity), and didn't see this problem here.

 > Could we find at least one guru able to build mutter so she or
 > he can debug it - I don't have the faintest idea how to do that.

I've posted that question.

> Here with Xfce on Debian I'm using a minibuffer child frame that moves
> along with the selected window, resizes exactly like the normal
> minibuffer window and disappears whenever it's not active.  So child
> frames work reliably here.

Well... guess I'm happy it works at least for some users.

> OTOH, as we've seen with Bug#38452, mutter also seems to have problems
> processing calls for normal Emacs frames as requested.  So we really
> should try to contact Florian Müllner (fmuellner@gnome.org) - maybe he
> could give us at least some hints on how to proceed or what to test.
> But this means that at least two or three people using Emacs on GNOME
> shell should participate, so this doesn't look like some sort of stray
> issue, occasionally encountered by one or two users as with
> https://gitlab.gnome.org/GNOME/mutter/issues/840.

Should we start commenting on that issue?

Maybe you could start with a more comprehensive explanation there. Using 
terms that Mutter developers would understand more easily (meaning, not 
Lisp code).

Florian seems to be subscribed to that issue, BTW.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-19  8:52                                                               ` martin rudalics
@ 2020-01-20 14:14                                                                 ` Dmitry Gutov
  2020-01-20 15:57                                                                   ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-20 14:14 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 19.01.2020 11:52, martin rudalics wrote:
>  > Maybe. But it might also mean that it's possible to provide some hint
>  > to the window manager that resizing is indeed allowed.
> 
> Maybe.  But how would we find out?

By asking Mutter developers, maybe. Or reading Mutter code. Sorry, I'm 
not really qualified to do either.

> Did others try your "fix" already?

I've posted the patch to posframe, let's see what others say. But I'm 
seeing a reliable improvement.

>  > Do you have a compositing window manager (on your GNU/Linux system)?
> 
> Xfce comes with compositing capabilities but my graphic card might not
> comply.  Setting an 'alpha' parameter for a child frame effectively does
> not work (it seemed to work on my Windows machine but that is broken now
> so I can't check).

If sending you a newer graphics card would help the situation, I'm game. :-)

Linux graphics drivers situation has been rather poor historically, so 
I'm not sure which one to choose.

 > Mostly I don't care because normal Emacs frames
 > always flicker during resizing anyway.

Even when resizing doesn't actually change the size?

>  > It doesn't flicker always, but like 3 out of 4 times is does. And 
> running resize-test in a loop always shows 1-2 flickers, at least.
> 
> So when you now resize a child frame by dragging its corners, it usually
> flickers.

I still can't resize it by dragging its corners. The "dragging" code 
doesn't know to make the frame invisible/visible, and I don't know where 
to change that.

> It does not flicker at all here.  Probably because its buffer
> is empty, possibly because certain compositing effects are ignored or
> not implemented.

The buffer contents are the same for me.

>  >> You could try to play around with 'x-wait-for-event-timeout'.
>  >
>  > You mean to bind it to a larger value around the body of resize-test?
>  >
>  > I tried 1, as well as 10. No change.
> 
> A floating point value less than 0.1.  Non-floating point values stand
> for 0 ("no wait").  It stands for waiting that many seconds for a
> configure notify event that would confirm that your frame has really
> become visible or invisible.  So IIUC (Noam might correct me) you may
> have to wait twice that time with WMs that don't send such events.

This is the usage you meant, right?

(defun resize-test (frame height)
   (let ((x-wait-for-event-timeout 0.05))
     (make-frame-invisible frame)
     (set-frame-height frame height)
     (make-frame-visible frame)))

I tried different values: 0.05, 0.001, 0.2, 0.5. The upshot, in this 
round of testing, is that it always flickers at least once. It might 
only flicker the mode-line and the scrollbar. Or it might flicker to 
show the contents of the underlying window. But that seems to happen 
regardless of the value above.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-20 13:37                                                       ` Dmitry Gutov
@ 2020-01-20 15:57                                                         ` martin rudalics
  2020-01-20 23:02                                                           ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-20 15:57 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > https://github.com/tumashu/company-posframe/issues/2
 >
 > Mutter is singled out as a cause, HiDPI or not.

OK.  Has anyone tried with a non-GTK build so we can exclude GTK
dependencies too?  Has anyone tried with NS (here GNUstep doesn't even
build at the moment)?

 > Andrey Orst said that he tried it with Mate desktop (using a fork of Metacity), and didn't see this problem here.

OK.

One more thing to try.  In x_wm_set_size_hint we don't set size hints
for child windows here (around line 1404 of gtkutil.c):

   if (NILP (Vafter_init_time)
       || !FRAME_GTK_OUTER_WIDGET (f)
       || FRAME_PARENT_FRAME (f))
     return;

I forgot why, maybe it broke something or caused some weird behavior.  I
should have had a reason back then and forgot to comment it.

Replace that with

   if (NILP (Vafter_init_time)
       || !FRAME_GTK_OUTER_WIDGET (f))
/**       || FRAME_PARENT_FRAME (f)) **/
     return;

and rebuild (it builds and runs without problems here).  Make sure to
run with 'frame-resize-pixelwise' t.  To the best of my knowledge we do
set size hints for non-GTK builds ...

 >  > Could we find at least one guru able to build mutter so she or
 >  > he can debug it - I don't have the faintest idea how to do that.
 >
 > I've posted that question.

Thanks.  I have no great hope that anyone will answer.

 > Should we start commenting on that issue?

Politely so, yes.  Always keep in mind that our way of using GTK is a
peculiar one and that child frames are a somewhat underdeveloped issue,
mostly used for modal dialogues, centered on their parent, never
changing size and the like.

 > Maybe you could start with a more comprehensive explanation
 > there. Using terms that Mutter developers would understand more easily
 > (meaning, not Lisp code).

Will do as soon as I know answers to the questions above.

 > Florian seems to be subscribed to that issue, BTW.

That's why I mentioned him.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-20 14:14                                                                 ` Dmitry Gutov
@ 2020-01-20 15:57                                                                   ` martin rudalics
  2020-01-20 22:20                                                                     ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-20 15:57 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >  > Mostly I don't care because normal Emacs frames
 >  > always flicker during resizing anyway.
 >
 > Even when resizing doesn't actually change the size?

You mean when making a frame invisible and then visible?  Here it's
always changing the frame size itself that causes flickers, mostly when
redisplaying the scroll bars and mode lines.

 >>  > It doesn't flicker always, but like 3 out of 4 times is does. And running resize-test in a loop always shows 1-2 flickers, at least.
 >>
 >> So when you now resize a child frame by dragging its corners, it usually
 >> flickers.
 >
 > I still can't resize it by dragging its corners. The "dragging" code doesn't know to make the frame invisible/visible, and I don't know where to change that.

It would be no fun anyway.

 > (defun resize-test (frame height)
 >    (let ((x-wait-for-event-timeout 0.05))
 >      (make-frame-invisible frame)
 >      (set-frame-height frame height)
 >      (make-frame-visible frame)))
 >
 > I tried different values: 0.05, 0.001, 0.2, 0.5. The upshot, in this round of testing, is that it always flickers at least once. It might only flicker the mode-line and the scrollbar. Or it might flicker to show the contents of the underlying window. But that seems to happen regardless of the value above.

I see.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-20 15:57                                                                   ` martin rudalics
@ 2020-01-20 22:20                                                                     ` Dmitry Gutov
  2020-01-21  8:29                                                                       ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-20 22:20 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 20.01.2020 18:57, martin rudalics wrote:
>  >  > Mostly I don't care because normal Emacs frames
>  >  > always flicker during resizing anyway.
>  >
>  > Even when resizing doesn't actually change the size?
> 
> You mean when making a frame invisible and then visible?  Here it's
> always changing the frame size itself that causes flickers, mostly when
> redisplaying the scroll bars and mode lines.

I was asking about the best-case scenario here. Like, is there hope for 
persistent popups that don't flicker after every input.

Scrollbars and mode lines aren't a problem because they're not needed in 
a popup. But visibility cycling still created flickering, even without 
them, in the Lucid build.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-20 15:57                                                         ` martin rudalics
@ 2020-01-20 23:02                                                           ` Dmitry Gutov
  2020-01-21  8:29                                                             ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-20 23:02 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 20.01.2020 18:57, martin rudalics wrote:
>  > https://github.com/tumashu/company-posframe/issues/2
>  >
>  > Mutter is singled out as a cause, HiDPI or not.
> 
> OK.  Has anyone tried with a non-GTK build so we can exclude GTK
> dependencies too?  Has anyone tried with NS (here GNUstep doesn't even
> build at the moment)?

GNUstep what? I'm hesitant to install the dependencies, whatever they are.

Still, a good question. I did a Lucid toolkit build and, lo and behold, 
the bug went away. Also it's blazing fast:

(benchmark 200 '(resize-test test-frame))
=> 0.007s

> One more thing to try.  In x_wm_set_size_hint we don't set size hints
> for child windows here (around line 1404 of gtkutil.c):
> 
>    if (NILP (Vafter_init_time)
>        || !FRAME_GTK_OUTER_WIDGET (f)
>        || FRAME_PARENT_FRAME (f))
>      return;
> 
> I forgot why, maybe it broke something or caused some weird behavior.  I
> should have had a reason back then and forgot to comment it.
> 
> Replace that with
> 
>    if (NILP (Vafter_init_time)
>        || !FRAME_GTK_OUTER_WIDGET (f))
> /**       || FRAME_PARENT_FRAME (f)) **/
>      return;
> 
> and rebuild (it builds and runs without problems here).  Make sure to
> run with 'frame-resize-pixelwise' t.  To the best of my knowledge we do
> set size hints for non-GTK builds ...

That didn't help, however. With either value of frame-resize-pixelwise.

Did 'make bootstrap', to make doubly sure.

>  > Should we start commenting on that issue?
> 
> Politely so, yes.  Always keep in mind that our way of using GTK is a
> peculiar one and that child frames are a somewhat underdeveloped issue,
> mostly used for modal dialogues, centered on their parent, never
> changing size and the like.

Sure.

It appears that they work okay in other desktop environments, though. It 
might also turn out to be a GTK problem.

FTR, my GTK version is 3.24.8.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-20 22:20                                                                     ` Dmitry Gutov
@ 2020-01-21  8:29                                                                       ` martin rudalics
  2020-01-21 11:36                                                                         ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-21  8:29 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > I was asking about the best-case scenario here. Like, is there hope for persistent popups that don't flicker after every input.

If we are able to identify the cause for the flicker first.  I suppose
with "input" you mean "resizing" and not plain updating of its text.

 > Scrollbars and mode lines aren't a problem because they're not needed
 > in a popup. But visibility cycling still created flickering, even
 > without them, in the Lucid build.


You mean the Lucid build is not any better in this regard than a GTK
build making the frame invisible, resizing it and making it visible
again?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-20 23:02                                                           ` Dmitry Gutov
@ 2020-01-21  8:29                                                             ` martin rudalics
  2020-01-21 12:11                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-21  8:29 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > GNUstep what? I'm hesitant to install the dependencies, whatever they are.

Forget it.  It can be useful for checking dependencies when implementing
new features.  One cannot do practical work with it IME.  What I meant
was rather whether anyone see problms like yours on NS-based machines.

 > Still, a good question. I did a Lucid toolkit build and, lo and behold, the bug went away. Also it's blazing fast:
 >
 > (benchmark 200 '(resize-test test-frame))
 > => 0.007s

So is it usable?  In your other mail you seemed to indicate that it's
still flickering.  And can you resize child frames by dragging their
borders with it?

If it _is_ usable, the problem is not with mutter but with GTK (maybe in
connection with mutter) or our interpretation of GTK.  To make very sure
you could also try a Motif build (it had very few dependencies when I
installed it, IIRC).

In either case this is the most important finding we had so far.  I
should have asked you earlier.

 > That didn't help, however. With either value of frame-resize-pixelwise.
 >
 > Did 'make bootstrap', to make doubly sure.

I have to go through our GTK code once more.  Maybe I find a similar
discrepancy.  For example, does anything change when you set
'x-gtk-use-window-move' to nil?

 > It appears that they work okay in other desktop environments, though. It might also turn out to be a GTK problem.
 >
 > FTR, my GTK version is 3.24.8.

Mine is 3.22.11 and I'm always reluctant to upgrade my environment.  For
every problem upgrading fixes, I usually get three new ones.  Does your
GTK still have the

(emacs:2053): Gtk-CRITICAL **: gtk_distribute_natural_allocation: assertion 'extra_space >= 0' failed

problem?  I see it here when starting emacs -Q from a terminal and use
the mouse to shrink the Emacs GUI frame to something less than the tool
bar width.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-21  8:29                                                                       ` martin rudalics
@ 2020-01-21 11:36                                                                         ` Dmitry Gutov
  2020-01-21 16:11                                                                           ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-21 11:36 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 21.01.2020 11:29, martin rudalics wrote:
>  > I was asking about the best-case scenario here. Like, is there hope 
> for persistent popups that don't flicker after every input.
> 
> If we are able to identify the cause for the flicker first.  I suppose
> with "input" you mean "resizing" and not plain updating of its text.

No, I meant more practical usage of posframe as a library, where we 
show/update tooltip after every character typed by the user.

>  > Scrollbars and mode lines aren't a problem because they're not needed
>  > in a popup. But visibility cycling still created flickering, even
>  > without them, in the Lucid build.
> 
> 
> You mean the Lucid build is not any better in this regard than a GTK
> build making the frame invisible, resizing it and making it visible
> again?

*If* I cycle visibility, yes. Even if "resizing" doesn't change the 
size. But cycling visibility is not necessary with Lucid to make 
resizing work.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-21  8:29                                                             ` martin rudalics
@ 2020-01-21 12:11                                                               ` Dmitry Gutov
  2020-01-21 16:12                                                                 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-21 12:11 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 21.01.2020 11:29, martin rudalics wrote:
>  > GNUstep what? I'm hesitant to install the dependencies, whatever they 
> are.
> 
> Forget it.  It can be useful for checking dependencies when implementing
> new features.  One cannot do practical work with it IME.  What I meant
> was rather whether anyone see problms like yours on NS-based machines.

Like a Mac? Apparently not. But they do complain about flickering:

https://github.com/sebastiencs/company-box/issues/79#issuecomment-576507598

>  > Still, a good question. I did a Lucid toolkit build and, lo and 
> behold, the bug went away. Also it's blazing fast:
>  >
>  > (benchmark 200 '(resize-test test-frame))
>  > => 0.007s
> 
> So is it usable?  In your other mail you seemed to indicate that it's
> still flickering.

It's usable, yes. Without visibility cycling, there's little flickering, 
and it doesn't happen in the simple scenario we're discussing now.

 > And can you resize child frames by dragging their
 > borders with it?

Yes, that works both with Lucid and Motif. BTW, dragging bottom and 
right borders is fast and smooth, but dragging top-left is very choppy.

> If it _is_ usable, the problem is not with mutter but with GTK (maybe in
> connection with mutter) or our interpretation of GTK.  To make very sure
> you could also try a Motif build (it had very few dependencies when I
> installed it, IIRC).

Apparently so. Again, Motif works about as well as Lucid.

Unfortunately, I'm getting reports that the Lucid build is much slower 
than GTK at least for some others: 
https://github.com/tumashu/company-posframe/issues/2#issuecomment-576582371

> In either case this is the most important finding we had so far.  I
> should have asked you earlier.

I should have tried it myself as well.

>  > That didn't help, however. With either value of frame-resize-pixelwise.
>  >
>  > Did 'make bootstrap', to make doubly sure.
> 
> I have to go through our GTK code once more.  Maybe I find a similar
> discrepancy.  For example, does anything change when you set
> 'x-gtk-use-window-move' to nil?

No change.

>  > It appears that they work okay in other desktop environments, though. 
> It might also turn out to be a GTK problem.
>  >
>  > FTR, my GTK version is 3.24.8.
> 
> Mine is 3.22.11 and I'm always reluctant to upgrade my environment.  For
> every problem upgrading fixes, I usually get three new ones.

If only we didn't have to support newer versions for other users. :-)

> Does your
> GTK still have the
> 
> (emacs:2053): Gtk-CRITICAL **: gtk_distribute_natural_allocation: 
> assertion 'extra_space >= 0' failed
> 
> problem?  I see it here when starting emacs -Q from a terminal and use
> the mouse to shrink the Emacs GUI frame to something less than the tool
> bar width.

Yup. I see it.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-21 11:36                                                                         ` Dmitry Gutov
@ 2020-01-21 16:11                                                                           ` martin rudalics
  2020-01-21 21:33                                                                             ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-21 16:11 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > No, I meant more practical usage of posframe as a library, where we
 > show/update tooltip after every character typed by the user.

Without a timer-based delay?

 >> You mean the Lucid build is not any better in this regard than a GTK
 >> build making the frame invisible, resizing it and making it visible
 >> again?
 >
 > *If* I cycle visibility, yes. Even if "resizing" doesn't change the size. But cycling visibility is not necessary with Lucid to make resizing work.

OK.  So I conclude that the Lucid build is currently fully functional
for you without having to cycle visibility.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-21 12:11                                                               ` Dmitry Gutov
@ 2020-01-21 16:12                                                                 ` martin rudalics
  2020-01-21 22:26                                                                   ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-21 16:12 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > Yes, that works both with Lucid and Motif. BTW, dragging bottom and right borders is fast and smooth, but dragging top-left is very choppy.

Because the frame has to resize _and_ move.  GTK has an internal
function that moves and resizes a window in one go but I haven't seen an
external interface to it.

 > Unfortunately, I'm getting reports that the Lucid build is much slower
 > than GTK at least for some others:

I can't comment on that.  I only have non-optimized Lucid builds here
and they are much too slow to do anything with child frames at all.

Next thing to try: Before the

   gtk_window_get_size (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
		       &gwidth, &gheight);

lines in xg_frame_set_char_size insert the two lines

   if (!gtk_window_get_resizable (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))))
     gtk_window_set_resizable (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), TRUE);

put a breakpoint on the second one and tell me whether you get a hit.
Just to make sure ...

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-21 16:11                                                                           ` martin rudalics
@ 2020-01-21 21:33                                                                             ` Dmitry Gutov
  2020-01-22  9:07                                                                               ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-21 21:33 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 21.01.2020 19:11, martin rudalics wrote:
> 
> Without a timer-based delay?

Usually without (but sometimes with). If a completion popup blinks in 
and out of existence with a 100ms timeout, it's bound to cause 
irritation (if not more, for those affected by certain neurological 
disorders).

> OK.  So I conclude that the Lucid build is 
> currently fully functional
> for you without having to cycle visibility.

Indeed.

As you can see from the discussion I linked several times now, I 
recommended using it as the workaround. Unfortunately, it's much slower 
for some other users. But it's really working very fast for me. I don't 
understand this.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-21 16:12                                                                 ` martin rudalics
@ 2020-01-21 22:26                                                                   ` Dmitry Gutov
  2020-01-22  9:08                                                                     ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-21 22:26 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 21.01.2020 19:12, martin rudalics wrote:
>  > Yes, that works both with Lucid and Motif. BTW, dragging bottom and 
> right borders is fast and smooth, but dragging top-left is very choppy.
> 
> Because the frame has to resize _and_ move.  GTK has an internal
> function that moves and resizes a window in one go but I haven't seen an
> external interface to it.

But I can drag it smoothly (by the mode-line), and I can resize it 
smoothly. It kind of weird that drag+resize is more than 2x as slow.

Anyway, that's not the current issue.

>  > Unfortunately, I'm getting reports that the Lucid build is much slower
>  > than GTK at least for some others:
> 
> I can't comment on that.  I only have non-optimized Lucid builds here
> and they are much too slow to do anything with child frames at all.

Does building with '-Og' help? It's really fast here, faster than GTK by 
an order of magnitude (or two).

> Next thing to try: Before the
> 
>    gtk_window_get_size (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
>                 &gwidth, &gheight);
> 
> lines in xg_frame_set_char_size insert the two lines
> 
>    if (!gtk_window_get_resizable (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))))
>      gtk_window_set_resizable (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), 
> TRUE);
> 
> put a breakpoint on the second one and tell me whether you get a hit.
> Just to make sure ...

Still no luck (hits line 960, but not 961).



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-21 21:33                                                                             ` Dmitry Gutov
@ 2020-01-22  9:07                                                                               ` martin rudalics
  2020-01-22 10:57                                                                                 ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-22  9:07 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > Usually without (but sometimes with). If a completion popup blinks in
 > and out of existence with a 100ms timeout, it's bound to cause
 > irritation (if not more, for those affected by certain neurological
 > disorders).

But a non-blinking-in-and-out popup is supposed to move and resize along
with the cursor which is the source of our problems here.  Right?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-21 22:26                                                                   ` Dmitry Gutov
@ 2020-01-22  9:08                                                                     ` martin rudalics
  2020-01-22 11:35                                                                       ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-22  9:08 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1557 bytes --]

 >> Because the frame has to resize _and_ move.  GTK has an internal
 >> function that moves and resizes a window in one go but I haven't seen an
 >> external interface to it.
 >
 > But I can drag it smoothly (by the mode-line), and I can resize it smoothly. It kind of weird that drag+resize is more than 2x as slow.

It's not only weird.  IIUC it's also wrong sometimes.  I guess parts of
Emacs' readjust-positions code get into the way here.

 > Does building with '-Og' help? It's really fast here, faster than GTK by an order of magnitude (or two).

I haven't tried it.  What I need is an executable I can debug reliably.

 >> Next thing to try: Before the
 >>
 >>    gtk_window_get_size (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 >>                 &gwidth, &gheight);
 >>
 >> lines in xg_frame_set_char_size insert the two lines
 >>
 >>    if (!gtk_window_get_resizable (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f))))
 >>      gtk_window_set_resizable (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), TRUE);
 >>
 >> put a breakpoint on the second one and tell me whether you get a hit.
 >> Just to make sure ...
 >
 > Still no luck (hits line 960, but not 961).

So at least no-one interferes with this.

Next thing to try is to always run XResizeWindow and XMoveWindow for GTK
child windows.  This should avoid any GTK related checks for them.  The
attached patch has three hunks.  Try them all first and maybe try to
only apply the last one (or the last two) afterwards.  Here it breaks my
"moving the left or top border of GTK child frames" behavior.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: xterm.diff --]
[-- Type: text/x-patch; name="xterm.diff", Size: 1767 bytes --]

diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..02055f133f 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10604,9 +10604,13 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_
     }

 #ifdef USE_GTK
-  /* Make sure we adjust for possible scaling.  */
-  gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-		   modified_left / scale, modified_top / scale);
+  if (FRAME_PARENT_FRAME (f))
+    XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+		 modified_left, modified_top);
+  else
+    /* Make sure we adjust for possible scaling.  */
+    gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+		     modified_left / scale, modified_top / scale);
 #else
   XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 	       modified_left, modified_top);
@@ -11355,9 +11359,14 @@ x_set_window_size_1 (struct frame *f, bool change_gravity,
   int old_height = FRAME_PIXEL_HEIGHT (f);
   Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);

-  if (change_gravity)
-    f->win_gravity = NorthWestGravity;
-  x_wm_set_size_hint (f, 0, false);
+
+  if (!FRAME_PARENT_FRAME (f))
+    {
+      if (change_gravity)
+	f->win_gravity = NorthWestGravity;
+
+      x_wm_set_size_hint (f, 0, false);
+    }

   /* When the frame is fullheight and we only want to change the width
      or it is fullwidth and we only want to change the height we should
@@ -11489,7 +11498,7 @@ x_set_window_size (struct frame *f, bool change_gravity,
     }

 #ifdef USE_GTK
-  if (FRAME_GTK_WIDGET (f))
+  if (FRAME_GTK_WIDGET (f) && !FRAME_PARENT_FRAME (f))
     xg_frame_set_char_size (f, width, height);
   else
     x_set_window_size_1 (f, change_gravity, width, height);

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re:Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22  9:09 ` martin rudalics
@ 2020-01-22 10:01   ` tumashu
  2020-01-22 10:03   ` tumashu
  1 sibling, 0 replies; 196+ messages in thread
From: tumashu @ 2020-01-22 10:01 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel@gnu.org, Dmitry Gutov

















At 2020-01-22 17:09:11, "martin rudalics" <rudalics@gmx.at> wrote:
> > Today I test lucid emacs again,  maybe the slowness is  posn-at-point
> >
> > (benchmark 1000 '(posn-at-point (point)))
> >
> > "Elapsed time: 0.684959s"
> >
> > for posframe call posn-at-point
>
>And what do you get for a GTK build?  Here I get
>
>in an O3 GTK build  Elapsed time: 0.590930s (0.175256s in 3 GCs)
>
>in an O0 GTK build  Elapsed time: 2.644455s (0.764866s in 4 GCs)
>
>in an O0 Lucid build  Elapsed time: 2.785499s (0.776188s in 4 GCs)
>
>martin

just ./configure

"Elapsed time: 0.209364s (0.025391s in 1 GCs)"


^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re:Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22  9:09 ` martin rudalics
  2020-01-22 10:01   ` tumashu
@ 2020-01-22 10:03   ` tumashu
  2020-01-22 17:33     ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: tumashu @ 2020-01-22 10:03 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel@gnu.org, Dmitry Gutov

















At 2020-01-22 17:09:11, "martin rudalics" <rudalics@gmx.at> wrote:
> > Today I test lucid emacs again,  maybe the slowness is  posn-at-point
> >
> > (benchmark 1000 '(posn-at-point (point)))
> >
> > "Elapsed time: 0.684959s"
> >
> > for posframe call posn-at-point
>
>And what do you get for a GTK build?  Here I get
>
>in an O3 GTK build  Elapsed time: 0.590930s (0.175256s in 3 GCs)
>
>in an O0 GTK build  Elapsed time: 2.644455s (0.764866s in 4 GCs)
>
>in an O0 Lucid build  Elapsed time: 2.785499s (0.776188s in 4 GCs)
>
>martin


Mark set
Elapsed time: 0.235007s (0.050980s in 2 GCs)
"Elapsed time: 0.235007s (0.050980s in 2 GCs)"
Elapsed time: 0.209364s (0.025391s in 1 GCs)
"Elapsed time: 0.209364s (0.025391s in 1 GCs)"
Mark activated
Elapsed time: 0.250710s (0.052309s in 2 GCs)
"Elapsed time: 0.250710s (0.052309s in 2 GCs)"
Elapsed time: 0.241979s (0.051069s in 2 GCs)
"Elapsed time: 0.241979s (0.051069s in 2 GCs)"
Mark set 

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22  9:07                                                                               ` martin rudalics
@ 2020-01-22 10:57                                                                                 ` Dmitry Gutov
  0 siblings, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-22 10:57 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 22.01.2020 12:07, martin rudalics wrote:
> But a non-blinking-in-and-out popup is supposed to move and resize along
> with the cursor which is the source of our problems here.  Right?

At least it won't move due to mouse dragging. It'll be positioned 
according to calculations based on posn-at-point, usually (but not 
always). And it won't move after *every* input, only after some of them.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22  9:08                                                                     ` martin rudalics
@ 2020-01-22 11:35                                                                       ` Dmitry Gutov
  2020-01-22 13:18                                                                         ` tumashu
  2020-01-22 17:35                                                                         ` martin rudalics
  0 siblings, 2 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-22 11:35 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 22.01.2020 12:08, martin rudalics wrote:

>  > Does building with '-Og' help? It's really fast here, faster than GTK 
> by an order of magnitude (or two).
> 
> I haven't tried it.  What I need is an executable I can debug reliably.

All I'm saying, the users are not really helpful so far, so you might be 
the best person to try debugging the perf problems with Lucid. I'd try, 
but I don't have any.

> Next thing to try is to always run XResizeWindow and XMoveWindow for GTK
> child windows.  This should avoid any GTK related checks for them.  The
> attached patch has three hunks.  Try them all first and maybe try to
> only apply the last one (or the last two) afterwards.  Here it breaks my
> "moving the left or top border of GTK child frames" behavior.

Aaand none of this helped either. Not all 3 hunks together, nor 
combinations (2, 3), (3) or (1).



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re:Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 11:35                                                                       ` Dmitry Gutov
@ 2020-01-22 13:18                                                                         ` tumashu
  2020-01-22 13:32                                                                           ` Dmitry Gutov
  2020-01-22 17:35                                                                         ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: tumashu @ 2020-01-22 13:18 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: martin rudalics, emacs-devel@gnu.org

















At 2020-01-22 19:35:40, "Dmitry Gutov" <dgutov@yandex.ru> wrote:
>On 22.01.2020 12:08, martin rudalics wrote:
>
>>  > Does building with '-Og' help? It's really fast here, faster than GTK 
>> by an order of magnitude (or two).
>> 
>> I haven't tried it.  What I need is an executable I can debug reliably.
>
>All I'm saying, the users are not really helpful so far, so you might be 
>the best person to try debugging the perf problems with Lucid. I'd try, 
>but I don't have any.
>

I think it is set-frame-position's reason,   posframe have positon cache, so if posframe's position no
change, it will fast, if position changed, it will show half second lags

(require 'posframe)

(posframe-show "test" :string "aaaaaaaa"
               :background-color "red")

```
(setq child-frame
      (with-current-buffer "test"
        posframe--frame))

(setq p nil)

(defun test ()
  (setq p (if (equal p '(10 10))
              '(100 100)
            '(10 10)))
  (set-frame-position child-frame (car p) (cadr p)))

(benchmark 5 '(test))
```

"Elapsed time: 1.063156s"




>> Next thing to try is to always run XResizeWindow and XMoveWindow for GTK
>> child windows.  This should avoid any GTK related checks for them.  The
>> attached patch has three hunks.  Try them all first and maybe try to
>> only apply the last one (or the last two) afterwards.  Here it breaks my
>> "moving the left or top border of GTK child frames" behavior.
>
>Aaand none of this helped either. Not all 3 hunks together, nor 
>combinations (2, 3), (3) or (1).

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 13:18                                                                         ` tumashu
@ 2020-01-22 13:32                                                                           ` Dmitry Gutov
  2020-01-22 16:19                                                                             ` Eli Zaretskii
  2020-01-22 17:36                                                                             ` martin rudalics
  0 siblings, 2 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-22 13:32 UTC (permalink / raw)
  To: tumashu; +Cc: martin rudalics, emacs-devel@gnu.org

On 22.01.2020 16:18, tumashu wrote:
> I think it is set-frame-position's reason,   posframe have positon cache, so if posframe's position no
> change, it will fast, if position changed, it will show half second lags
> 
> (require 'posframe)
> 
> (posframe-show "test" :string "aaaaaaaa"
>                 :background-color "red")
> 
> ```
> (setq child-frame
>        (with-current-buffer "test"
>          posframe--frame))
> 
> (setq p nil)
> 
> (defun test ()
>    (setq p (if (equal p '(10 10))
>                '(100 100)
>              '(10 10)))
>    (set-frame-position child-frame (car p) (cadr p)))
> 
> (benchmark 5 '(test))
> ```
> 
> "Elapsed time: 1.063156s"

Thanks, I can confirm this. Only it's even longer in my case (2.63s).

Dragging with mode-line is similarly sluggish. Guess I didn't test that 
properly before.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 13:32                                                                           ` Dmitry Gutov
@ 2020-01-22 16:19                                                                             ` Eli Zaretskii
  2020-01-22 17:36                                                                             ` martin rudalics
  1 sibling, 0 replies; 196+ messages in thread
From: Eli Zaretskii @ 2020-01-22 16:19 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: tumashu, emacs-devel, rudalics

> From: Dmitry Gutov <dgutov@yandex.ru>
> Date: Wed, 22 Jan 2020 16:32:02 +0300
> Cc: martin rudalics <rudalics@gmx.at>,
>  "emacs-devel@gnu.org" <emacs-devel@gnu.org>
> 
> > (defun test ()
> >    (setq p (if (equal p '(10 10))
> >                '(100 100)
> >              '(10 10)))
> >    (set-frame-position child-frame (car p) (cadr p)))
> > 
> > (benchmark 5 '(test))
> > ```
> > 
> > "Elapsed time: 1.063156s"
> 
> Thanks, I can confirm this. Only it's even longer in my case (2.63s).

This sounds like some waiting loop somewhere.  Don't we wait for X in
some situations after asking the WM to make some change?



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 11:35                                                                       ` Dmitry Gutov
  2020-01-22 13:18                                                                         ` tumashu
@ 2020-01-22 17:35                                                                         ` martin rudalics
  2020-01-22 22:40                                                                           ` tumashu
  2020-01-23  0:21                                                                           ` Dmitry Gutov
  1 sibling, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-22 17:35 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > All I'm saying, the users are not really helpful so far, so you might
 > be the best person to try debugging the perf problems with Lucid. I'd
 > try, but I don't have any.

That was a misunderstanding.  All my debug builds here are too slow for
normal editing.  I keep them all for testing purposes only.  Optimized
builds have certain performance problems but these are not related to
the use of child frames.

 > Aaand none of this helped either. Not all 3 hunks together, nor
 > combinations (2, 3), (3) or (1).

(1) was a NOOP anyway.  I have to think of something better - the
height specifications for GTK and other X builds are not compatible and
break the behavior even on my build.  I should come up with something
better.

Till then please do the following.  With emacs -Q put this modified
version of tumashu's code into *scratch*


(defun open-test (buffer)
   (display-buffer-in-child-frame
    buffer '((child-frame-parameters
              . ((width . 40)
                 (height . 10)
                 (top . 50)
                 (left . 50)
                 )))))

(defun resize-test (frame)
   (set-frame-height frame 20))

(setq-local test-buffer (get-buffer-create "test child-frame"))
(setq-local test-frame (window-frame (open-test test-buffer)))

;; (eval-buffer)
;; (setq frame-size-history '(100))
;; (resize-test test-frame)
;; (frame--size-history test-frame)
;; (display-buffer "*frame-size-history*")


and evaluate from top to bottom each of the commented out forms.  At the
end this gets me a buffer like

Frame size history of #<frame test child-frame 0x5636a0abf9a0>
adjust-frame-size-1	 (360 180 360 360) (height 1)
adjust-frame-size-2	 (360 180 360 360) (nil nil)
xg-frame-set-char-size-3 (360 180 360 360) (390 360)
xg-frame-resized	 (360 180 360 360) nil
adjust-frame-size-1	 (360 180 360 360) (change-frame-size 5)
adjust-frame-size-3	 (360 180 360 360) (390 180 390 360)

Please do this for the GTK and Lucid build.  And, replace the body of
'resize-test' with your invisible, resize, visible trick and post the
history for that case as well.

Thanks, martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 13:32                                                                           ` Dmitry Gutov
  2020-01-22 16:19                                                                             ` Eli Zaretskii
@ 2020-01-22 17:36                                                                             ` martin rudalics
  2020-01-22 21:15                                                                               ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-22 17:36 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > Dragging with mode-line is similarly sluggish. Guess I didn't test that properly before.

What did you drag with the mode-line?  A Lucid child frame?  And it's
slower than dragging a gtk child frame?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 17:36                                                                             ` martin rudalics
@ 2020-01-22 21:15                                                                               ` Dmitry Gutov
  2020-01-25  8:41                                                                                 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-22 21:15 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 22.01.2020 20:36, martin rudalics wrote:
> What did you drag with the mode-line?  A Lucid child frame?  And it's
> slower than dragging a gtk child frame?

Yes, exactly. Much slower. Resizing is faster, but moving is slower.

(I wanted to do the same experiment with a "top-level" frame as well, 
but couldn't find out how.)



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re:Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 17:33     ` martin rudalics
@ 2020-01-22 22:30       ` tumashu
  0 siblings, 0 replies; 196+ messages in thread
From: tumashu @ 2020-01-22 22:30 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel@gnu.org, Dmitry Gutov


















At 2020-01-23 01:33:25, "martin rudalics" <rudalics@gmx.at> wrote:
> > Mark set
> > Elapsed time: 0.235007s (0.050980s in 2 GCs)
> > "Elapsed time: 0.235007s (0.050980s in 2 GCs)"
> > Elapsed time: 0.209364s (0.025391s in 1 GCs)
> > "Elapsed time: 0.209364s (0.025391s in 1 GCs)"
> > Mark activated
> > Elapsed time: 0.250710s (0.052309s in 2 GCs)
> > "Elapsed time: 0.250710s (0.052309s in 2 GCs)"
> > Elapsed time: 0.241979s (0.051069s in 2 GCs)
> > "Elapsed time: 0.241979s (0.051069s in 2 GCs)"
> > Mark set
>
>Sorry, what are these numbers?  Do they represent GTK builds with the
>same options as the Lucid build that takes 0.684959s?  Did you test all
>with emacs -Q in the same buffer and at the same position?
>

Sorry, finally I find it is set-frame-position's reason, it too slow,  not posn-at-point

When I test, I replace posn-at-point to a fix value, and  posframe has cached this value,
not call set-frame-positon, so speed is fast,






>martin

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re:Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 17:35                                                                         ` martin rudalics
@ 2020-01-22 22:40                                                                           ` tumashu
  2020-01-25  8:41                                                                             ` martin rudalics
  2020-01-23  0:21                                                                           ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: tumashu @ 2020-01-22 22:40 UTC (permalink / raw)
  To: martin rudalics; +Cc: emacs-devel@gnu.org, Dmitry Gutov

----------------------------------------------------------------
# in xfce4, gtk emacs
----------------------------------------------------------------
Frame size history of #<frame test child-frame 0x555960081020>
adjust-frame-size-1      (440 240 440 480) (height 1)
adjust-frame-size-2      (440 240 440 480) (nil nil)
xg-frame-set-char-size-3 (440 240 440 480) (456 480)
xg-frame-resized         (440 240 440 480) nil
adjust-frame-size-1      (440 240 440 480) (change-frame-size 5)
adjust-frame-size-3      (440 240 440 480) (456 240 456 480)
adjust-frame-size-1      (440 480 440 480) (height 1)

-----------------------------------------------------------------
# in gnome shell, gtk emacs
------------------------------------------------------------------
Frame size history of #<frame test child-frame 0x56253dbbf000>
adjust-frame-size-1      (440 240 440 480) (height 1)
adjust-frame-size-2      (440 240 440 480) (nil nil)
xg-frame-set-char-size-3 (440 240 440 480) (456 480)
















At 2020-01-23 01:35:50, "martin rudalics" <rudalics@gmx.at> wrote:
> > All I'm saying, the users are not really helpful so far, so you might
> > be the best person to try debugging the perf problems with Lucid. I'd
> > try, but I don't have any.
>
>That was a misunderstanding.  All my debug builds here are too slow for
>normal editing.  I keep them all for testing purposes only.  Optimized
>builds have certain performance problems but these are not related to
>the use of child frames.
>
> > Aaand none of this helped either. Not all 3 hunks together, nor
> > combinations (2, 3), (3) or (1).
>
>(1) was a NOOP anyway.  I have to think of something better - the
>height specifications for GTK and other X builds are not compatible and
>break the behavior even on my build.  I should come up with something
>better.
>
>Till then please do the following.  With emacs -Q put this modified
>version of tumashu's code into *scratch*
>
>
>(defun open-test (buffer)
>   (display-buffer-in-child-frame
>    buffer '((child-frame-parameters
>              . ((width . 40)
>                 (height . 10)
>                 (top . 50)
>                 (left . 50)
>                 )))))
>
>(defun resize-test (frame)
>   (set-frame-height frame 20))
>
>(setq-local test-buffer (get-buffer-create "test child-frame"))
>(setq-local test-frame (window-frame (open-test test-buffer)))
>
>;; (eval-buffer)
>;; (setq frame-size-history '(100))
>;; (resize-test test-frame)
>;; (frame--size-history test-frame)
>;; (display-buffer "*frame-size-history*")
>
>
>and evaluate from top to bottom each of the commented out forms.  At the
>end this gets me a buffer like
>
>Frame size history of #<frame test child-frame 0x5636a0abf9a0>
>adjust-frame-size-1	 (360 180 360 360) (height 1)
>adjust-frame-size-2	 (360 180 360 360) (nil nil)
>xg-frame-set-char-size-3 (360 180 360 360) (390 360)
>xg-frame-resized	 (360 180 360 360) nil
>adjust-frame-size-1	 (360 180 360 360) (change-frame-size 5)
>adjust-frame-size-3	 (360 180 360 360) (390 180 390 360)
>
>Please do this for the GTK and Lucid build.  And, replace the body of
>'resize-test' with your invisible, resize, visible trick and post the
>history for that case as well.
>
>Thanks, martin

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 17:35                                                                         ` martin rudalics
  2020-01-22 22:40                                                                           ` tumashu
@ 2020-01-23  0:21                                                                           ` Dmitry Gutov
  2020-01-23  0:39                                                                             ` tumashu
  2020-01-25  8:42                                                                             ` martin rudalics
  1 sibling, 2 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-23  0:21 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 22.01.2020 20:35, martin rudalics wrote:

> Till then please do the following.  With emacs -Q put this modified
> version of tumashu's code into *scratch*
> 
> <...>
> Please do this for the GTK and Lucid build.  And, replace the body of
> 'resize-test' with your invisible, resize, visible trick and post the
> history for that case as well.

Here you go.

GNOME Shell, Lucid Emacs:

Frame size history of #<frame test child-frame 0x55c2abb444a0>
adjust-frame-size-1	 (720 360 720 720) (height 1)
adjust-frame-size-2	 (720 360 720 720) (nil nil)
x-set-window-size-3	 (720 360 720 720) (754 722 0)
x-net-wm-state		 nil (nil nil)
EmacsFrameResize	 (720 360 720 720) (754 722 0 0 2)
EmacsFrameResize	 (720 360 720 720) (754 722 0 0 2)
adjust-frame-size-1	 (720 360 720 720) (change-frame-size 5)
adjust-frame-size-3	 (720 360 720 720) (754 362 754 722)
EmacsFrameResize	 (720 720 720 720) (754 722 0 0 2)
EmacsFrameResize	 (720 720 720 720) (754 722 0 0 2)
adjust-frame-size-1	 (720 720 720 720) (change-frame-size 5)

GNOME Shell, GTK Emacs:

Frame size history of #<frame test child-frame 0x5580c2116ea0>
adjust-frame-size-1	 (720 360 720 720) (height 1)
adjust-frame-size-2	 (720 360 720 720) (nil nil)
xg-frame-set-char-size-3 (720 360 720 720) (384 360)

GNOME Shell, GTK Emacs with modified resize-test:

Frame size history of #<frame test child-frame 0x5649dd2e5640>
adjust-frame-size-1	 (720 360 720 720) (height 1)
adjust-frame-size-2	 (720 360 720 720) (nil nil)
xg-frame-set-char-size-3 (720 360 720 720) (384 360)
adjust-frame-size-1	 (720 360 720 720) (xg-frame-set-char-size 5)
adjust-frame-size-3	 (720 360 720 720) (768 360 768 720)
xg-frame-resized	 (720 720 720 720) nil



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re:Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-23  0:21                                                                           ` Dmitry Gutov
@ 2020-01-23  0:39                                                                             ` tumashu
  2020-01-25  8:42                                                                             ` martin rudalics
  1 sibling, 0 replies; 196+ messages in thread
From: tumashu @ 2020-01-23  0:39 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: martin rudalics, emacs-devel@gnu.org

















At 2020-01-23 08:21:13, "Dmitry Gutov" <dgutov@yandex.ru> wrote:
>On 22.01.2020 20:35, martin rudalics wrote:
>
>> Till then please do the following.  With emacs -Q put this modified
>> version of tumashu's code into *scratch*
>> 
>> <...>
>> Please do this for the GTK and Lucid build.  And, replace the body of
>> 'resize-test' with your invisible, resize, visible trick and post the
>> history for that case as well.
>
>Here you go.
>
>GNOME Shell, Lucid Emacs:
>
>Frame size history of #<frame test child-frame 0x55c2abb444a0>
>adjust-frame-size-1	 (720 360 720 720) (height 1)
>adjust-frame-size-2	 (720 360 720 720) (nil nil)
>x-set-window-size-3	 (720 360 720 720) (754 722 0)
>x-net-wm-state		 nil (nil nil)
>EmacsFrameResize	 (720 360 720 720) (754 722 0 0 2)
>EmacsFrameResize	 (720 360 720 720) (754 722 0 0 2)
>adjust-frame-size-1	 (720 360 720 720) (change-frame-size 5)
>adjust-frame-size-3	 (720 360 720 720) (754 362 754 722)
>EmacsFrameResize	 (720 720 720 720) (754 722 0 0 2)
>EmacsFrameResize	 (720 720 720 720) (754 722 0 0 2)
>adjust-frame-size-1	 (720 720 720 720) (change-frame-size 5)

I have tested with lucid emacs , the result is below

Frame size history of #<frame test child-frame 0x5566cb63e550>
adjust-frame-size-1	 (320 230 320 460) (height 1)
adjust-frame-size-2	 (320 230 320 460) (nil nil)
x-set-window-size-3	 (320 230 320 460) (354 462 0)
x-net-wm-state		 nil (nil nil)
EmacsFrameResize	 (320 230 320 460) (354 462 0 0 2)
EmacsFrameResize	 (320 230 320 460) (354 462 0 0 2)
adjust-frame-size-1	 (320 230 320 460) (change-frame-size 5)
adjust-frame-size-3	 (320 230 320 460) (354 232 354 462)
EmacsFrameResize	 (320 460 320 460) (354 462 0 0 2)
EmacsFrameResize	 (320 460 320 460) (354 462 0 0 2)
adjust-frame-size-1	 (320 460 320 460) (change-frame-size 5)




>
>GNOME Shell, GTK Emacs:
>
>Frame size history of #<frame test child-frame 0x5580c2116ea0>
>adjust-frame-size-1	 (720 360 720 720) (height 1)
>adjust-frame-size-2	 (720 360 720 720) (nil nil)
>xg-frame-set-char-size-3 (720 360 720 720) (384 360)
>
>GNOME Shell, GTK Emacs with modified resize-test:
>
>Frame size history of #<frame test child-frame 0x5649dd2e5640>
>adjust-frame-size-1	 (720 360 720 720) (height 1)
>adjust-frame-size-2	 (720 360 720 720) (nil nil)
>xg-frame-set-char-size-3 (720 360 720 720) (384 360)
>adjust-frame-size-1	 (720 360 720 720) (xg-frame-set-char-size 5)
>adjust-frame-size-3	 (720 360 720 720) (768 360 768 720)
>xg-frame-resized	 (720 720 720 720) nil

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 21:15                                                                               ` Dmitry Gutov
@ 2020-01-25  8:41                                                                                 ` martin rudalics
  2020-01-25 10:09                                                                                   ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-25  8:41 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> What did you drag with the mode-line?  A Lucid child frame?  And it's
 >> slower than dragging a gtk child frame?
 >
 > Yes, exactly. Much slower. Resizing is faster, but moving is slower.

I meanwhile can reproduce it here (with my first optimzed Lucid build).
So far no luck in fixing this.

 > (I wanted to do the same experiment with a "top-level" frame as well, but couldn't find out how.)

Use

(setq default-frame-alist
       '((minibuffer . nil) (undecorated . t) (drag-with-mode-line . t)
	(border-width . 0) (internal-border-width . 8) (drag-internal-border . t)
	(menu-bar-lines . 0) (tool-bar-lines . 0)))

because the frame to drag must not have a minibuffer window.  And please
try with gtk and lucid.

Here I can move a top-level Lucid frame and drag its left and top
borders without any problems which seems to prove that the moving
problem is child frame specific.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-22 22:40                                                                           ` tumashu
@ 2020-01-25  8:41                                                                             ` martin rudalics
  2020-01-25 10:17                                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-25  8:41 UTC (permalink / raw)
  To: tumashu; +Cc: Dmitry Gutov, emacs-devel@gnu.org

 > ----------------------------------------------------------------
 > # in xfce4, gtk emacs
 > ----------------------------------------------------------------
 > Frame size history of #<frame test child-frame 0x555960081020>
 > adjust-frame-size-1      (440 240 440 480) (height 1)
 > adjust-frame-size-2      (440 240 440 480) (nil nil)
 > xg-frame-set-char-size-3 (440 240 440 480) (456 480)
 > xg-frame-resized         (440 240 440 480) nil
 > adjust-frame-size-1      (440 240 440 480) (change-frame-size 5)
 > adjust-frame-size-3      (440 240 440 480) (456 240 456 480)
 > adjust-frame-size-1      (440 480 440 480) (height 1)
 >
 > -----------------------------------------------------------------
 > # in gnome shell, gtk emacs
 > ------------------------------------------------------------------
 > Frame size history of #<frame test child-frame 0x56253dbbf000>
 > adjust-frame-size-1      (440 240 440 480) (height 1)
 > adjust-frame-size-2      (440 240 440 480) (nil nil)
 > xg-frame-set-char-size-3 (440 240 440 480) (456 480)

OK.  So we apparently do not get the 'xg-frame-resized' event for
mutter.  One final check that it's not lost by Emacs itself:

(1) Run this experiment under gdb putting a breakpoint in
     'set-frame-height' for example at the line

   adjust_frame_size (f, -1, pixel_height, 1, !NILP (pretend), Qheight);

(2) When you hit the breakpoint from (1) put another one on the line

       configureEvent = *event;

     in xterm.c and continue via "c".

(3) Tell me if the breakpoint from (2) is hit.

Thanks, martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-23  0:21                                                                           ` Dmitry Gutov
  2020-01-23  0:39                                                                             ` tumashu
@ 2020-01-25  8:42                                                                             ` martin rudalics
  1 sibling, 0 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-25  8:42 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > GNOME Shell, Lucid Emacs:
 >
 > Frame size history of #<frame test child-frame 0x55c2abb444a0>
 > adjust-frame-size-1     (720 360 720 720) (height 1)
 > adjust-frame-size-2     (720 360 720 720) (nil nil)
 > x-set-window-size-3     (720 360 720 720) (754 722 0)
 > x-net-wm-state         nil (nil nil)
 > EmacsFrameResize     (720 360 720 720) (754 722 0 0 2)
 > EmacsFrameResize     (720 360 720 720) (754 722 0 0 2)
 > adjust-frame-size-1     (720 360 720 720) (change-frame-size 5)
 > adjust-frame-size-3     (720 360 720 720) (754 362 754 722)
 > EmacsFrameResize     (720 720 720 720) (754 722 0 0 2)
 > EmacsFrameResize     (720 720 720 720) (754 722 0 0 2)
 > adjust-frame-size-1     (720 720 720 720) (change-frame-size 5)

Thanks.  I have to look into why we end up getting the EmacsFrameResize
requests twice in a row (and am meanwhile stupefied by a comment like

   /* Some ConfigureNotify events does not end up in EmacsFrameResize so
      make sure we get them all.  Seen with xfcwm4 for example.  */

in widget.c).  This will probably take some time.

Otherwise, your numbers seem to confirm tumashu's results, with scaling
(wherever that comes from).

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-25  8:41                                                                                 ` martin rudalics
@ 2020-01-25 10:09                                                                                   ` Dmitry Gutov
  2020-01-25 12:10                                                                                     ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-25 10:09 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 25.01.2020 11:41, martin rudalics wrote:
> 
> (setq default-frame-alist
>        '((minibuffer . nil) (undecorated . t) (drag-with-mode-line . t)
>      (border-width . 0) (internal-border-width . 8) 
> (drag-internal-border . t)
>      (menu-bar-lines . 0) (tool-bar-lines . 0)))

Lucid:

The first experiment: moving the frame by mode-line is smooth.

After that: I tried resizing the dragging the border. Apparently, it 
doesn't account for window scaling, so it resizes to wrong size, and the 
window generally shrinked. After that, moving became choppy as well. 
Including after I deleted the resized frame and created new one(s).

In the meantime, resizing the first, "normal" frame works okay. Moving 
too (by the title bar).

GTK:

Actually, similar story with resizing.

Moving seems smooth enough before and after, with gradual drift toward 
top-left (because of the other bug we've mentioned before, probably).



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-25  8:41                                                                             ` martin rudalics
@ 2020-01-25 10:17                                                                               ` Dmitry Gutov
  2020-01-25 10:29                                                                                 ` Eli Zaretskii
  2020-01-25 12:11                                                                                 ` martin rudalics
  0 siblings, 2 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-25 10:17 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 25.01.2020 11:41, martin rudalics wrote:
> (2) When you hit the breakpoint from (1) put another one on the line
> 
>        configureEvent = *event;
> 
>      in xterm.c and continue via "c".

Umm, it's not hit by resize-test (or any other step in the scenario).

But here's something weird:

(gdb) b frame.c:3572
Breakpoint 1 at 0x5555555ab4a0: file frame.c, line 3592.

I'm setting the breakpoint at line 3572, but it gets set on 3592. Is 
that normal?

Here's the full output:

Breakpoint 1 at 0x43814: file emacs.c, line 370.
Breakpoint 2 at 0xf94f0: file xterm.c, line 10134.
(gdb) b frame.c:3572
Breakpoint 3 at 0x574a0: file frame.c, line 3592.
(gdb) run -Q
Starting program: /home/dgutov/vc/emacs/src/emacs -Q
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffefcc5700 (LWP 5319)]
[New Thread 0x7fffef450700 (LWP 5320)]
[New Thread 0x7fffee842700 (LWP 5321)]
warning: Corrupted shared library list: 0x55555635c010 != 0x555556075e70
warning: Corrupted shared library list: 0x55555635c010 != 0x555556075e70
[New Thread 0x7fffed816700 (LWP 5324)]
[Thread 0x7fffee842700 (LWP 5321) exited]
[Thread 0x7fffef450700 (LWP 5320) exited]
[Thread 0x7fffefcc5700 (LWP 5319) exited]
[Thread 0x7ffff14c4e00 (LWP 5315) exited]
[Inferior 1 (process 5315) exited normally]



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-25 10:17                                                                               ` Dmitry Gutov
@ 2020-01-25 10:29                                                                                 ` Eli Zaretskii
  2020-01-25 10:52                                                                                   ` Dmitry Gutov
  2020-01-25 12:11                                                                                 ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Eli Zaretskii @ 2020-01-25 10:29 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: rudalics, emacs-devel, tumashu

> From: Dmitry Gutov <dgutov@yandex.ru>
> Date: Sat, 25 Jan 2020 13:17:54 +0300
> Cc: "emacs-devel@gnu.org" <emacs-devel@gnu.org>
> 
> (gdb) b frame.c:3572
> Breakpoint 1 at 0x5555555ab4a0: file frame.c, line 3592.
> 
> I'm setting the breakpoint at line 3572, but it gets set on 3592. Is 
> that normal?

Could be that your binary doesn't match the sources?

Or maybe your build is optimized?



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-25 10:29                                                                                 ` Eli Zaretskii
@ 2020-01-25 10:52                                                                                   ` Dmitry Gutov
  0 siblings, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-25 10:52 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics@gmx.at, emacs-devel@gnu.org, tumashu@163.com

[-- Attachment #1: Type: text/html, Size: 1073 bytes --]

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-25 10:09                                                                                   ` Dmitry Gutov
@ 2020-01-25 12:10                                                                                     ` martin rudalics
  2020-01-26 11:59                                                                                       ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-25 12:10 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > The first experiment: moving the frame by mode-line is smooth.

And it's slow with child frames so we have a major difference here.
Correct?

 > After that: I tried resizing the dragging the border.

Which border(s)?

 > Apparently, it
 > doesn't account for window scaling, so it resizes to wrong size, and
 > the window generally shrinked. After that, moving became choppy as
 > well. Including after I deleted the resized frame and created new
 > one(s).

This sounds interesting.  Does scaling work at all with the Lucid build?

 > In the meantime, resizing the first, "normal" frame works okay. Moving
 > too (by the title bar).

How comes the first frame has a title bar with this specification

(setq default-frame-alist
       '((minibuffer . nil) (undecorated . t) (drag-with-mode-line . t)
	(border-width . 0) (internal-border-width . 8) (drag-internal-border . t)
	(menu-bar-lines . 0) (tool-bar-lines . 0)))

 > GTK:
 >
 > Actually, similar story with resizing.

You mean similar to the Lucid resizing behavior?

 > Moving seems smooth enough before and after, with gradual drift toward
 > top-left (because of the other bug we've mentioned before, probably).

Bug#38452, I presume.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-25 10:17                                                                               ` Dmitry Gutov
  2020-01-25 10:29                                                                                 ` Eli Zaretskii
@ 2020-01-25 12:11                                                                                 ` martin rudalics
  2020-01-25 23:01                                                                                   ` Dmitry Gutov
  2020-01-26 11:03                                                                                   ` Dmitry Gutov
  1 sibling, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-25 12:11 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> (2) When you hit the breakpoint from (1) put another one on the line
 >>
 >>        configureEvent = *event;
 >>
 >>      in xterm.c and continue via "c".
 >
 > Umm, it's not hit by resize-test (or any other step in the scenario).

Is it hit when you _move_ the child frame?  The breakpoint for (1) would
then be around line 3663 of frame.c

   if (FRAME_WINDOW_P (f))

of Fset_frame_position.

 > But here's something weird:
 >
 > (gdb) b frame.c:3572
 > Breakpoint 1 at 0x5555555ab4a0: file frame.c, line 3592.
 >
 > I'm setting the breakpoint at line 3572, but it gets set on 3592. Is that normal?
 >
 > Here's the full output:
 >
 > Breakpoint 1 at 0x43814: file emacs.c, line 370.
 > Breakpoint 2 at 0xf94f0: file xterm.c, line 10134.
 > (gdb) b frame.c:3572
 > Breakpoint 3 at 0x574a0: file frame.c, line 3592.

Is the indicator in the fringe at line 3592?  The gdb logic can reset
breakpoints in code that has been #ifdef'd away but I see no such
justification here.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-25 12:11                                                                                 ` martin rudalics
@ 2020-01-25 23:01                                                                                   ` Dmitry Gutov
  2020-01-26  8:43                                                                                     ` martin rudalics
  2020-01-26 11:03                                                                                   ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-25 23:01 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 25.01.2020 15:11, martin rudalics wrote:
> Is the indicator in the fringe at line 3592?  The gdb logic can reset
> breakpoints in code that has been #ifdef'd away but I see no such
> justification here.

Eli seems to have had the right idea. I rebuilt with

   ./configure --with-x-toolkit=gtk3 CFLAGS='-Og -g3'

and:

1. When trying to resize the child frame, adjust_frame_size (...) *is* 
hit. "configureEvent = ..." is not hit.

2. When moving the child frame by dragging the mode-line (or any other 
way), the second breakpoint is hit.

The first one (if (FRAME_WINDOW_P (f)) ...), -- isn't hit when dragging 
the mode-line. It *is* hit if I call set-frame-position explicitly from 
Lisp.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-25 23:01                                                                                   ` Dmitry Gutov
@ 2020-01-26  8:43                                                                                     ` martin rudalics
  2020-01-26 11:02                                                                                       ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-26  8:43 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 623 bytes --]

 > 1. When trying to resize the child frame, adjust_frame_size (...) *is*
 > hit. "configureEvent = ..." is not hit.

OK.  Someone else swallows our resize request and I have no idea who and
why.  Can you try these steps once more with xterm.diff applied?  I'll
attach it again.

 > 2. When moving the child frame by dragging the mode-line (or any other
 > way), the second breakpoint is hit.

OK.

 > The first one (if (FRAME_WINDOW_P (f)) ...), -- isn't hit when
 >  dragging the mode-line. It *is* hit if I call set-frame-position
 >  explicitly from Lisp.

The former uses frame parameters so this is expected.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: xterm.diff --]
[-- Type: text/x-patch; name="xterm.diff", Size: 1767 bytes --]

diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..02055f133f 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10604,9 +10604,13 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_
     }

 #ifdef USE_GTK
-  /* Make sure we adjust for possible scaling.  */
-  gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-		   modified_left / scale, modified_top / scale);
+  if (FRAME_PARENT_FRAME (f))
+    XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+		 modified_left, modified_top);
+  else
+    /* Make sure we adjust for possible scaling.  */
+    gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+		     modified_left / scale, modified_top / scale);
 #else
   XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 	       modified_left, modified_top);
@@ -11355,9 +11359,14 @@ x_set_window_size_1 (struct frame *f, bool change_gravity,
   int old_height = FRAME_PIXEL_HEIGHT (f);
   Lisp_Object fullscreen = get_frame_param (f, Qfullscreen);

-  if (change_gravity)
-    f->win_gravity = NorthWestGravity;
-  x_wm_set_size_hint (f, 0, false);
+
+  if (!FRAME_PARENT_FRAME (f))
+    {
+      if (change_gravity)
+	f->win_gravity = NorthWestGravity;
+
+      x_wm_set_size_hint (f, 0, false);
+    }

   /* When the frame is fullheight and we only want to change the width
      or it is fullwidth and we only want to change the height we should
@@ -11489,7 +11498,7 @@ x_set_window_size (struct frame *f, bool change_gravity,
     }

 #ifdef USE_GTK
-  if (FRAME_GTK_WIDGET (f))
+  if (FRAME_GTK_WIDGET (f) && !FRAME_PARENT_FRAME (f))
     xg_frame_set_char_size (f, width, height);
   else
     x_set_window_size_1 (f, change_gravity, width, height);

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-26  8:43                                                                                     ` martin rudalics
@ 2020-01-26 11:02                                                                                       ` Dmitry Gutov
  2020-01-26 15:32                                                                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-26 11:02 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 26.01.2020 11:43, martin rudalics wrote:
> OK.  Someone else swallows our resize request and I have no idea who and
> why.  Can you try these steps once more with xterm.diff applied?  I'll
> attach it again.

Okay. With xterm.diff applied it works like this:

Breakpoint 1 is hit. I add breakpoint 2. Hit continue -> B 2 is hit.

Call resize-test again (target height is the same): B1 is hit, B2 is not.

Change resize-test to call set-frame-height with a different HEIGHT 
(e.g. 30). Call resize-test: B1 and B2 are both hit.

Call resize-test again (however many times): only B1 is hit.

IOW, something somewhere remembers the last value we've set HEIGHT to, 
and doesn't send any more configureEvent's for the same value.

The actual visible height of the child frame still doesn't change, 
meanwhile.

(gdb) b frame.c:3572
Breakpoint 3 at 0x4e8d2: file frame.c, line 3572.
(gdb) run -Q
Starting program: /home/dgutov/vc/emacs/src/emacs -Q
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7fffefcc5700 (LWP 23475)]
[New Thread 0x7fffef450700 (LWP 23476)]
[New Thread 0x7fffee842700 (LWP 23477)]
warning: Corrupted shared library list: 0x5555563e2fd0 != 0x5555560c3f00
[New Thread 0x7fffed816700 (LWP 23481)]
warning: Corrupted shared library list: 0x55555626b400 != 0x5555563e2fd0

Thread 1 "emacs" hit Breakpoint 3, Fset_frame_height (frame=<optimized 
out>,
     height=make_fixnum(20), pretend=XIL(0), pixelwise=XIL(0)) at 
frame.c:3572
3572	  adjust_frame_size (f, -1, pixel_height, 1, !NILP (pretend), Qheight);
(gdb) b xterm.c:8904
Breakpoint 4 at 0x55555565c97c: file xterm.c, line 8904.
(gdb) c
Continuing.

Thread 1 "emacs" hit Breakpoint 4, handle_one_xevent 
(dpyinfo=0x555555fda800,
     event=0x7fffffffcad0, finish=0x555555b9df30 <current_finish>, 
hold_quit=0x7fffffffcd50)
     at xterm.c:8904
8904	      configureEvent = *event;
(gdb) p event
$1 = (const XEvent *) 0x7fffffffcad0
(gdb) c
Continuing.

Thread 1 "emacs" hit Breakpoint 3, Fset_frame_height (frame=<optimized 
out>,
     height=make_fixnum(20), pretend=XIL(0), pixelwise=XIL(0)) at 
frame.c:3572
3572	  adjust_frame_size (f, -1, pixel_height, 1, !NILP (pretend), Qheight);
(gdb) c
Continuing.

Thread 1 "emacs" hit Breakpoint 3, Fset_frame_height (frame=<optimized 
out>,
     height=make_fixnum(30), pretend=XIL(0), pixelwise=XIL(0)) at 
frame.c:3572
3572	  adjust_frame_size (f, -1, pixel_height, 1, !NILP (pretend), Qheight);
(gdb) c
Continuing.

Thread 1 "emacs" hit Breakpoint 4, handle_one_xevent 
(dpyinfo=0x555555fda800,
     event=0x7fffffffcad0, finish=0x555555b9df30 <current_finish>, 
hold_quit=0x7fffffffcd50)
     at xterm.c:8904
8904	      configureEvent = *event;
(gdb) c
Continuing.

Thread 1 "emacs" hit Breakpoint 3, Fset_frame_height (frame=<optimized 
out>,
     height=make_fixnum(30), pretend=XIL(0), pixelwise=XIL(0)) at 
frame.c:3572
3572	  adjust_frame_size (f, -1, pixel_height, 1, !NILP (pretend), Qheight);
(gdb) c
Continuing.

Thread 1 "emacs" hit Breakpoint 3, Fset_frame_height (frame=<optimized 
out>,
     height=make_fixnum(30), pretend=XIL(0), pixelwise=XIL(0)) at 
frame.c:3572
3572	  adjust_frame_size (f, -1, pixel_height, 1, !NILP (pretend), Qheight);
(gdb) c
Continuing.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-25 12:11                                                                                 ` martin rudalics
  2020-01-25 23:01                                                                                   ` Dmitry Gutov
@ 2020-01-26 11:03                                                                                   ` Dmitry Gutov
  1 sibling, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-26 11:03 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 25.01.2020 15:11, martin rudalics wrote:
> Is the indicator in the fringe at line 3592?  The gdb logic can reset
> breakpoints in code that has been #ifdef'd away but I see no such
> justification here.

BTW, I'm just using GDB in the terminal.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-25 12:10                                                                                     ` martin rudalics
@ 2020-01-26 11:59                                                                                       ` Dmitry Gutov
  2020-01-26 17:38                                                                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-26 11:59 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 25.01.2020 15:10, martin rudalics wrote:
>  > The first experiment: moving the frame by mode-line is smooth.
> 
> And it's slow with child frames so we have a major difference here.
> Correct?

It's a very murky story.

I rebuilt with toolkit=lucid, tried the experiment

   => dragging by mode-line was choppy

Changed the scaling factor of the desktop to 100% (everything became 
tiny on my monitor), restarted Emacs.

   => dragging by mode-line was smooth

BUT dragging the borders to resize had the same problem I reported 
previously, so it's likely not HiDPI related.

Then I changed scaling back to 200%, restarted Emacs.

   => dragging by mode-line was still smooth (normal frame).

Then tried the child-frame example.

   => dragging was choppy. But it resizes smoothly enough when dragged 
by the bottom or right edges. And, more importantly, resizes correctly. 
When dragged by top-left, it resizes choppily, but still correctly.

In the same session, I applied your default-frame-alist change and 
created a second "normal" frame. Dragging it by mode-line was choppy 
again. And resizing it was broken in the same sense I described before 
(and will again clarify below).

So, in the same session, a child frame and a normal frame have a 
different resizing behavior. A normal frame can move smoothly 
*sometimes*, a child frame always moves choppily.

>  > After that: I tried resizing the dragging the border.
> 
> Which border(s)?

Any of them. But:

When I drag top-left, the bottom-right corner seems to exhibit a more 
gradual drift top-left. When I drag bottom-right, I moves top-left a lot 
more quickly (even if I drag it in the bottom-right direction).

Please note: in most of my experiments I dragged by the corner (top-left 
or bottom-right), and moved in circular-ish, random trajectories. This 
triggers the bug most prominently. But if I just grab one border and 
move the mouse in a straight line, that makes the border move in the 
desired direction, albeit not exactly following the mouse cursor (hence 
the effect, probably).

E.g. if I drag the right border right, it moves after the mouse, but 
more slowly than the mouse. If I move it left, it moves *faster* than 
the mouse. Same with the bottom border. Top and left seem to have a 
similar effect, but less pronounced. Also dragging the top border seems 
to have an effect on the position of the bottom edge (it moves up). In 
all cases, resizing is not smooth.

>  > Apparently, it
>  > doesn't account for window scaling, so it resizes to wrong size, and
>  > the window generally shrinked. After that, moving became choppy as
>  > well. Including after I deleted the resized frame and created new
>  > one(s).
> 
> This sounds interesting.  Does scaling work at all with the Lucid build?

Seems so. Aside from the toolbar icons which are not scaled. The context 
menu appears where it should.

Also, the GTK3 build seems to have the same problem, and it has had 
quite a few HiDPI patches applied recently.

So maybe scaling is not the actual issue (or the jumps would be sharper, 
this just occurred to me).

>  > In the meantime, resizing the first, "normal" frame works okay. Moving
>  > too (by the title bar).
> 
> How comes the first frame has a title bar with this specification

Err, it never occurred to me to put this form in the init script.

I launch Emacs, then evaluate this in scratch in the first frame, and 
then press 'C-x 5 2' and experiment with the second frame.

> (setq default-frame-alist
>        '((minibuffer . nil) (undecorated . t) (drag-with-mode-line . t)
>      (border-width . 0) (internal-border-width . 8) 
> (drag-internal-border . t)
>      (menu-bar-lines . 0) (tool-bar-lines . 0)))
> 
>  > GTK:
>  >
>  > Actually, similar story with resizing.
> 
> You mean similar to the Lucid resizing behavior?

Yes (!!). Very similar (maybe exactly the same even).

The differences are: child frames do not resize. And dragging them by 
mode-line looks the same as dragging normal ones: move smoothly enough, 
with some drift.

>  > Moving seems smooth enough before and after, with gradual drift toward
>  > top-left (because of the other bug we've mentioned before, probably).
> 
> Bug#38452, I presume.

Yes.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-26 11:02                                                                                       ` Dmitry Gutov
@ 2020-01-26 15:32                                                                                         ` martin rudalics
  2020-01-26 21:35                                                                                           ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-26 15:32 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 2714 bytes --]

 > Okay. With xterm.diff applied it works like this:
 >
 > Breakpoint 1 is hit. I add breakpoint 2. Hit continue -> B 2 is hit.

This is at least interesting so we could continue work from here.  IIUC
B 2 is hit but no resizing occurs.  Is that correct?

 > Call resize-test again (target height is the same): B1 is hit, B2 is not.

OK per se, just that our frame does not have that height and we don't
know.

 > Change resize-test to call set-frame-height with a different HEIGHT (e.g. 30). Call resize-test: B1 and B2 are both hit.
 >
 > Call resize-test again (however many times): only B1 is hit.

OK, both.  Just that the frame still doesn't have that height.  Right?

 > IOW, something somewhere remembers the last value we've set HEIGHT to, and doesn't send any more configureEvent's for the same value.

That something should be Emacs itself.  At the time adjust_frame_size is
called in say 'set-frame-height' it's not yet clear whether Emacs will
issue a resize request.  The resize request is issued in this block

       if (FRAME_TERMINAL (f)->set_window_size_hook)
         FRAME_TERMINAL (f)->set_window_size_hook
	  (f, 0, new_text_width, new_text_height, 1);
       f->resized_p = true;

of adjust_frame_size so if you set B 1 there you will see whether Emacs
has decided that the request is necessary so it gets dispatched to the
various toolkit backends (or frontends depending on the way you look at
them).  Please try.

 > The actual visible height of the child frame still doesn't change, meanwhile.

One thing that can be useful for further debugging: Put a background on
the child frame like this (which also disables some additional things).

(defun open-test (buffer)
   (display-buffer-in-child-frame
    buffer '((child-frame-parameters
              . ((width . 10)
                 (height . 10)
                 (top . 50)
                 (left . 50)
		(undecorated . t)
;; 		(override-redirect . t)
		(inhibit-double-buffering . t)
		(background-color . "yellow")
		(minibuffer . nil)
		(tool-bar-lines . 0)
		(menu-bar-lines . 0)
		(vertical-scroll-bars . nil)
		(horizontal-scroll-bars . nil)
		(left-fringe . 0)
		(right-fringe . 0)
		(border-width . 0)
		(internal-border-width . 2)
		(drag-internal-border . t)
		(drag-with-mode-line . t)
                 )))))

The background color here is useful to discern window system operations
that apparently do clear parts of the screen in reaction to our requests
but do not send us the related ConfigureNotify message nor the messages
to re-expose the obscured parts of the parent frame.

And finally try the attached patch for GTK builds to resize frames
directly via gdk calls.  I doubt it changes anything but who knows.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gtkutil.diff --]
[-- Type: text/x-patch; name="gtkutil.diff", Size: 1633 bytes --]

diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..7a1dd15ade 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -953,6 +953,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
   int totalheight
     = pixelheight + FRAME_TOOLBAR_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
   int totalwidth = pixelwidth + FRAME_TOOLBAR_WIDTH (f);
+  GdkWindow *window = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));

   if (FRAME_PIXEL_HEIGHT (f) == 0)
     return;
@@ -983,8 +984,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
 	(f, Qxg_frame_set_char_size_1, width, height,
 	 list2i (gheight, totalheight));

-      gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-			 gwidth, totalheight);
+      gdk_window_resize (window, gwidth, totalheight);
     }
   else if (EQ (fullscreen, Qfullheight) && height == FRAME_TEXT_HEIGHT (f))
     {
@@ -992,8 +992,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
 	(f, Qxg_frame_set_char_size_2, width, height,
 	 list2i (gwidth, totalwidth));

-      gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-			 totalwidth, gheight);
+      gdk_window_resize (window, totalwidth, gheight);
     }
   else
     {
@@ -1001,8 +1000,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
 	(f, Qxg_frame_set_char_size_3, width, height,
 	 list2i (totalwidth, totalheight));

-      gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-			 totalwidth, totalheight);
+      gdk_window_resize (window, totalwidth, totalheight);
       fullscreen = Qnil;
     }


^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-26 11:59                                                                                       ` Dmitry Gutov
@ 2020-01-26 17:38                                                                                         ` martin rudalics
  2020-01-26 20:50                                                                                           ` Dmitry Gutov
                                                                                                             ` (2 more replies)
  0 siblings, 3 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-26 17:38 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >>  > The first experiment: moving the frame by mode-line is smooth.
 >>
 >> And it's slow with child frames so we have a major difference here.
 >> Correct?
 >
 > It's a very murky story.
 >
 > I rebuilt with toolkit=lucid, tried the experiment
 >
 >    => dragging by mode-line was choppy
 >
 > Changed the scaling factor of the desktop to 100% (everything became tiny on my monitor), restarted Emacs.
 >
 >    => dragging by mode-line was smooth

Don't you have some old laptop somwehere where you could try the
experiments without scaling (I'd never believe that changing scaling
on-the-fly works always in a reproducible fashion).

And, it does _not_ work smoothly here.  I can drag the frame smoothly by
a short distance, then it suddenly jumps, then it drags smoothly again
and so on ...

 > BUT dragging the borders to resize had the same problem I reported previously, so it's likely not HiDPI related.

Dragging the right and bottom borders too?  Here dragging any border is
usually smooth with very occasional jumps.  But it's much better than
moving.

I can only conclude that someone, somewhere simply drops an entire
sequence of move requests.

 > Then I changed scaling back to 200%, restarted Emacs.
 >
 >    => dragging by mode-line was still smooth (normal frame).

That's what I meant with never to change scaling with a running desktop.
Hot-plugging a scale factor is troublesome like changing the resolution
of the display IMHO.

 > Then tried the child-frame example.
 >
 >    => dragging was choppy. But it resizes smoothly enough when dragged
 > by the bottom or right edges. And, more importantly, resizes
 > correctly. When dragged by top-left, it resizes choppily, but still
 > correctly.
 >
 > In the same session, I applied your default-frame-alist change and
 > created a second "normal" frame. Dragging it by mode-line was choppy
 > again.

This again hints at something not really reproducible when changing the
scale factor.

 > And resizing it was broken in the same sense I described before
 > (and will again clarify below).

 > So, in the same session, a child frame and a normal frame have a
 > different resizing behavior. A normal frame can move smoothly
 > *sometimes*, a child frame always moves choppily.

To a certain degree I see the same here.  Just that resizing a normal
frame is always smooth here.

 > When I drag top-left, the bottom-right corner seems to exhibit a more
 > gradual drift top-left. When I drag bottom-right, I moves top-left a
 > lot more quickly (even if I drag it in the bottom-right direction).

This might be related to the fact that we move and resize in two
distinct steps.  I wrote a function to do both in one step but its
behavior is just broken with pure X-builds and I'm not able to find out
what goes wrong (it doesn't work with normal frames either).

But it obviously might be a by-product of Bug#38452.

 > Please note: in most of my experiments I dragged by the corner
 > (top-left or bottom-right), and moved in circular-ish, random
 > trajectories. This triggers the bug most prominently. But if I just
 > grab one border and move the mouse in a straight line, that makes the
 > border move in the desired direction, albeit not exactly following the
 > mouse cursor (hence the effect, probably).
 >
 > E.g. if I drag the right border right, it moves after the mouse, but
 > more slowly than the mouse. If I move it left, it moves *faster* than
 > the mouse. Same with the bottom border. Top and left seem to have a
 > similar effect, but less pronounced. Also dragging the top border
 > seems to have an effect on the position of the bottom edge (it moves
 > up). In all cases, resizing is not smooth.

Both of these hint at Bug#38452.

 > Seems so. Aside from the toolbar icons which are not scaled. The context menu appears where it should.

Aha.  Are tooltips well-positioned too?

(A side question: Do emacs' native tooltips work with a gtk build -
customizing 'x-gtk-use-system-tooltips' to nil?)

 > Also, the GTK3 build seems to have the same problem, and it has had quite a few HiDPI patches applied recently.

You mean the icons problem?

 > So maybe scaling is not the actual issue (or the jumps would be sharper, this just occurred to me).
 >
 >>  > In the meantime, resizing the first, "normal" frame works okay. Moving
 >>  > too (by the title bar).
 >>
 >> How comes the first frame has a title bar with this specification
 >
 > Err, it never occurred to me to put this form in the init script.
 >
 > I launch Emacs, then evaluate this in scratch in the first frame, and then press 'C-x 5 2' and experiment with the second frame.
 >
 >> (setq default-frame-alist
 >>        '((minibuffer . nil) (undecorated . t) (drag-with-mode-line . t)
 >>      (border-width . 0) (internal-border-width . 8) (drag-internal-border . t)
 >>      (menu-bar-lines . 0) (tool-bar-lines . 0)))
 >>
 >>  > GTK:
 >>  >
 >>  > Actually, similar story with resizing.
 >>
 >> You mean similar to the Lucid resizing behavior?
 >
 > Yes (!!). Very similar (maybe exactly the same even).

I just noticed that dragging the left border of a normal GTK frame moves
the right border too here.  So something is rotten.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-26 17:38                                                                                         ` martin rudalics
@ 2020-01-26 20:50                                                                                           ` Dmitry Gutov
  2020-01-28  9:46                                                                                             ` martin rudalics
  2020-01-27 19:17                                                                                           ` martin rudalics
  2020-01-27 23:20                                                                                           ` Dmitry Gutov
  2 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-26 20:50 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 26.01.2020 20:38, martin rudalics wrote:

>  > Changed the scaling factor of the desktop to 100% (everything became 
> tiny on my monitor), restarted Emacs.
>  >
>  >    => dragging by mode-line was smooth
> 
> Don't you have some old laptop somwehere where you could try the
> experiments without scaling (I'd never believe that changing scaling
> on-the-fly works always in a reproducible fashion).

I should see if my old laptop is still functional when I'm near 
geographically (maybe tomorrow).

Speaking of old laptops, my offer regarding help installing GNOME or 
sending a newer video card still stands. Although I'm guessing, given an 
old enough system, you might have to change both the MB and CPU as well.

> And, it does _not_ work smoothly here.  I can drag the frame smoothly by
> a short distance, then it suddenly jumps, then it drags smoothly again
> and so on ...

I'm guessing you could be more sensitive to GC pauses. My current laptop 
is almost top-of-the-line.

>  > BUT dragging the borders to resize had the same problem I reported 
> previously, so it's likely not HiDPI related.
> 
> Dragging the right and bottom borders too?  Here dragging any border is
> usually smooth with very occasional jumps.  But it's much better than
> moving.

Yes. I described that later in the previous email.

>  > Then I changed scaling back to 200%, restarted Emacs.
>  >
>  >    => dragging by mode-line was still smooth (normal frame).
> 
> That's what I meant with never to change scaling with a running desktop.
> Hot-plugging a scale factor is troublesome like changing the resolution
> of the display IMHO.

Same flakiness of behavior also happened the last time I tried this. And 
at that time I didn't change the scale factor at all. Simply: at the 
beginning of the session dragging was smooth, then something happened, 
and it became choppy. And I deleted/created new frames in the meantime.

>  > Then tried the child-frame example.
>  >
>  >    => dragging was choppy. But it resizes smoothly enough when dragged
>  > by the bottom or right edges. And, more importantly, resizes
>  > correctly. When dragged by top-left, it resizes choppily, but still
>  > correctly.
>  >
>  > In the same session, I applied your default-frame-alist change and
>  > created a second "normal" frame. Dragging it by mode-line was choppy
>  > again.
> 
> This again hints at something not really reproducible when changing the
> scale factor.

I don't think so. And again, in this instance, both the child frame and 
the normal frame were created after the last change of the scale factor.

I also repeated this experiment at least twice (restarting Emacs in 
between).

>  > When I drag top-left, the bottom-right corner seems to exhibit a more
>  > gradual drift top-left. When I drag bottom-right, I moves top-left a
>  > lot more quickly (even if I drag it in the bottom-right direction).
> 
> This might be related to the fact that we move and resize in two
> distinct steps.  I wrote a function to do both in one step but its
> behavior is just broken with pure X-builds and I'm not able to find out
> what goes wrong (it doesn't work with normal frames either).
> 
> But it obviously might be a by-product of Bug#38452.

Could be. But the effect is a lot more pronounced.

>  > Seems so. Aside from the toolbar icons which are not scaled. The 
> context menu appears where it should.
> 
> Aha.  Are tooltips well-positioned too?

Yup. Using both Lucid and GTK3.

> (A side question: Do emacs' native tooltips work with a gtk build -
> customizing 'x-gtk-use-system-tooltips' to nil?)

Seem to work, yes. Tested with flymake-mode and tooltip-mode on.

>  > Also, the GTK3 build seems to have the same problem, and it has had 
> quite a few HiDPI patches applied recently.
> 
> You mean the icons problem?

The normal frame resizing problem (with drag-internal-border). The icons 
are fine.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-26 15:32                                                                                         ` martin rudalics
@ 2020-01-26 21:35                                                                                           ` Dmitry Gutov
  2020-01-28  9:46                                                                                             ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-26 21:35 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 26.01.2020 18:32, martin rudalics wrote:
>  > Okay. With xterm.diff applied it works like this:
>  >
>  > Breakpoint 1 is hit. I add breakpoint 2. Hit continue -> B 2 is hit.
> 
> This is at least interesting so we could continue work from here.  IIUC
> B 2 is hit but no resizing occurs.  Is that correct?

Yes.

>  > Call resize-test again (target height is the same): B1 is hit, B2 is 
> not.
> 
> OK per se, just that our frame does not have that height and we don't
> know.

Right.

>  > Change resize-test to call set-frame-height with a different HEIGHT 
> (e.g. 30). Call resize-test: B1 and B2 are both hit.
>  >
>  > Call resize-test again (however many times): only B1 is hit.
> 
> OK, both.  Just that the frame still doesn't have that height.  Right?

Yup.

>  > IOW, something somewhere remembers the last value we've set HEIGHT 
> to, and doesn't send any more configureEvent's for the same value.
> 
> That something should be Emacs itself.  At the time adjust_frame_size is
> called in say 'set-frame-height' it's not yet clear whether Emacs will
> issue a resize request.  The resize request is issued in this block
> 
>        if (FRAME_TERMINAL (f)->set_window_size_hook)
>          FRAME_TERMINAL (f)->set_window_size_hook
>        (f, 0, new_text_width, new_text_height, 1);
>        f->resized_p = true;
> 
> of adjust_frame_size so if you set B 1 there you will see whether Emacs
> has decided that the request is necessary so it gets dispatched to the
> various toolkit backends (or frontends depending on the way you look at
> them).  Please try.

AFAICT, the "if" predicate always returns true when resize-test is 
called: I set breakpoints on both the first and the second lines, and 
both of them are triggered when resize-test is called. Yet, the frame is 
not resized.

>  > The actual visible height of the child frame still doesn't change, 
> meanwhile.
> 
> One thing that can be useful for further debugging: Put a background on
> the child frame like this (which also disables some additional things).
> 
> (defun open-test (buffer)
>    (display-buffer-in-child-frame
>     buffer '((child-frame-parameters
>               . ((width . 10)
>                  (height . 10)
>                  (top . 50)
>                  (left . 50)
>          (undecorated . t)
> ;;         (override-redirect . t)
>          (inhibit-double-buffering . t)
>          (background-color . "yellow")
>          (minibuffer . nil)
>          (tool-bar-lines . 0)
>          (menu-bar-lines . 0)
>          (vertical-scroll-bars . nil)
>          (horizontal-scroll-bars . nil)
>          (left-fringe . 0)
>          (right-fringe . 0)
>          (border-width . 0)
>          (internal-border-width . 2)
>          (drag-internal-border . t)
>          (drag-with-mode-line . t)
>                  )))))
> 
> The background color here is useful to discern window system operations
> that apparently do clear parts of the screen in reaction to our requests
> but do not send us the related ConfigureNotify message nor the messages
> to re-expose the obscured parts of the parent frame.

The child frame's background is now yellow. But I don't see anything 
else happen with it when I call resize-test.

> And finally try the attached patch for GTK builds to resize frames
> directly via gdk calls.  I doubt it changes anything but who knows.

Alas, no change. With override-redirect uncommented -- too.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-26 17:38                                                                                         ` martin rudalics
  2020-01-26 20:50                                                                                           ` Dmitry Gutov
@ 2020-01-27 19:17                                                                                           ` martin rudalics
  2020-01-27 21:15                                                                                             ` Dmitry Gutov
  2020-01-27 23:20                                                                                           ` Dmitry Gutov
  2 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-27 19:17 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1289 bytes --]

 > I just noticed that dragging the left border of a normal GTK frame moves
 > the right border too here.  So something is rotten.

The reason for this (and I don't know if you've seen it as well) is that
'mouse-resize-frame' consults 'frame-text-height' (and/or
'frame-text-width') in a fairly tight loop and it should not do that.

To reproduce the problem, load the attached foobar.el with emacs -Q
using the command 'reset' to put the frame at some fixed position and
size.  You may have to play with the numbers to get results suitable for
your setup.

The commands 'foo-' and 'foo+' drag the left border a 100 times to the
right or left by three pixels in one step.  The right border should
remain unchanged.  The commands 'bar-' and 'bar+' should do the same
but, in fact, sometimes move the right border as well.  Doing a
'redisplay' or sleeping in between each single movement makes the 'bar'
functions behave more like the 'foo' ones but still not 100%.

The reason might be the way we delay size changes in change_frame_sizes
and eventually process them via do_pending_window_change.  Somehow,
frame size and position can drift apart while we process them and unless
we put some tight synchronization there (via redisplay) or wait long
enough the calculations go wrong.

martin

[-- Attachment #2: foobar.el --]
[-- Type: text/x-emacs-lisp, Size: 1839 bytes --]

(setq frame-resize-pixelwise t)

(defvar left 500)
(defvar top 100)
(defvar width 800)
(defvar height 400)

(defun reset ()
  (interactive)
  (setq left 500)
  (setq top 100)
  (setq width 800)
  (setq height 400)
  (modify-frame-parameters
   nil `((width . (text-pixels . ,width))
	 (height . (text-pixels . ,height))
	 (left . ,left) (top . ,top))))

(defun foo- ()
  (interactive)
  (let ((i 0))
    (while (< i 100)
      (setq left (- left 3))
      (setq width (+ width 3))
      (setq i (1+ i))
      (modify-frame-parameters
       nil `((width . (text-pixels . ,width))
	     (height . (text-pixels . ,height))
	     (left . ,left) (top . ,top)))
;;       (redisplay t)
;;       (sleep-for 0.1)
      )))

(defun foo+ ()
  (interactive)
  (let ((i 0))
    (while (< i 100)
      (setq left (+ left 3))
      (setq width (- width 3))
      (setq i (1+ i))
      (modify-frame-parameters
       nil `((width . (text-pixels . ,width))
	     (height . (text-pixels . ,height))
	     (left . ,left) (top . ,top)))
;;       (redisplay t)
;;       (sleep-for 0.1)
      )))

(defun bar- ()
  (interactive)
  (let ((i 0))
    (while (< i 100)
      (setq left (- left 3))
      (setq width (+ width 3))
      (setq i (1+ i))
      (modify-frame-parameters
       nil `((width . (text-pixels . ,(+ (frame-text-width) 3)))
	     (height . (text-pixels . ,height))
	     (left . ,left) (top . ,top)))
;;       (redisplay t)
;;       (sleep-for 0.1)
      )))

(defun bar+ ()
  (interactive)
  (let ((i 0))
    (while (< i 100)
      (setq left (+ left 3))
      (setq width (- width 3))
      (setq i (1+ i))
      (modify-frame-parameters
       nil `((width . (text-pixels . ,(- (frame-text-width) 3)))
	     (height . (text-pixels . ,height))
	     (left . ,left) (top . ,top)))
;;       (redisplay t)
;;       (sleep-for 0.1)
      )))

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-27 19:17                                                                                           ` martin rudalics
@ 2020-01-27 21:15                                                                                             ` Dmitry Gutov
  2020-01-28  9:47                                                                                               ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-27 21:15 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 27.01.2020 22:17, martin rudalics wrote:
>  > I just noticed that dragging the left border of a normal GTK frame moves
>  > the right border too here.  So something is rotten.
> 
> The reason for this (and I don't know if you've seen it as well)

Not really. If I drag any border of a normal, decorated frame, the other 
borders stay where they were.

I'm guessing that here, under Mutter, the window manager controls the 
sizing and positioning when I'm doing this. And Emacs just handles 
sizing notifications and redraws itself. So I've never seen this 
particular issue act up in practice.

But your description sounds similar to my results in the previous 
experiment with non-decorated non-child frames.

> The 
> commands 'foo-' and 'foo+' drag the left border a 100 times to the
> right or left by three pixels in one step.  The right border should
> remain unchanged.  The commands 'bar-' and 'bar+' should do the same
> but, in fact, sometimes move the right border as well.

Yes, I'm seeing exactly the same results with these commands (aside from 
the redisplay detail, which I haven't tried).



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-26 17:38                                                                                         ` martin rudalics
  2020-01-26 20:50                                                                                           ` Dmitry Gutov
  2020-01-27 19:17                                                                                           ` martin rudalics
@ 2020-01-27 23:20                                                                                           ` Dmitry Gutov
  2020-01-27 23:32                                                                                             ` Dmitry Gutov
  2020-01-28  9:48                                                                                             ` martin rudalics
  2 siblings, 2 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-27 23:20 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 26.01.2020 20:38, martin rudalics wrote:
> Don't you have some old laptop somwehere where you could try the
> experiments without scaling (I'd never believe that changing scaling
> on-the-fly works always in a reproducible fashion).

So, I tried this stuff on an old laptop. Ubuntu 16.04, with whatever 
version of Unity was there, as well as with GNOME Shell 3.18 (and the 
same version of GTK3 in both cases). No scaling.

Unity:

Child frame resizes fine, just like in all other DEs aside from Mutter, 
apparently.

GNOME:

Child frame does not resize, even using these rather old GNOME Mutter 
and GTK.

Dragging a normal un-decorated Lucid frame is smooth-ish (with pauses). 
Although I hadn't tried the more involved experiment involving a child 
frame.

In both:

Normal un-decorated frames have exactly the same drag-resizing behavior 
problem that I described before, so it's definitely not HiDPI-related.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-27 23:20                                                                                           ` Dmitry Gutov
@ 2020-01-27 23:32                                                                                             ` Dmitry Gutov
  2020-01-28  9:48                                                                                               ` martin rudalics
  2020-01-28  9:48                                                                                             ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-27 23:32 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 28.01.2020 2:20, Dmitry Gutov wrote:
> So, I tried this stuff on an old laptop. Ubuntu 16.04, with ... 
> ... GNOME Shell 3.18 (and the 
> same version of GTK3 in both cases). No scaling.

Something else:

Dragging a GTK3 un-decorated normal frame by the mode-line in this GNOME 
environment didn't exhibit the same kind of "drift" that I'm seeing on 
the newer system.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-26 20:50                                                                                           ` Dmitry Gutov
@ 2020-01-28  9:46                                                                                             ` martin rudalics
  2020-01-28 15:19                                                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-28  9:46 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> And, it does _not_ work smoothly here.  I can drag the frame smoothly by
 >> a short distance, then it suddenly jumps, then it drags smoothly again
 >> and so on ...
 >
 > I'm guessing you could be more sensitive to GC pauses.

This could be the cause.  I'll have to set up my code to check that.

 >> Dragging the right and bottom borders too?  Here dragging any border is
 >> usually smooth with very occasional jumps.  But it's much better than
 >> moving.
 >
 > Yes. I described that later in the previous email.

It just doesn't make sense.  Moving a frame is a no-brainer, regardless
of whether you do it via the title bar or via the mode line.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-26 21:35                                                                                           ` Dmitry Gutov
@ 2020-01-28  9:46                                                                                             ` martin rudalics
  2020-01-30  2:23                                                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-28  9:46 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> This is at least interesting so we could continue work from here.  IIUC
 >> B 2 is hit but no resizing occurs.  Is that correct?
 >
 > Yes.

Can you enable the 'frame-size-history' here?  The ingredient would be a
gtk build with xterm.diff applied loading the old resize child frame
code.  Then eval

(progn
   (setq frame-size-history '(100))
   (resize-test test-frame)
   (frame--size-history test-frame)
   (display-buffer "*frame-size-history*"))

and post the result.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-27 21:15                                                                                             ` Dmitry Gutov
@ 2020-01-28  9:47                                                                                               ` martin rudalics
  2020-01-30  2:10                                                                                                 ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-28  9:47 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> The reason for this (and I don't know if you've seen it as well)
 >
 > Not really. If I drag any border of a normal, decorated frame, the other borders stay where they were.

Did you run this with a pristine, unpatched GTK+ build?  Did you compare
the outer right edges before and after the moves?  Everything here is OK
when running the 'bar' functions from a Lucid build, BTW.

I suppose though that your Emacs' redraws too lag behind by showing
either a gap between the right scroll bar and frame border when dragging
to the left and not showing the scroll bar when dragging to the right?
Here they do that even when dragging the left border with the WM alone.

 > I'm guessing that here, under Mutter, the window manager controls the
 > sizing and positioning when I'm doing this. And Emacs just handles
 > sizing notifications and redraws itself. So I've never seen this
 > particular issue act up in practice.

Then it would ignore the Emacs sizing request even for a top-level frame
something we hadn't that far.  Unless your machine is so fast that you
can handle all requests in "real time" so that you don't see the lags I
mentioned above.

 > But your description sounds similar to my results in the previous experiment with non-decorated non-child frames.
 >
 >> The commands 'foo-' and 'foo+' drag the left border a 100 times to the
 >> right or left by three pixels in one step.  The right border should
 >> remain unchanged.  The commands 'bar-' and 'bar+' should do the same
 >> but, in fact, sometimes move the right border as well.
 >
 > Yes, I'm seeing exactly the same results with these commands (aside from the redisplay detail, which I haven't tried).

You mean the right border never ever moves with the bar functions.
Don't bother for the redisplay and sleep-for details then.  We just see
different bugs with different builds and WMs.  Biodiversity at work.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-27 23:20                                                                                           ` Dmitry Gutov
  2020-01-27 23:32                                                                                             ` Dmitry Gutov
@ 2020-01-28  9:48                                                                                             ` martin rudalics
  2020-01-28 15:51                                                                                               ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-28  9:48 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > So, I tried this stuff on an old laptop. Ubuntu 16.04, with whatever
 > version of Unity was there, as well as with GNOME Shell 3.18 (and the
 > same version of GTK3 in both cases). No scaling.

Thank you.

 > Unity:
 >
 > Child frame resizes fine, just like in all other DEs aside from Mutter, apparently.
 >
 > GNOME:
 >
 > Child frame does not resize, even using these rather old GNOME Mutter and GTK.
 >
 > Dragging a normal un-decorated Lucid frame is smooth-ish (with pauses).

GC pauses maybe.

 > Although I hadn't tried the more involved experiment involving a child frame.
 >
 > In both:
 >
 > Normal un-decorated frames have exactly the same drag-resizing behavior problem that I described before, so it's definitely not HiDPI-related.

Can you please summarize that behavior in one or two sentences.

In either case the child frame issue cannot be resolved from here.  We
have to discuss that with the mutter people.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-27 23:32                                                                                             ` Dmitry Gutov
@ 2020-01-28  9:48                                                                                               ` martin rudalics
  2020-01-28 15:39                                                                                                 ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-28  9:48 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > Something else:
 >
 > Dragging a GTK3 un-decorated normal frame by the mode-line in this GNOME environment didn't exhibit the same kind of "drift" that I'm seeing on the newer system.

What was that "drift"?  The fact that mouse cursor and frame edge/corner
drift apart?  Here these drift apart when dragging a normally decorated
frame too.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-28  9:46                                                                                             ` martin rudalics
@ 2020-01-28 15:19                                                                                               ` Dmitry Gutov
  2020-01-28 16:20                                                                                                 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-28 15:19 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 28.01.2020 12:46, martin rudalics wrote:
>  >> Dragging the right and bottom borders too?  Here dragging any border is
>  >> usually smooth with very occasional jumps.  But it's much better than
>  >> moving.
>  >
>  > Yes. I described that later in the previous email.
> 
> It just doesn't make sense.  Moving a frame is a no-brainer, regardless
> of whether you do it via the title bar or via the mode li

Resizing the frame. Dragging the borders (right and bottom too) resizes 
the frame, and doing that with an un-decorated normal frame exhibits the 
same broken resizing behavior.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-28  9:48                                                                                               ` martin rudalics
@ 2020-01-28 15:39                                                                                                 ` Dmitry Gutov
  2020-01-28 16:20                                                                                                   ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-28 15:39 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 28.01.2020 12:48, martin rudalics wrote:
>  > Dragging a GTK3 un-decorated normal frame by the mode-line in this 
> GNOME environment didn't exhibit the same kind of "drift" that I'm 
> seeing on the newer system.
> 
> What was that "drift"?  The fact that mouse cursor and frame edge/corner
> drift apart?

Mouse cursor and the mode-line drift apart (I'm dragging by the mode-line).

 > Here these drift apart when dragging a normally decorated
 > frame too.

Apparently Mutter makes sure that this doesn't happen.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-28  9:48                                                                                             ` martin rudalics
@ 2020-01-28 15:51                                                                                               ` Dmitry Gutov
  0 siblings, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-28 15:51 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 28.01.2020 12:48, martin rudalics wrote:
>  > So, I tried this stuff on an old laptop. Ubuntu 16.04, with whatever
>  > version of Unity was there, as well as with GNOME Shell 3.18 (and the
>  > same version of GTK3 in both cases). No scaling.
> <...>
>  > In both:
>  >
>  > Normal un-decorated frames have exactly the same drag-resizing 
> behavior problem that I described before, so it's definitely not 
> HiDPI-related.
> 
> Can you please summarize that behavior in one or two sentences.

Dragging the bottom-right corner of a non-decorated normal frame in a 
circular motion causes the frame to shrink. Same for the top-left 
corner, albeit more slowly.

Dragging the right border right moves it right, but more slowly than the 
cursor. Dragging it left makes it move faster than the cursor. Etc. I've 
described this before.

> In either case the child frame issue cannot be resolved from here.  We
> have to discuss that with the mutter people.

I'm pretty sure child frame resizing issue under Mutter is unrelated to 
the above. But sure.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-28 15:19                                                                                               ` Dmitry Gutov
@ 2020-01-28 16:20                                                                                                 ` martin rudalics
  2020-01-30  2:14                                                                                                   ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-28 16:20 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >>  >> Dragging the right and bottom borders too?  Here dragging any border is
 >>  >> usually smooth with very occasional jumps.  But it's much better than
 >>  >> moving.
 >>  >
 >>  > Yes. I described that later in the previous email.
 >>
 >> It just doesn't make sense.  Moving a frame is a no-brainer, regardless
 >> of whether you do it via the title bar or via the mode li
 >
 > Resizing the frame. Dragging the borders (right and bottom too) resizes the frame, and doing that with an un-decorated normal frame exhibits the same broken resizing behavior.

We have miscommunicated here: First I wrote that resizing is "much better
than moving" (because dragging a border is resizing) and you apparently
agreed with "Yes. I described that later in the previous email.".  Then
I meant that "Moving a frame is a no-brainer" and you responded with
"Resizing the frame.".

Either way, both resizing and moving are broken.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-28 15:39                                                                                                 ` Dmitry Gutov
@ 2020-01-28 16:20                                                                                                   ` martin rudalics
  0 siblings, 0 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-28 16:20 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >>  > Dragging a GTK3 un-decorated normal frame by the mode-line in this GNOME environment didn't exhibit the same kind of "drift" that I'm seeing on the newer system.
 >>
 >> What was that "drift"?  The fact that mouse cursor and frame edge/corner
 >> drift apart?
 >
 > Mouse cursor and the mode-line drift apart (I'm dragging by the mode-line).
 >
 >  > Here these drift apart when dragging a normally decorated
 >  > frame too.
 >
 > Apparently Mutter makes sure that this doesn't happen.

I lied.  Mouse cursor and title bar never drift here either.  Mouse cursor
and corners drift.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-28  9:47                                                                                               ` martin rudalics
@ 2020-01-30  2:10                                                                                                 ` Dmitry Gutov
  2020-01-30  9:38                                                                                                   ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-30  2:10 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 28.01.2020 12:47, martin rudalics wrote:
>  >> The reason for this (and I don't know if you've seen it as well)
>  >
>  > Not really. If I drag any border of a normal, decorated frame, the 
> other borders stay where they were.
> 
> Did you run this with a pristine, unpatched GTK+ build?  Did you compare
> the outer right edges before and after the moves?  Everything here is OK
> when running the 'bar' functions from a Lucid build, BTW.

Unpatched GTK+ build, yes. Or any other build. Resizing the "normal" 
kind of frames always behaves as expected here. Moving by the title-bar 
does, too. It might be not buttery-smooth, but the edges always move 
where expected, and there are no unexpected jumps that I see when 
resizing an undecorated frame. Or move a frame by the mode-line in a 
Lucid build.

I didn't exactly compare the edge positions programmatically, but my 
eyes are usually good at catching that kind of thing.

> I suppose though that your Emacs' redraws too lag behind by showing
> either a gap between the right scroll bar and frame border when dragging
> to the left and not showing the scroll bar when dragging to the right?
> Here they do that even when dragging the left border with the WM alone.

That happens here too.

And it's not what my previous complaints were about. A drift is not 
simply a lag. Lag rights itself at the end of the cursor motion (you 
just have to wait a little). Drift doesn't right itself: the cursor ends 
up at a certain distance from the the point of the frame it has been 
dragging.

>  > I'm guessing that here, under Mutter, the window manager controls the
>  > sizing and positioning when I'm doing this. And Emacs just handles
>  > sizing notifications and redraws itself. So I've never seen this
>  > particular issue act up in practice.
> 
> Then it would ignore the Emacs sizing request even for a top-level frame
> something we hadn't that far.  Unless your machine is so fast that you
> can handle all requests in "real time" so that you don't see the lags I
> mentioned above.

It doesn't exactly ignore sizing requests. Or not all of them. At least, 
set-frame-size works just fine on top-level frames like that.

Rather, I think in these cases it's not Emacs which handles the resizing 
or dragging events. The WM does that and only tells the Emacs window to 
resize appropriately.

>  > But your description sounds similar to my results in the previous 
> experiment with non-decorated non-child frames.
>  >
>  >> The commands 'foo-' and 'foo+' drag the left border a 100 times to the
>  >> right or left by three pixels in one step.  The right border should
>  >> remain unchanged.  The commands 'bar-' and 'bar+' should do the same
>  >> but, in fact, sometimes move the right border as well.
>  >
>  > Yes, I'm seeing exactly the same results with these commands (aside 
> from the redisplay detail, which I haven't tried).
> 
> You mean the right border never ever moves with the bar functions.

I'm saying I see the same results are you do (with Mutter; GTK3 build).

foo commands don't move the right border. bar commands do move it 
(basically always).



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-28 16:20                                                                                                 ` martin rudalics
@ 2020-01-30  2:14                                                                                                   ` Dmitry Gutov
  0 siblings, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-30  2:14 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 28.01.2020 19:20, martin rudalics wrote:
> We have miscommunicated here: First I wrote that resizing is "much better
> than moving" (because dragging a border is resizing) and you apparently
> agreed with "Yes. I described that later in the previous email.".  Then
> I meant that "Moving a frame is a no-brainer" and you responded with
> "Resizing the frame.".

Sorry if it was unclear.

"Yes" was my answer to "Dragging the right and bottom borders too?", the 
question which started your paragraph that ended with "But it's much 
better than moving".

> Either way, both resizing and moving are broken.

Apparently so. Though only some of this breakage is relevant to child 
frames, I think.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-28  9:46                                                                                             ` martin rudalics
@ 2020-01-30  2:23                                                                                               ` Dmitry Gutov
  2020-01-30  9:38                                                                                                 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-30  2:23 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 28.01.2020 12:46, martin rudalics wrote:
> Can you enable the 'frame-size-history' here?  The ingredient would be a
> gtk build with xterm.diff applied loading the old resize child frame
> code.  Then eval
> 
> (progn
>    (setq frame-size-history '(100))
>    (resize-test test-frame)
>    (frame--size-history test-frame)
>    (display-buffer "*frame-size-history*"))
> 
> and post the result.

Here you go. It's a little different, but not by much. :-(

Frame size history of #<frame test child-frame 0x55a43258efd0>
adjust-frame-size-1	 (720 360 720 720) (height 1)
adjust-frame-size-2	 (720 360 720 720) (nil nil)
x-set-window-size-3	 (720 360 720 720) (768 720 0)



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-30  2:23                                                                                               ` Dmitry Gutov
@ 2020-01-30  9:38                                                                                                 ` martin rudalics
  2020-01-30 17:32                                                                                                   ` Dmitry Gutov
  2020-01-30 17:42                                                                                                   ` Dmitry Gutov
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-30  9:38 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> Can you enable the 'frame-size-history' here?  The ingredient would be a
 >> gtk build with xterm.diff applied loading the old resize child frame
 >> code.  Then eval
 >>
 >> (progn
 >>    (setq frame-size-history '(100))
 >>    (resize-test test-frame)
 >>    (frame--size-history test-frame)
 >>    (display-buffer "*frame-size-history*"))
 >>
 >> and post the result.
 >
 > Here you go. It's a little different, but not by much. :-(
 >
 > Frame size history of #<frame test child-frame 0x55a43258efd0>
 > adjust-frame-size-1     (720 360 720 720) (height 1)
 > adjust-frame-size-2     (720 360 720 720) (nil nil)
 > x-set-window-size-3     (720 360 720 720) (768 720 0)

I suppose it does nothing because it cannot get a top frame.  If you put
a breakpoint within 'set-frame-height' run the usual 'resize-test' and
when that breakpoint is hit set a breakpoint at

       f = x_top_window_to_frame (dpyinfo, configureEvent.xconfigure.window);

around line 8927 in xterm.c and do "n" after that breakpoint is hit,
what do you get if you do p f now?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-30  2:10                                                                                                 ` Dmitry Gutov
@ 2020-01-30  9:38                                                                                                   ` martin rudalics
  2020-01-30 17:21                                                                                                     ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-30  9:38 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 638 bytes --]

 > And it's not what my previous complaints were about. A drift is not
 > simply a lag. Lag rights itself at the end of the cursor motion (you
 > just have to wait a little). Drift doesn't right itself: the cursor
 > ends up at a certain distance from the the point of the frame it has
 > been dragging.

I've rewritten the mouse code completely, patch attached.  It neither
fixes the GTK child frame resizing problem nor the jumping issues in
Lucid but should provide better dragging of frames via internal borders
and mode-/header-line otherwise.  In particular the drift you mentioned
above should be gone now.  Please try it.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mouse.el.diff --]
[-- Type: text/x-patch; name="mouse.el.diff", Size: 32187 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index e58a2e6da1..bacee65436 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -552,7 +552,7 @@ mouse-drag-mode-line
              (not (eq (window-frame minibuffer-window) frame))))
       ;; Drag frame when the window is on the bottom of its frame and
       ;; there is no minibuffer window below.
-      (mouse-drag-frame start-event 'move)))))
+      (mouse-drag-frame-move start-event)))))
 
 (defun mouse-drag-header-line (start-event)
   "Change the height of a window by dragging on its header line.
@@ -569,7 +569,7 @@ mouse-drag-header-line
         (mouse-drag-line start-event 'header)
       (let ((frame (window-frame window)))
         (when (frame-parameter frame 'drag-with-header-line)
-          (mouse-drag-frame start-event 'move))))))
+          (mouse-drag-frame-move start-event))))))
 
 (defun mouse-drag-vertical-line (start-event)
   "Change the width of a window by dragging on a vertical line.
@@ -577,46 +577,7 @@ mouse-drag-vertical-line
   (interactive "e")
   (mouse-drag-line start-event 'vertical))
 \f
-(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move)
-  "Helper function for `mouse-drag-frame'."
-  (let* ((frame-x-y (frame-position frame))
-         (frame-x (car frame-x-y))
-         (frame-y (cdr frame-x-y))
-         alist)
-    (if (> x-diff 0)
-        (when x-move
-          (setq x-diff (min x-diff frame-x))
-          (setq x-move (- frame-x x-diff)))
-      (let* ((min-width (frame-windows-min-size frame t nil t))
-             (min-diff (max 0 (- (frame-inner-width frame) min-width))))
-        (setq x-diff (max x-diff (- min-diff)))
-        (when x-move
-          (setq x-move (+ frame-x (- x-diff))))))
-
-    (if (> y-diff 0)
-        (when y-move
-          (setq y-diff (min y-diff frame-y))
-          (setq y-move (- frame-y y-diff)))
-      (let* ((min-height (frame-windows-min-size frame nil nil t))
-             (min-diff (max 0 (- (frame-inner-height frame) min-height))))
-        (setq y-diff (max y-diff (- min-diff)))
-        (when y-move
-          (setq y-move (+ frame-y (- y-diff))))))
-
-    (unless (zerop x-diff)
-      (when x-move
-        (push `(left . ,x-move) alist))
-      (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff)))
-            alist))
-    (unless (zerop y-diff)
-      (when y-move
-        (push `(top . ,y-move) alist))
-      (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff)))
-            alist))
-    (when alist
-      (modify-frame-parameters frame alist))))
-
-(defun mouse-drag-frame (start-event part)
+(defun mouse-drag-frame-resize (start-event part)
   "Drag a frame or one of its edges with the mouse.
 START-EVENT is the starting mouse event of the drag action.  Its
 position window denotes the frame that will be dragged.
@@ -635,9 +596,140 @@ mouse-drag-frame
          (frame (if (window-live-p window)
                     (window-frame window)
                   window))
-         (width (frame-native-width frame))
-         (height (frame-native-height frame))
-         ;; PARENT is the parent frame of FRAME or, if FRAME is a
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+	 (first-top (cdr first-pos))
+	 (first-width (frame-text-width frame))
+	 (first-height (frame-text-height frame))
+	 ;; Don't let FRAME become less large than the size needed to
+	 ;; fit all of its windows.
+	 (min-text-width
+	  (+ (frame-windows-min-size frame t nil t)
+	     (- (frame-inner-width frame) first-width)))
+	 (min-text-height
+	  (+ (frame-windows-min-size frame nil nil t)
+	     (- (frame-inner-height frame) first-height)))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
+         ;; top-level frame, FRAME's workarea.
+         (parent (frame-parent frame))
+         (parent-edges
+          (if parent
+              (frame-edges parent)
+            (let* ((attributes
+                    (car (display-monitor-attributes-list)))
+                   (workarea (assq 'workarea attributes)))
+              (and workarea
+                   `(,(nth 1 workarea) ,(nth 2 workarea)
+                     ,(+ (nth 1 workarea) (nth 3 workarea))
+                     ,(+ (nth 2 workarea) (nth 4 workarea)))))))
+         (parent-left (and parent-edges (nth 0 parent-edges)))
+         (parent-top (and parent-edges (nth 1 parent-edges)))
+         (parent-right (and parent-edges (nth 2 parent-edges)))
+         (parent-bottom (and parent-edges (nth 3 parent-edges)))
+	 ;; Drag types.  drag-left/drag-right and drag-top/drag-bottom
+	 ;; are mutually exclusive.
+	 (drag-left (memq part '(bottom-left left top-left)))
+	 (drag-top (memq part '(top-left top top-right)))
+	 (drag-right (memq part '(top-right right bottom-right)))
+	 (drag-bottom (memq part '(bottom-right bottom bottom-left)))
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         (exitfun nil)
+         (move
+          (lambda (event)
+            (interactive "e")
+            (when (consp event)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+		     alist)
+                ;; We never want to warp the mouse position here.  When
+                ;; moving the mouse leftward or upward, then with a wide
+                ;; border the calculated left or top position of the
+                ;; frame could drop to a value less than zero depending
+                ;; on where precisely the mouse within the border.  We
+                ;; guard against this by never allowing the frame to
+                ;; move to a position less than zero here.  No such
+                ;; precautions are used for the right and bottom borders
+                ;; so with a large internal border parts of that border
+                ;; may disappear.
+                (when (and drag-left (>= last-x parent-left)
+                           (>= (- first-width left) min-text-width))
+		  (push `(left . ,(max (+ first-left left) 0)) alist)
+		  (push `(width . (text-pixels . ,(- first-width left))) alist))
+	        (when (and drag-top (>= last-y parent-top)
+                           (>= (- first-height top) min-text-height))
+		  (push `(top . ,(max 0 (+ first-top top))) alist)
+		  (push `(height . (text-pixels . ,(- first-height top))) alist))
+	        (when (and drag-right (<= last-x parent-right)
+                           (>= (+ first-width left) min-text-width))
+		  (push `(width . (text-pixels . ,(+ first-width left))) alist))
+	        (when (and drag-bottom (<= last-y parent-bottom)
+                           (>= (+ first-height top) min-text-height))
+		  (push `(height . (text-pixels . ,(+ first-height top))) alist))
+	        (modify-frame-parameters frame alist)))))
+         (old-track-mouse track-mouse))
+    ;; Start tracking.  The special value 'dragging' signals the
+    ;; display engine to freeze the mouse pointer shape for as long
+    ;; as we drag.
+    (setq track-mouse 'dragging)
+    ;; Loop reading events and sampling the position of the mouse.
+    (setq exitfun
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [scroll-bar-movement] #'ignore)
+             (define-key map [mouse-movement] move)
+             ;; Swallow drag-mouse-1 events to avoid selecting some other window.
+             (define-key map [drag-mouse-1]
+               (lambda () (interactive) (funcall exitfun)))
+             ;; Some of the events will of course end up looked up
+             ;; with a mode-line, header-line or vertical-line prefix ...
+             (define-key map [mode-line] map)
+             (define-key map [header-line] map)
+             (define-key map [vertical-line] map)
+             ;; ... and some maybe even with a right- or bottom-divider
+             ;; prefix.
+             (define-key map [right-divider] map)
+             (define-key map [bottom-divider] map)
+             map)
+           t (lambda () (setq track-mouse old-track-mouse))))))
+
+(defun mouse-drag-frame-move (start-event)
+  "Drag a frame or one of its edges with the mouse.
+START-EVENT is the starting mouse event of the drag action.  Its
+position window denotes the frame that will be dragged.
+
+PART specifies the part that has been dragged and must be one of
+the symbols `left', `top', `right', `bottom', `top-left',
+`top-right', `bottom-left', `bottom-right' to drag an internal
+border or edge.  If PART equals `move', this means to move the
+frame with the mouse."
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
+  (let* ((echo-keystrokes 0)
+	 (start (event-start start-event))
+         (window (posn-window start))
+         ;; FRAME is the frame to drag.
+         (frame (if (window-live-p window)
+                    (window-frame window)
+                  window))
+         (native-width (frame-native-width frame))
+         (native-height (frame-native-height frame))
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+	 (first-top (cdr first-pos))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
          ;; top-level frame, FRAME's workarea.
          (parent (frame-parent frame))
          (parent-edges
@@ -654,19 +746,16 @@ mouse-drag-frame
          (parent-top (and parent-edges (nth 1 parent-edges)))
          (parent-right (and parent-edges (nth 2 parent-edges)))
          (parent-bottom (and parent-edges (nth 3 parent-edges)))
-         ;; `pos-x' and `pos-y' record the x- and y-coordinates of the
-	 ;; last sampled mouse position.  Note that we sample absolute
-	 ;; mouse positions to avoid that moving the mouse from one
-	 ;; frame into another gets into our way.  `last-x' and `last-y'
-	 ;; records the x- and y-coordinates of the previously sampled
-	 ;; position.  The differences between `last-x' and `pos-x' as
-	 ;; well as `last-y' and `pos-y' determine the amount the mouse
-	 ;; has been dragged between the last two samples.
-         pos-x-y pos-x pos-y
-         (last-x-y (mouse-absolute-pixel-position))
-         (last-x (car last-x-y))
-         (last-y (cdr last-x-y))
-         ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         ;; `snap-width' (maybe also a yet to be provided `snap-height')
+         ;; could become floats to handle proportionality wrt PARENT.
+         ;; We don't do any checks on this parameter so far.
+         (snap-width (frame-parameter frame 'snap-width))
+	 ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
          ;; mouse position when FRAME snapped.  As soon as the
          ;; difference between `pos-x' and `snap-x' (or `pos-y' and
          ;; `snap-y') exceeds the value of FRAME's `snap-width'
@@ -678,176 +767,144 @@ mouse-drag-frame
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (setq pos-x-y (mouse-absolute-pixel-position))
-              (setq pos-x (car pos-x-y))
-              (setq pos-y (cdr pos-x-y))
-              (cond
-               ((eq part 'left)
-                (mouse-resize-frame frame (- last-x pos-x) 0 t))
-               ((eq part 'top)
-                (mouse-resize-frame frame 0 (- last-y pos-y) nil t))
-               ((eq part 'right)
-                (mouse-resize-frame frame (- pos-x last-x) 0))
-               ((eq part 'bottom)
-                (mouse-resize-frame frame 0 (- pos-y last-y)))
-               ((eq part 'top-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- last-y pos-y) t t))
-               ((eq part 'top-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- last-y pos-y) nil t))
-               ((eq part 'bottom-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- pos-y last-y) t))
-               ((eq part 'bottom-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- pos-y last-y)))
-               ((eq part 'move)
-                (let* ((old-position (frame-position frame))
-                       (old-left (car old-position))
-                       (old-top (cdr old-position))
-                       (left (+ old-left (- pos-x last-x)))
-                       (top (+ old-top (- pos-y last-y)))
-                       right bottom
-                       ;; `snap-width' (maybe also a yet to be provided
-                       ;; `snap-height') could become floats to handle
-                       ;; proportionality wrt PARENT.  We don't do any
-                       ;; checks on this parameter so far.
-                       (snap-width (frame-parameter frame 'snap-width)))
-                  ;; Docking and constraining.
-                  (when (and (numberp snap-width) parent-edges)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+                     right bottom)
+		(setq left (+ first-left left))
+		(setq top (+ first-top top))
+                ;; Docking and constraining.
+                (when (and (numberp snap-width) parent-edges)
+                  (cond
+                   ;; Docking at the left parent edge.
+                   ((< last-x first-x)
                     (cond
-                     ;; Docking at the left parent edge.
-                     ((< pos-x last-x)
-                      (cond
-                       ((and (> left parent-left)
-                             (<= (- left parent-left) snap-width))
-                        ;; Snap when the mouse moved leftward and
-                        ;; FRAME's left edge would end up within
-                        ;; `snap-width' pixels from PARENT's left edge.
-                        (setq snap-x pos-x)
-                        (setq left parent-left))
-                       ((and (<= left parent-left)
-                             (<= (- parent-left left) snap-width)
-                             snap-x (<= (- snap-x pos-x) snap-width))
-                        ;; Stay snapped when the mouse moved leftward
-                        ;; but not more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq left parent-left))
-                       (t
-                        ;; Unsnap when the mouse moved more than
-                        ;; `snap-width' pixels leftward from the time
-                        ;; FRAME snapped.
-                        (setq snap-x nil))))
-                     ((> pos-x last-x)
-                      (setq right (+ left width))
-                      (cond
-                       ((and (< right parent-right)
-                             (<= (- parent-right right) snap-width))
-                        ;; Snap when the mouse moved rightward and
-                        ;; FRAME's right edge would end up within
-                        ;; `snap-width' pixels from PARENT's right edge.
-                        (setq snap-x pos-x)
-                        (setq left (- parent-right width)))
-                       ((and (>= right parent-right)
-                             (<= (- right parent-right) snap-width)
-                             snap-x (<= (- pos-x snap-x) snap-width))
-                        ;; Stay snapped when the mouse moved rightward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq left (- parent-right width)))
-                       (t
-                        ;; Unsnap when the mouse moved rightward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-x nil)))))
-
+                     ((and (> left parent-left)
+                           (<= (- left parent-left) snap-width))
+                      ;; Snap when the mouse moved leftward and FRAME's
+                      ;; left edge would end up within `snap-width'
+                      ;; pixels from PARENT's left edge.
+                      (setq snap-x last-x)
+                      (setq left parent-left))
+                     ((and (<= left parent-left)
+                           (<= (- parent-left left) snap-width)
+                           snap-x (<= (- snap-x last-x) snap-width))
+                      ;; Stay snapped when the mouse moved leftward but
+                      ;; not more than `snap-width' pixels from the time
+                      ;; FRAME snapped.
+                      (setq left parent-left))
+                     (t
+                      ;; Unsnap when the mouse moved more than
+                      ;; `snap-width' pixels leftward from the time
+                      ;; FRAME snapped.
+                      (setq snap-x nil))))
+                   ((> last-x first-x)
+                    (setq right (+ left native-width))
                     (cond
-                     ((< pos-y last-y)
-                      (cond
-                       ((and (> top parent-top)
-                             (<= (- top parent-top) snap-width))
-                        ;; Snap when the mouse moved upward and FRAME's
-                        ;; top edge would end up within `snap-width'
-                        ;; pixels from PARENT's top edge.
-                        (setq snap-y pos-y)
-                        (setq top parent-top))
-                       ((and (<= top parent-top)
-                             (<= (- parent-top top) snap-width)
-                             snap-y (<= (- snap-y pos-y) snap-width))
-                        ;; Stay snapped when the mouse moved upward but
-                        ;; not more more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq top parent-top))
-                       (t
-                        ;; Unsnap when the mouse moved upward more than
-                        ;; `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))
-                     ((> pos-y last-y)
-                      (setq bottom (+ top height))
-                      (cond
-                       ((and (< bottom parent-bottom)
-                             (<= (- parent-bottom bottom) snap-width))
-                        ;; Snap when the mouse moved downward and
-                        ;; FRAME's bottom edge would end up within
-                        ;; `snap-width' pixels from PARENT's bottom
-                        ;; edge.
-                        (setq snap-y pos-y)
-                        (setq top (- parent-bottom height)))
-                       ((and (>= bottom parent-bottom)
-                             (<= (- bottom parent-bottom) snap-width)
-                             snap-y (<= (- pos-y snap-y) snap-width))
-                        ;; Stay snapped when the mouse moved downward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq top (- parent-bottom height)))
-                       (t
-                        ;; Unsnap when the mouse moved downward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))))
-
-                  ;; If requested, constrain FRAME's draggable areas to
-                  ;; PARENT's edges.  The `top-visible' parameter should
-                  ;; be set when FRAME has a draggable header-line.  If
-                  ;; set to a number, it ascertains that the top of
-                  ;; FRAME is always constrained to the top of PARENT
-                  ;; and that at least as many pixels of FRAME as
-                  ;; specified by that number are visible on each of the
-                  ;; three remaining sides of PARENT.
-                  ;;
-                  ;; The `bottom-visible' parameter should be set when
-                  ;; FRAME has a draggable mode-line.  If set to a
-                  ;; number, it ascertains that the bottom of FRAME is
-                  ;; always constrained to the bottom of PARENT and that
-                  ;; at least as many pixels of FRAME as specified by
-                  ;; that number are visible on each of the three
-                  ;; remaining sides of PARENT.
-                  (let ((par (frame-parameter frame 'top-visible))
-                        bottom-visible)
-                    (unless par
-                      (setq par (frame-parameter frame 'bottom-visible))
-                      (setq bottom-visible t))
-                    (when (and (numberp par) parent-edges)
-                      (setq left
-                            (max (min (- parent-right par) left)
-                                 (+ (- parent-left width) par)))
-                      (setq top
-                            (if bottom-visible
-                                (min (max top (- parent-top (- height par)))
-                                     (- parent-bottom height))
-                              (min (max top parent-top)
-                                   (- parent-bottom par))))))
-
-                  ;; Use `modify-frame-parameters' since `left' and
-                  ;; `top' may want to move FRAME out of its PARENT.
-                  (modify-frame-parameters
-                   frame
-                   `((left . (+ ,left)) (top . (+ ,top)))))))
-              (setq last-x pos-x)
-              (setq last-y pos-y))))
-         (old-track-mouse track-mouse))
+                     ((and (< right parent-right)
+                           (<= (- parent-right right) snap-width))
+                      ;; Snap when the mouse moved rightward and FRAME's
+                      ;; right edge would end up within `snap-width'
+                      ;; pixels from PARENT's right edge.
+                      (setq snap-x last-x)
+                      (setq left (- parent-right native-width)))
+                     ((and (>= right parent-right)
+                           (<= (- right parent-right) snap-width)
+                           snap-x (<= (- last-x snap-x) snap-width))
+                      ;; Stay snapped when the mouse moved rightward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq left (- parent-right native-width)))
+                     (t
+                      ;; Unsnap when the mouse moved rightward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-x nil)))))
+                  (cond
+                   ((< last-y first-y)
+                    (cond
+                     ((and (> top parent-top)
+                           (<= (- top parent-top) snap-width))
+                      ;; Snap when the mouse moved upward and FRAME's
+                      ;; top edge would end up within `snap-width'
+                      ;; pixels from PARENT's top edge.
+                      (setq snap-y last-y)
+                      (setq top parent-top))
+                     ((and (<= top parent-top)
+                           (<= (- parent-top top) snap-width)
+                           snap-y (<= (- snap-y last-y) snap-width))
+                      ;; Stay snapped when the mouse moved upward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top parent-top))
+                     (t
+                      ;; Unsnap when the mouse moved upward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))
+                   ((> last-y first-y)
+                    (setq bottom (+ top native-height))
+                    (cond
+                     ((and (< bottom parent-bottom)
+                           (<= (- parent-bottom bottom) snap-width))
+                      ;; Snap when the mouse moved downward and FRAME's
+                      ;; bottom edge would end up within `snap-width'
+                      ;; pixels from PARENT's bottom edge.
+                      (setq snap-y last-y)
+                      (setq top (- parent-bottom native-height)))
+                     ((and (>= bottom parent-bottom)
+                           (<= (- bottom parent-bottom) snap-width)
+                           snap-y (<= (- last-y snap-y) snap-width))
+                      ;; Stay snapped when the mouse moved downward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top (- parent-bottom native-height)))
+                     (t
+                      ;; Unsnap when the mouse moved downward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))))
+
+                ;; If requested, constrain FRAME's draggable areas to
+                ;; PARENT's edges.  The `top-visible' parameter should
+                ;; be set when FRAME has a draggable header-line.  If
+                ;; set to a number, it ascertains that the top of FRAME
+                ;; is always constrained to the top of PARENT and that
+                ;; at least as many pixels of FRAME as specified by that
+                ;; number are visible on each of the three remaining
+                ;; sides of PARENT.
+                ;;
+                ;; The `bottom-visible' parameter should be set when
+                ;; FRAME has a draggable mode-line.  If set to a number,
+                ;; it ascertains that the bottom of FRAME is always
+                ;; constrained to the bottom of PARENT and that at least
+                ;; as many pixels of FRAME as specified by that number
+                ;; are visible on each of the three remaining sides of
+                ;; PARENT.
+                (let ((par (frame-parameter frame 'top-visible))
+                      bottom-visible)
+                  (unless par
+                    (setq par (frame-parameter frame 'bottom-visible))
+                    (setq bottom-visible t))
+                  (when (and (numberp par) parent-edges)
+                    (setq left
+                          (max (min (- parent-right par) left)
+                               (+ (- parent-left native-width) par)))
+                    (setq top
+                          (if bottom-visible
+                              (min (max top (- parent-top (- native-height par)))
+                                   (- parent-bottom native-height))
+                            (min (max top parent-top)
+                                 (- parent-bottom par))))))
+
+                ;; Use `modify-frame-parameters' since `left' and `top'
+                ;; may want to move FRAME out of its PARENT.
+                (modify-frame-parameters
+                 frame
+                 `((left . (+ ,left)) (top . (+ ,top))))))))
+	 (old-track-mouse track-mouse))
     ;; Start tracking.  The special value 'dragging' signals the
     ;; display engine to freeze the mouse pointer shape for as long
     ;; as we drag.
@@ -879,49 +936,49 @@ mouse-drag-left-edge
   "Drag left edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'left))
+  (mouse-drag-frame-resize start-event 'left))
 
 (defun mouse-drag-top-left-corner (start-event)
   "Drag top left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-left))
+  (mouse-drag-frame-resize start-event 'top-left))
 
 (defun mouse-drag-top-edge (start-event)
   "Drag top edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top))
+  (mouse-drag-frame-resize start-event 'top))
 
 (defun mouse-drag-top-right-corner (start-event)
   "Drag top right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-right))
+  (mouse-drag-frame-resize start-event 'top-right))
 
 (defun mouse-drag-right-edge (start-event)
   "Drag right edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'right))
+  (mouse-drag-frame-resize start-event 'right))
 
 (defun mouse-drag-bottom-right-corner (start-event)
   "Drag bottom right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-right))
+  (mouse-drag-frame-resize start-event 'bottom-right))
 
 (defun mouse-drag-bottom-edge (start-event)
   "Drag bottom edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom))
+  (mouse-drag-frame-resize start-event 'bottom))
 
 (defun mouse-drag-bottom-left-corner (start-event)
   "Drag bottom left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-left))
+  (mouse-drag-frame-resize start-event 'bottom-left))
 
 (defcustom mouse-select-region-move-to-beginning nil
   "Effect of selecting a region extending backward from double click.
diff --git a/src/dispnew.c b/src/dispnew.c
index 9af1ce259d..2d64d4660a 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -5741,7 +5741,13 @@ do_pending_window_change (bool safe)
 	{
 	  struct frame *f = XFRAME (frame);
 
-	  if (f->new_height != 0 || f->new_width != 0)
+	  if (FRAME_PARENT_FRAME (f))
+	    {
+	      if (f->new_height != 0 || f->new_width != 0)
+		change_frame_size (f, f->new_width, f->new_height,
+				   0, 0, safe, f->new_pixelwise);
+	    }
+	  else if (f->new_height != 0 || f->new_width != 0)
 	    change_frame_size (f, f->new_width, f->new_height,
 			       0, 0, safe, f->new_pixelwise);
 	}

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-30  9:38                                                                                                   ` martin rudalics
@ 2020-01-30 17:21                                                                                                     ` martin rudalics
  2020-01-30 18:15                                                                                                       ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-30 17:21 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 762 bytes --]

 > I've rewritten the mouse code completely, patch attached.  It neither
 > fixes the GTK child frame resizing problem nor the jumping issues in
 > Lucid but should provide better dragging of frames via internal borders
 > and mode-/header-line otherwise.  In particular the drift you mentioned
 > above should be gone now.  Please try it.

The new patch attached now uses different API functions for resizing +
moving frames.  The function is called 'x-set-frame-size-and-position'
and works only under X and GTK.  It makes mouse-dragging X frames about
as smooth as the old GTK code did here (tested with Lucid, Motif and
without toolkit support).  I doubt that it also solves the GTK child
frame resize issue but you could nevertheless give it a try.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mouse+xfns.diff --]
[-- Type: text/x-patch; name="mouse+xfns.diff", Size: 40312 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index e58a2e6da1..155bcc20a3 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -552,7 +552,7 @@ mouse-drag-mode-line
              (not (eq (window-frame minibuffer-window) frame))))
       ;; Drag frame when the window is on the bottom of its frame and
       ;; there is no minibuffer window below.
-      (mouse-drag-frame start-event 'move)))))
+      (mouse-drag-frame-move start-event)))))
 
 (defun mouse-drag-header-line (start-event)
   "Change the height of a window by dragging on its header line.
@@ -569,7 +569,7 @@ mouse-drag-header-line
         (mouse-drag-line start-event 'header)
       (let ((frame (window-frame window)))
         (when (frame-parameter frame 'drag-with-header-line)
-          (mouse-drag-frame start-event 'move))))))
+          (mouse-drag-frame-move start-event))))))
 
 (defun mouse-drag-vertical-line (start-event)
   "Change the width of a window by dragging on a vertical line.
@@ -577,46 +577,7 @@ mouse-drag-vertical-line
   (interactive "e")
   (mouse-drag-line start-event 'vertical))
 \f
-(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move)
-  "Helper function for `mouse-drag-frame'."
-  (let* ((frame-x-y (frame-position frame))
-         (frame-x (car frame-x-y))
-         (frame-y (cdr frame-x-y))
-         alist)
-    (if (> x-diff 0)
-        (when x-move
-          (setq x-diff (min x-diff frame-x))
-          (setq x-move (- frame-x x-diff)))
-      (let* ((min-width (frame-windows-min-size frame t nil t))
-             (min-diff (max 0 (- (frame-inner-width frame) min-width))))
-        (setq x-diff (max x-diff (- min-diff)))
-        (when x-move
-          (setq x-move (+ frame-x (- x-diff))))))
-
-    (if (> y-diff 0)
-        (when y-move
-          (setq y-diff (min y-diff frame-y))
-          (setq y-move (- frame-y y-diff)))
-      (let* ((min-height (frame-windows-min-size frame nil nil t))
-             (min-diff (max 0 (- (frame-inner-height frame) min-height))))
-        (setq y-diff (max y-diff (- min-diff)))
-        (when y-move
-          (setq y-move (+ frame-y (- y-diff))))))
-
-    (unless (zerop x-diff)
-      (when x-move
-        (push `(left . ,x-move) alist))
-      (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff)))
-            alist))
-    (unless (zerop y-diff)
-      (when y-move
-        (push `(top . ,y-move) alist))
-      (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff)))
-            alist))
-    (when alist
-      (modify-frame-parameters frame alist))))
-
-(defun mouse-drag-frame (start-event part)
+(defun mouse-drag-frame-resize (start-event part)
   "Drag a frame or one of its edges with the mouse.
 START-EVENT is the starting mouse event of the drag action.  Its
 position window denotes the frame that will be dragged.
@@ -635,9 +596,168 @@ mouse-drag-frame
          (frame (if (window-live-p window)
                     (window-frame window)
                   window))
-         (width (frame-native-width frame))
-         (height (frame-native-height frame))
-         ;; PARENT is the parent frame of FRAME or, if FRAME is a
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+         (x-left first-left)
+         (first-top (cdr first-pos))
+         (x-top first-top)
+	 (first-width (frame-text-width frame))
+         (x-width first-width)
+	 (first-height (frame-text-height frame))
+         (x-height first-height)
+	 ;; Don't let FRAME become less large than the size needed to
+	 ;; fit all of its windows.
+	 (min-text-width
+	  (+ (frame-windows-min-size frame t nil t)
+	     (- (frame-inner-width frame) first-width)))
+	 (min-text-height
+	  (+ (frame-windows-min-size frame nil nil t)
+	     (- (frame-inner-height frame) first-height)))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
+         ;; top-level frame, FRAME's workarea.
+         (parent (frame-parent frame))
+         (parent-edges
+          (if parent
+              (frame-edges parent)
+            (let* ((attributes
+                    (car (display-monitor-attributes-list)))
+                   (workarea (assq 'workarea attributes)))
+              (and workarea
+                   `(,(nth 1 workarea) ,(nth 2 workarea)
+                     ,(+ (nth 1 workarea) (nth 3 workarea))
+                     ,(+ (nth 2 workarea) (nth 4 workarea)))))))
+         (parent-left (and parent-edges (nth 0 parent-edges)))
+         (parent-top (and parent-edges (nth 1 parent-edges)))
+         (parent-right (and parent-edges (nth 2 parent-edges)))
+         (parent-bottom (and parent-edges (nth 3 parent-edges)))
+	 ;; Drag types.  drag-left/drag-right and drag-top/drag-bottom
+	 ;; are mutually exclusive.
+	 (drag-left (memq part '(bottom-left left top-left)))
+	 (drag-top (memq part '(top-left top top-right)))
+	 (drag-right (memq part '(top-right right bottom-right)))
+	 (drag-bottom (memq part '(bottom-right bottom bottom-left)))
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         (exitfun nil)
+         (move
+          (lambda (event)
+            (interactive "e")
+            (when (consp event)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+		     alist)
+                ;; We never want to warp the mouse position here.  When
+                ;; moving the mouse leftward or upward, then with a wide
+                ;; border the calculated left or top position of the
+                ;; frame could drop to a value less than zero depending
+                ;; on where precisely the mouse within the border.  We
+                ;; guard against this by never allowing the frame to
+                ;; move to a position less than zero here.  No such
+                ;; precautions are used for the right and bottom borders
+                ;; so with a large internal border parts of that border
+                ;; may disappear.
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (progn
+                      (when (and drag-left (>= last-x parent-left)
+                                 (>= (- first-width left) min-text-width))
+		        (setq x-left (max (+ first-left left) 0))
+		        (setq x-width (- first-width left)))
+	              (when (and drag-top (>= last-y parent-top)
+                                 (>= (- first-height top) min-text-height))
+		        (setq x-top (max 0 (+ first-top top)))
+		        (setq x-height (- first-height top)))
+	              (when (and drag-right (<= last-x parent-right)
+                                 (>= (+ first-width left) min-text-width))
+		        (setq x-width (+ first-width left)))
+	              (when (and drag-bottom (<= last-y parent-bottom)
+                                 (>= (+ first-height top) min-text-height))
+		        (setq x-height (+ first-height top)))
+                      (x-set-frame-size-and-position
+                       frame x-width x-height x-left x-top t))
+                  (when (and drag-left (>= last-x parent-left)
+                             (>= (- first-width left) min-text-width))
+		    (push `(left . ,(max (+ first-left left) 0)) alist)
+		    (push `(width . (text-pixels . ,(- first-width left)))
+                          alist))
+	          (when (and drag-top (>= last-y parent-top)
+                             (>= (- first-height top) min-text-height))
+		    (push `(top . ,(max 0 (+ first-top top))) alist)
+		    (push `(height . (text-pixels . ,(- first-height top)))
+                          alist))
+	          (when (and drag-right (<= last-x parent-right)
+                             (>= (+ first-width left) min-text-width))
+		    (push `(width . (text-pixels . ,(+ first-width left)))
+                          alist))
+	          (when (and drag-bottom (<= last-y parent-bottom)
+                             (>= (+ first-height top) min-text-height))
+		    (push `(height . (text-pixels . ,(+ first-height top)))
+                          alist))
+	          (modify-frame-parameters frame alist))))))
+         (old-track-mouse track-mouse))
+    ;; Start tracking.  The special value 'dragging' signals the
+    ;; display engine to freeze the mouse pointer shape for as long
+    ;; as we drag.
+    (setq track-mouse 'dragging)
+    ;; Loop reading events and sampling the position of the mouse.
+    (setq exitfun
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [scroll-bar-movement] #'ignore)
+             (define-key map [mouse-movement] move)
+             ;; Swallow drag-mouse-1 events to avoid selecting some other window.
+             (define-key map [drag-mouse-1]
+               (lambda () (interactive) (funcall exitfun)))
+             ;; Some of the events will of course end up looked up
+             ;; with a mode-line, header-line or vertical-line prefix ...
+             (define-key map [mode-line] map)
+             (define-key map [header-line] map)
+             (define-key map [vertical-line] map)
+             ;; ... and some maybe even with a right- or bottom-divider
+             ;; prefix.
+             (define-key map [right-divider] map)
+             (define-key map [bottom-divider] map)
+             map)
+           t (lambda () (setq track-mouse old-track-mouse))))))
+
+(defun mouse-drag-frame-move (start-event)
+  "Drag a frame or one of its edges with the mouse.
+START-EVENT is the starting mouse event of the drag action.  Its
+position window denotes the frame that will be dragged.
+
+PART specifies the part that has been dragged and must be one of
+the symbols `left', `top', `right', `bottom', `top-left',
+`top-right', `bottom-left', `bottom-right' to drag an internal
+border or edge.  If PART equals `move', this means to move the
+frame with the mouse."
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
+  (let* ((echo-keystrokes 0)
+	 (start (event-start start-event))
+         (window (posn-window start))
+         ;; FRAME is the frame to drag.
+         (frame (if (window-live-p window)
+                    (window-frame window)
+                  window))
+         (native-width (frame-native-width frame))
+         (native-height (frame-native-height frame))
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+	 (first-top (cdr first-pos))
+	 (first-width (frame-text-width frame))
+	 (first-height (frame-text-height frame))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
          ;; top-level frame, FRAME's workarea.
          (parent (frame-parent frame))
          (parent-edges
@@ -654,19 +774,16 @@ mouse-drag-frame
          (parent-top (and parent-edges (nth 1 parent-edges)))
          (parent-right (and parent-edges (nth 2 parent-edges)))
          (parent-bottom (and parent-edges (nth 3 parent-edges)))
-         ;; `pos-x' and `pos-y' record the x- and y-coordinates of the
-	 ;; last sampled mouse position.  Note that we sample absolute
-	 ;; mouse positions to avoid that moving the mouse from one
-	 ;; frame into another gets into our way.  `last-x' and `last-y'
-	 ;; records the x- and y-coordinates of the previously sampled
-	 ;; position.  The differences between `last-x' and `pos-x' as
-	 ;; well as `last-y' and `pos-y' determine the amount the mouse
-	 ;; has been dragged between the last two samples.
-         pos-x-y pos-x pos-y
-         (last-x-y (mouse-absolute-pixel-position))
-         (last-x (car last-x-y))
-         (last-y (cdr last-x-y))
-         ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         ;; `snap-width' (maybe also a yet to be provided `snap-height')
+         ;; could become floats to handle proportionality wrt PARENT.
+         ;; We don't do any checks on this parameter so far.
+         (snap-width (frame-parameter frame 'snap-width))
+	 ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
          ;; mouse position when FRAME snapped.  As soon as the
          ;; difference between `pos-x' and `snap-x' (or `pos-y' and
          ;; `snap-y') exceeds the value of FRAME's `snap-width'
@@ -678,176 +795,144 @@ mouse-drag-frame
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (setq pos-x-y (mouse-absolute-pixel-position))
-              (setq pos-x (car pos-x-y))
-              (setq pos-y (cdr pos-x-y))
-              (cond
-               ((eq part 'left)
-                (mouse-resize-frame frame (- last-x pos-x) 0 t))
-               ((eq part 'top)
-                (mouse-resize-frame frame 0 (- last-y pos-y) nil t))
-               ((eq part 'right)
-                (mouse-resize-frame frame (- pos-x last-x) 0))
-               ((eq part 'bottom)
-                (mouse-resize-frame frame 0 (- pos-y last-y)))
-               ((eq part 'top-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- last-y pos-y) t t))
-               ((eq part 'top-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- last-y pos-y) nil t))
-               ((eq part 'bottom-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- pos-y last-y) t))
-               ((eq part 'bottom-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- pos-y last-y)))
-               ((eq part 'move)
-                (let* ((old-position (frame-position frame))
-                       (old-left (car old-position))
-                       (old-top (cdr old-position))
-                       (left (+ old-left (- pos-x last-x)))
-                       (top (+ old-top (- pos-y last-y)))
-                       right bottom
-                       ;; `snap-width' (maybe also a yet to be provided
-                       ;; `snap-height') could become floats to handle
-                       ;; proportionality wrt PARENT.  We don't do any
-                       ;; checks on this parameter so far.
-                       (snap-width (frame-parameter frame 'snap-width)))
-                  ;; Docking and constraining.
-                  (when (and (numberp snap-width) parent-edges)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+                     right bottom)
+		(setq left (+ first-left left))
+		(setq top (+ first-top top))
+                ;; Docking and constraining.
+                (when (and (numberp snap-width) parent-edges)
+                  (cond
+                   ;; Docking at the left parent edge.
+                   ((< last-x first-x)
                     (cond
-                     ;; Docking at the left parent edge.
-                     ((< pos-x last-x)
-                      (cond
-                       ((and (> left parent-left)
-                             (<= (- left parent-left) snap-width))
-                        ;; Snap when the mouse moved leftward and
-                        ;; FRAME's left edge would end up within
-                        ;; `snap-width' pixels from PARENT's left edge.
-                        (setq snap-x pos-x)
-                        (setq left parent-left))
-                       ((and (<= left parent-left)
-                             (<= (- parent-left left) snap-width)
-                             snap-x (<= (- snap-x pos-x) snap-width))
-                        ;; Stay snapped when the mouse moved leftward
-                        ;; but not more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq left parent-left))
-                       (t
-                        ;; Unsnap when the mouse moved more than
-                        ;; `snap-width' pixels leftward from the time
-                        ;; FRAME snapped.
-                        (setq snap-x nil))))
-                     ((> pos-x last-x)
-                      (setq right (+ left width))
-                      (cond
-                       ((and (< right parent-right)
-                             (<= (- parent-right right) snap-width))
-                        ;; Snap when the mouse moved rightward and
-                        ;; FRAME's right edge would end up within
-                        ;; `snap-width' pixels from PARENT's right edge.
-                        (setq snap-x pos-x)
-                        (setq left (- parent-right width)))
-                       ((and (>= right parent-right)
-                             (<= (- right parent-right) snap-width)
-                             snap-x (<= (- pos-x snap-x) snap-width))
-                        ;; Stay snapped when the mouse moved rightward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq left (- parent-right width)))
-                       (t
-                        ;; Unsnap when the mouse moved rightward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-x nil)))))
-
+                     ((and (> left parent-left)
+                           (<= (- left parent-left) snap-width))
+                      ;; Snap when the mouse moved leftward and FRAME's
+                      ;; left edge would end up within `snap-width'
+                      ;; pixels from PARENT's left edge.
+                      (setq snap-x last-x)
+                      (setq left parent-left))
+                     ((and (<= left parent-left)
+                           (<= (- parent-left left) snap-width)
+                           snap-x (<= (- snap-x last-x) snap-width))
+                      ;; Stay snapped when the mouse moved leftward but
+                      ;; not more than `snap-width' pixels from the time
+                      ;; FRAME snapped.
+                      (setq left parent-left))
+                     (t
+                      ;; Unsnap when the mouse moved more than
+                      ;; `snap-width' pixels leftward from the time
+                      ;; FRAME snapped.
+                      (setq snap-x nil))))
+                   ((> last-x first-x)
+                    (setq right (+ left native-width))
                     (cond
-                     ((< pos-y last-y)
-                      (cond
-                       ((and (> top parent-top)
-                             (<= (- top parent-top) snap-width))
-                        ;; Snap when the mouse moved upward and FRAME's
-                        ;; top edge would end up within `snap-width'
-                        ;; pixels from PARENT's top edge.
-                        (setq snap-y pos-y)
-                        (setq top parent-top))
-                       ((and (<= top parent-top)
-                             (<= (- parent-top top) snap-width)
-                             snap-y (<= (- snap-y pos-y) snap-width))
-                        ;; Stay snapped when the mouse moved upward but
-                        ;; not more more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq top parent-top))
-                       (t
-                        ;; Unsnap when the mouse moved upward more than
-                        ;; `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))
-                     ((> pos-y last-y)
-                      (setq bottom (+ top height))
-                      (cond
-                       ((and (< bottom parent-bottom)
-                             (<= (- parent-bottom bottom) snap-width))
-                        ;; Snap when the mouse moved downward and
-                        ;; FRAME's bottom edge would end up within
-                        ;; `snap-width' pixels from PARENT's bottom
-                        ;; edge.
-                        (setq snap-y pos-y)
-                        (setq top (- parent-bottom height)))
-                       ((and (>= bottom parent-bottom)
-                             (<= (- bottom parent-bottom) snap-width)
-                             snap-y (<= (- pos-y snap-y) snap-width))
-                        ;; Stay snapped when the mouse moved downward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq top (- parent-bottom height)))
-                       (t
-                        ;; Unsnap when the mouse moved downward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))))
-
-                  ;; If requested, constrain FRAME's draggable areas to
-                  ;; PARENT's edges.  The `top-visible' parameter should
-                  ;; be set when FRAME has a draggable header-line.  If
-                  ;; set to a number, it ascertains that the top of
-                  ;; FRAME is always constrained to the top of PARENT
-                  ;; and that at least as many pixels of FRAME as
-                  ;; specified by that number are visible on each of the
-                  ;; three remaining sides of PARENT.
-                  ;;
-                  ;; The `bottom-visible' parameter should be set when
-                  ;; FRAME has a draggable mode-line.  If set to a
-                  ;; number, it ascertains that the bottom of FRAME is
-                  ;; always constrained to the bottom of PARENT and that
-                  ;; at least as many pixels of FRAME as specified by
-                  ;; that number are visible on each of the three
-                  ;; remaining sides of PARENT.
-                  (let ((par (frame-parameter frame 'top-visible))
-                        bottom-visible)
-                    (unless par
-                      (setq par (frame-parameter frame 'bottom-visible))
-                      (setq bottom-visible t))
-                    (when (and (numberp par) parent-edges)
-                      (setq left
-                            (max (min (- parent-right par) left)
-                                 (+ (- parent-left width) par)))
-                      (setq top
-                            (if bottom-visible
-                                (min (max top (- parent-top (- height par)))
-                                     (- parent-bottom height))
-                              (min (max top parent-top)
-                                   (- parent-bottom par))))))
-
-                  ;; Use `modify-frame-parameters' since `left' and
-                  ;; `top' may want to move FRAME out of its PARENT.
-                  (modify-frame-parameters
-                   frame
-                   `((left . (+ ,left)) (top . (+ ,top)))))))
-              (setq last-x pos-x)
-              (setq last-y pos-y))))
-         (old-track-mouse track-mouse))
+                     ((and (< right parent-right)
+                           (<= (- parent-right right) snap-width))
+                      ;; Snap when the mouse moved rightward and FRAME's
+                      ;; right edge would end up within `snap-width'
+                      ;; pixels from PARENT's right edge.
+                      (setq snap-x last-x)
+                      (setq left (- parent-right native-width)))
+                     ((and (>= right parent-right)
+                           (<= (- right parent-right) snap-width)
+                           snap-x (<= (- last-x snap-x) snap-width))
+                      ;; Stay snapped when the mouse moved rightward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq left (- parent-right native-width)))
+                     (t
+                      ;; Unsnap when the mouse moved rightward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-x nil)))))
+                  (cond
+                   ((< last-y first-y)
+                    (cond
+                     ((and (> top parent-top)
+                           (<= (- top parent-top) snap-width))
+                      ;; Snap when the mouse moved upward and FRAME's
+                      ;; top edge would end up within `snap-width'
+                      ;; pixels from PARENT's top edge.
+                      (setq snap-y last-y)
+                      (setq top parent-top))
+                     ((and (<= top parent-top)
+                           (<= (- parent-top top) snap-width)
+                           snap-y (<= (- snap-y last-y) snap-width))
+                      ;; Stay snapped when the mouse moved upward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top parent-top))
+                     (t
+                      ;; Unsnap when the mouse moved upward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))
+                   ((> last-y first-y)
+                    (setq bottom (+ top native-height))
+                    (cond
+                     ((and (< bottom parent-bottom)
+                           (<= (- parent-bottom bottom) snap-width))
+                      ;; Snap when the mouse moved downward and FRAME's
+                      ;; bottom edge would end up within `snap-width'
+                      ;; pixels from PARENT's bottom edge.
+                      (setq snap-y last-y)
+                      (setq top (- parent-bottom native-height)))
+                     ((and (>= bottom parent-bottom)
+                           (<= (- bottom parent-bottom) snap-width)
+                           snap-y (<= (- last-y snap-y) snap-width))
+                      ;; Stay snapped when the mouse moved downward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top (- parent-bottom native-height)))
+                     (t
+                      ;; Unsnap when the mouse moved downward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))))
+
+                ;; If requested, constrain FRAME's draggable areas to
+                ;; PARENT's edges.  The `top-visible' parameter should
+                ;; be set when FRAME has a draggable header-line.  If
+                ;; set to a number, it ascertains that the top of FRAME
+                ;; is always constrained to the top of PARENT and that
+                ;; at least as many pixels of FRAME as specified by that
+                ;; number are visible on each of the three remaining
+                ;; sides of PARENT.
+                ;;
+                ;; The `bottom-visible' parameter should be set when
+                ;; FRAME has a draggable mode-line.  If set to a number,
+                ;; it ascertains that the bottom of FRAME is always
+                ;; constrained to the bottom of PARENT and that at least
+                ;; as many pixels of FRAME as specified by that number
+                ;; are visible on each of the three remaining sides of
+                ;; PARENT.
+                (let ((par (frame-parameter frame 'top-visible))
+                      bottom-visible)
+                  (unless par
+                    (setq par (frame-parameter frame 'bottom-visible))
+                    (setq bottom-visible t))
+                  (when (and (numberp par) parent-edges)
+                    (setq left
+                          (max (min (- parent-right par) left)
+                               (+ (- parent-left native-width) par)))
+                    (setq top
+                          (if bottom-visible
+                              (min (max top (- parent-top (- native-height par)))
+                                   (- parent-bottom native-height))
+                            (min (max top parent-top)
+                                 (- parent-bottom par))))))
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (x-set-frame-size-and-position
+                     frame first-width first-height left top t)
+                  ;; Use `modify-frame-parameters' since `left' and `top'
+                  ;; may want to move FRAME out of its PARENT.
+                  (modify-frame-parameters frame `((left . (+ ,left)) (top . (+ ,top)))))))))
+	 (old-track-mouse track-mouse))
     ;; Start tracking.  The special value 'dragging' signals the
     ;; display engine to freeze the mouse pointer shape for as long
     ;; as we drag.
@@ -879,49 +964,49 @@ mouse-drag-left-edge
   "Drag left edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'left))
+  (mouse-drag-frame-resize start-event 'left))
 
 (defun mouse-drag-top-left-corner (start-event)
   "Drag top left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-left))
+  (mouse-drag-frame-resize start-event 'top-left))
 
 (defun mouse-drag-top-edge (start-event)
   "Drag top edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top))
+  (mouse-drag-frame-resize start-event 'top))
 
 (defun mouse-drag-top-right-corner (start-event)
   "Drag top right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-right))
+  (mouse-drag-frame-resize start-event 'top-right))
 
 (defun mouse-drag-right-edge (start-event)
   "Drag right edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'right))
+  (mouse-drag-frame-resize start-event 'right))
 
 (defun mouse-drag-bottom-right-corner (start-event)
   "Drag bottom right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-right))
+  (mouse-drag-frame-resize start-event 'bottom-right))
 
 (defun mouse-drag-bottom-edge (start-event)
   "Drag bottom edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom))
+  (mouse-drag-frame-resize start-event 'bottom))
 
 (defun mouse-drag-bottom-left-corner (start-event)
   "Drag bottom left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-left))
+  (mouse-drag-frame-resize start-event 'bottom-left))
 
 (defcustom mouse-select-region-move-to-beginning nil
   "Effect of selecting a region extending backward from double click.
diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..2e2a83f2ca 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4203,6 +4203,187 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
  return unbind_to (count, frame);
 }
 
+DEFUN ("x-set-frame-size-and-position", Fx_set_frame_size_and_position,
+       Sx_set_frame_size_and_position, 6, 6, 0,
+       doc: /* Set position of FRAME to (X, Y) and size to (WIDTH, HEIGHT).
+PIXELWISE non-nil means count sizes in pixels instead of columns and
+lines.  */)
+       (Lisp_Object frame, Lisp_Object width, Lisp_Object height,
+	Lisp_Object x, Lisp_Object y, Lisp_Object pixelwise)
+{
+  CHECK_TYPE_RANGED_INTEGER (int, width);
+  CHECK_TYPE_RANGED_INTEGER (int, height);
+  CHECK_TYPE_RANGED_INTEGER (int, x);
+  CHECK_TYPE_RANGED_INTEGER (int, y);
+
+  struct frame *f = decode_live_frame (frame);
+  int unit_width = FRAME_COLUMN_WIDTH (f);
+  int unit_height = FRAME_LINE_HEIGHT (f);
+  int old_pixel_width = FRAME_PIXEL_WIDTH (f);
+  int old_pixel_height = FRAME_PIXEL_HEIGHT (f);
+  int old_cols = FRAME_COLS (f);
+  int old_lines = FRAME_LINES (f);
+  int new_pixel_width = (!NILP (pixelwise)
+			 ? XFIXNUM (width)
+			 : XFIXNUM (width) * unit_width);
+  int new_pixel_height = (!NILP (pixelwise)
+			  ? XFIXNUM (height)
+			  : XFIXNUM (height) * unit_height);
+  struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f));
+  int old_windows_width = WINDOW_PIXEL_WIDTH (r);
+  int old_windows_height
+    = (WINDOW_PIXEL_HEIGHT (r)
+       + ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
+	  ? WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_MINIBUF_WINDOW (f)))
+	  : 0));
+  int new_windows_width, new_windows_height;
+  int new_text_width, new_text_height, new_cols, new_lines;
+
+  XSETFRAME (frame, f);
+
+  frame_size_history_add
+    (f, Qx_set_frame_size_and_position_1, new_pixel_width, new_pixel_height, Qnil);
+
+  new_windows_width = new_pixel_width - 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
+  new_windows_height = (new_pixel_height
+			- FRAME_TOP_MARGIN_HEIGHT (f)
+			- 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
+
+  new_text_width = FRAME_PIXEL_TO_TEXT_WIDTH (f, new_pixel_width);
+  new_text_height = FRAME_PIXEL_TO_TEXT_HEIGHT (f, new_pixel_height);
+  new_cols = new_text_width / unit_width;
+  new_lines = new_text_height / unit_height;
+
+  block_input ();
+  if (FRAME_WINDOW_P (f) && f->can_set_window_size)
+    {
+#ifdef USE_GTK
+      GdkWindow *window = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+
+      x_wm_set_size_hint (f, 0, 1);
+      gdk_window_move_resize (window, XFIXNUM (x), XFIXNUM (y),
+			      new_pixel_width, new_pixel_height);
+      SET_FRAME_GARBAGED (f);
+      cancel_mouse_face (f);
+
+      if (FRAME_VISIBLE_P (f))
+	{
+	  /* Must call this to flush out events */
+	  (void)gtk_events_pending ();
+	  gdk_flush ();
+	  x_wait_for_event (f, ConfigureNotify);
+	}
+      else
+	{
+	  change_frame_size (f, new_pixel_width, new_pixel_height,
+			     false, true, false, true);
+	  x_sync (f);
+	}
+#else
+      f->win_gravity = NorthWestGravity;
+      x_wm_set_size_hint (f, 0, true);
+
+      XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+			 XFIXNUM (x), XFIXNUM (y), new_pixel_width,
+			 new_pixel_height + FRAME_MENUBAR_HEIGHT (f));
+
+      SET_FRAME_GARBAGED (f);
+
+      if (FRAME_VISIBLE_P (f))
+	x_wait_for_event (f, ConfigureNotify);
+      else
+	{
+	  change_frame_size (f,new_pixel_width, new_pixel_height,
+			     false, true, false, true);
+	  x_sync (f);
+	}
+
+      x_clear_under_internal_border (f);
+#endif
+
+      mark_window_cursors_off (XWINDOW (f->root_window));
+
+      cancel_mouse_face (f);
+
+      unblock_input ();
+
+      do_pending_window_change (false);
+
+    }
+
+  f->resized_p = true;
+
+  block_input ();
+  if (new_windows_width != old_windows_width)
+    {
+      resize_frame_windows (f, new_windows_width, true);
+      if (WINDOWP (f->tab_bar_window))
+	{
+	  XWINDOW (f->tab_bar_window)->pixel_width = new_windows_width;
+	  XWINDOW (f->tab_bar_window)->total_cols
+	    = new_windows_width / unit_width;
+	}
+
+#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
+      if (WINDOWP (f->tool_bar_window))
+	{
+	  XWINDOW (f->tool_bar_window)->pixel_width = new_windows_width;
+	  XWINDOW (f->tool_bar_window)->total_cols
+	    = new_windows_width / unit_width;
+	}
+#endif
+    }
+  else if (new_cols != old_cols)
+    call2 (Qwindow__pixel_to_total, frame, Qt);
+
+  if (new_windows_height != old_windows_height
+      || WINDOW_TOP_PIXEL_EDGE (r) != FRAME_TOP_MARGIN_HEIGHT (f))
+    resize_frame_windows (f, new_windows_height, false);
+  else if (new_lines != old_lines)
+    call2 (Qwindow__pixel_to_total, frame, Qnil);
+
+  frame_size_history_add
+    (f, Qx_set_frame_size_and_position_3, new_text_width, new_text_height, Qnil);
+
+  /* Assign new sizes.  */
+  FRAME_TEXT_WIDTH (f) = new_text_width;
+  FRAME_TEXT_HEIGHT (f) = new_text_height;
+  FRAME_PIXEL_WIDTH (f) = new_pixel_width;
+  FRAME_PIXEL_HEIGHT (f) = new_pixel_height;
+  SET_FRAME_COLS (f, new_cols);
+  SET_FRAME_LINES (f, new_lines);
+  SET_FRAME_COLS (f, new_cols);
+  SET_FRAME_LINES (f, new_lines);
+
+  {
+    struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+    int text_area_x, text_area_y, text_area_width, text_area_height;
+
+    window_box (w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width,
+		&text_area_height);
+    if (w->cursor.x >= text_area_x + text_area_width)
+      w->cursor.hpos = w->cursor.x = 0;
+    if (w->cursor.y >= text_area_y + text_area_height)
+      w->cursor.vpos = w->cursor.y = 0;
+  }
+
+  /* Sanitize window sizes.  */
+  sanitize_window_sizes (Qt);
+  sanitize_window_sizes (Qnil);
+
+  adjust_frame_glyphs (f);
+  calculate_costs (f);
+  SET_FRAME_GARBAGED (f);
+
+  /* A frame was "resized" if one of its pixelsizes changed, even if its
+     X window wasn't resized at all.  */
+  f->resized_p = (new_pixel_width != old_pixel_width
+		  || new_pixel_height != old_pixel_height);
+
+  unblock_input ();
+
+  return Qnil;
+}
 \f
 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
        doc: /* Internal function called by `color-defined-p'.
@@ -7810,6 +7991,9 @@ syms_of_xfns (void)
   DEFSYM (Qfont_parameter, "font-parameter");
   DEFSYM (Qmono, "mono");
   DEFSYM (Qassq_delete_all, "assq-delete-all");
+  DEFSYM (Qx_set_frame_size_and_position_1, "x-set-frame-size-and-position-1");
+  DEFSYM (Qx_set_frame_size_and_position_2, "x-set-frame-size-and-position-2");
+  DEFSYM (Qx_set_frame_size_and_position_3, "x-set-frame-size-and-position-3");
 
 #ifdef USE_CAIRO
   DEFSYM (Qpdf, "pdf");
@@ -8065,6 +8249,7 @@ syms_of_xfns (void)
   defsubr (&Sx_set_mouse_absolute_pixel_position);
   defsubr (&Sx_wm_set_size_hint);
   defsubr (&Sx_create_frame);
+  defsubr (&Sx_set_frame_size_and_position);
   defsubr (&Sx_open_connection);
   defsubr (&Sx_close_connection);
   defsubr (&Sx_display_list);

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-30  9:38                                                                                                 ` martin rudalics
@ 2020-01-30 17:32                                                                                                   ` Dmitry Gutov
  2020-01-30 18:04                                                                                                     ` martin rudalics
  2020-01-30 17:42                                                                                                   ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-30 17:32 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1405 bytes --]

On 30.01.2020 12:38, martin rudalics wrote:
>  >> Can you enable the 'frame-size-history' here?  The ingredient would 
> be a
>  >> gtk build with xterm.diff applied loading the old resize child frame
>  >> code.  Then eval
>  >>
>  >> (progn
>  >>    (setq frame-size-history '(100))
>  >>    (resize-test test-frame)
>  >>    (frame--size-history test-frame)
>  >>    (display-buffer "*frame-size-history*"))
>  >>
>  >> and post the result.
>  >
>  > Here you go. It's a little different, but not by much. :-(
>  >
>  > Frame size history of #<frame test child-frame 0x55a43258efd0>
>  > adjust-frame-size-1     (720 360 720 720) (height 1)
>  > adjust-frame-size-2     (720 360 720 720) (nil nil)
>  > x-set-window-size-3     (720 360 720 720) (768 720 0)
> 
> I suppose it does nothing because it cannot get a top frame.  If you put
> a breakpoint within 'set-frame-height' run the usual 'resize-test' and
> when that breakpoint is hit set a breakpoint at

Before I do that... there's something I failed to notice before: the 
frame *does* get resized, in a sense. At least X seems to think so, but 
Emacs doesn't.

Notice the white area of the same height as the child frame hiding the 
text in the parent frame on the attached screenshot. Also note that the 
yellow background didn't help: the area is white.

This only happens with xterm.diff applied, never without it.

[-- Attachment #2: Screenshot from 2020-01-30 20-23-35.png --]
[-- Type: image/png, Size: 138857 bytes --]

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-30  9:38                                                                                                 ` martin rudalics
  2020-01-30 17:32                                                                                                   ` Dmitry Gutov
@ 2020-01-30 17:42                                                                                                   ` Dmitry Gutov
  2020-01-30 18:04                                                                                                     ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-30 17:42 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 30.01.2020 12:38, martin rudalics wrote:
> If you put
> a breakpoint within 'set-frame-height' run the usual 'resize-test' and
> when that breakpoint is hit set a breakpoint at
> 
>        f = x_top_window_to_frame (dpyinfo, 
> configureEvent.xconfigure.window);
> 
> around line 8927 in xterm.c and do "n" after that breakpoint is hit,
> what do you get if you do p f now?

So. Putting a breakpoint on that line gives me:

Thread 1 "emacs" hit Breakpoint 4, handle_one_xevent 
(dpyinfo=0x555555fc5000,
     event=0x7fffffffcbb0, finish=0x555555b9df30 <current_finish>, 
hold_quit=0x7fffffffce30)
     at xterm.c:8923
8923	      f = x_top_window_to_frame (dpyinfo, 
configureEvent.xconfigure.window);
(gdb) p f
$1 = (struct frame *) 0x0
(gdb) print
$2 = (struct frame *) 0x0
(gdb) xframe
$3 = (struct frame *) 0x0
Cannot access memory at address 0x8

but that probably makes sense, since the var has not been assigned yet.

Putting a breakpoint at the next statement gives me this:

Thread 1 "emacs" hit Breakpoint 5, handle_one_xevent 
(dpyinfo=0x555555fc5000,
     event=<optimized out>, finish=0x555555b9df30 <current_finish>, 
hold_quit=0x7fffffffce30)
     at xterm.c:8929
8929	      block_input ();
(gdb) p f
$4 = (struct frame *) 0x5555560a5aa0
(gdb) xframe
$5 = (struct frame *) 0x5555560a5aa0
"test child-frame"



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-30 17:32                                                                                                   ` Dmitry Gutov
@ 2020-01-30 18:04                                                                                                     ` martin rudalics
  0 siblings, 0 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-30 18:04 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > Before I do that... there's something I failed to notice before: the
 > frame *does* get resized, in a sense. At least X seems to think so,
 > but Emacs doesn't.

In a sense, yes.

 > Notice the white area of the same height as the child frame hiding the
 > text in the parent frame on the attached screenshot. Also note that
 > the yellow background didn't help: the area is white.

The yellow background allows to discern what Emacs thinks about the
child frame (yellow) from what it should think (white).  Whether that
white area was cleared by the WM or by Emacs itself is not clear to me.
It should have been Emacs because well, why should the WM clear it?

 > This only happens with xterm.diff applied, never without it.

It's similar to the old behavior of X where I also saw those cleared
areas.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-30 17:42                                                                                                   ` Dmitry Gutov
@ 2020-01-30 18:04                                                                                                     ` martin rudalics
  0 siblings, 0 replies; 196+ messages in thread
From: martin rudalics @ 2020-01-30 18:04 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> around line 8927 in xterm.c and do "n" after that breakpoint is hit,
 >> what do you get if you do p f now?
 >
 > So. Putting a breakpoint on that line gives me:
 >
 > Thread 1 "emacs" hit Breakpoint 4, handle_one_xevent (dpyinfo=0x555555fc5000,
 >      event=0x7fffffffcbb0, finish=0x555555b9df30 <current_finish>, hold_quit=0x7fffffffce30)
 >      at xterm.c:8923
 > 8923          f = x_top_window_to_frame (dpyinfo, configureEvent.xconfigure.window);
 > (gdb) p f
 > $1 = (struct frame *) 0x0
 > (gdb) print
 > $2 = (struct frame *) 0x0
 > (gdb) xframe
 > $3 = (struct frame *) 0x0
 > Cannot access memory at address 0x8
 >
 > but that probably makes sense, since the var has not been assigned yet.

That's why I said to do "n" after that breakpoint is hit ;-)

 > Putting a breakpoint at the next statement gives me this:
 >
 > Thread 1 "emacs" hit Breakpoint 5, handle_one_xevent (dpyinfo=0x555555fc5000,
 >      event=<optimized out>, finish=0x555555b9df30 <current_finish>, hold_quit=0x7fffffffce30)
 >      at xterm.c:8929
 > 8929          block_input ();
 > (gdb) p f
 > $4 = (struct frame *) 0x5555560a5aa0
 > (gdb) xframe
 > $5 = (struct frame *) 0x5555560a5aa0
 > "test child-frame"

OK.  But no resizing after that ...

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-30 17:21                                                                                                     ` martin rudalics
@ 2020-01-30 18:15                                                                                                       ` Dmitry Gutov
  2020-01-30 18:41                                                                                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-30 18:15 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 30.01.2020 20:21, martin rudalics wrote:
> The new patch attached now uses different API functions for resizing +
> moving frames.  The function is called 'x-set-frame-size-and-position'
> and works only under X and GTK.  It makes mouse-dragging X frames about
> as smooth as the old GTK code did here (tested with Lucid, Motif and
> without toolkit support).  I doubt that it also solves the GTK child
> frame resize issue but you could nevertheless give it a try.

I've tried both patches now.

mouse.el.diff seems to solve the undecorated frame resizing problem. No 
drift anymore, both with and without frame-resize-pixelwise. So brief 
testing showed that it's okay now.

mouse+xfns.diff, on the other hand, is more broken. First of all, it 
didn't help resizing child frames (not discernible difference). Second, 
it's very broken with desktop scaling (my 200% makes dragging the frame 
behave very wildly). Without scaling it almost works as well as the 
other patch, but not quite. For instance, when mouse dragging by the 
bottom-right corner, at first the corner jumps a little away from the 
cursor in the top-left direction, and then follows it, more or less 
correctly, from that distance.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-30 18:15                                                                                                       ` Dmitry Gutov
@ 2020-01-30 18:41                                                                                                         ` martin rudalics
  2020-01-31  1:22                                                                                                           ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-30 18:41 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > mouse.el.diff seems to solve the undecorated frame resizing
 > problem. No drift anymore, both with and without
 > frame-resize-pixelwise. So brief testing showed that it's okay now.

OK.  With an undecorated top-level frame, I presume.

 > mouse+xfns.diff, on the other hand, is more broken. First of all, it
 > didn't help resizing child frames (not discernible
 > difference).

With GTK you mean.

 > Second, it's very broken with desktop scaling (my 200%
 > makes dragging the frame behave very wildly). Without scaling it
 > almost works as well as the other patch, but not quite. For instance,
 > when mouse dragging by the bottom-right corner, at first the corner
 > jumps a little away from the cursor in the top-left direction, and
 > then follows it, more or less correctly, from that distance.

I didn't care about the scaling factors.  The most important aspect of
the second patch is that it should solve the X issue with slow child
frame resizing and moving (at least it does so here).  So you would have
to try it with a Lucid child frame, unscaled first.  I'll try to fix the
scaling issues later.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-30 18:41                                                                                                         ` martin rudalics
@ 2020-01-31  1:22                                                                                                           ` Dmitry Gutov
  2020-01-31  9:29                                                                                                             ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-31  1:22 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 30.01.2020 21:41, martin rudalics wrote:
>  > mouse.el.diff seems to solve the undecorated frame resizing
>  > problem. No drift anymore, both with and without
>  > frame-resize-pixelwise. So brief testing showed that it's okay now.
> 
> OK.  With an undecorated top-level frame, I presume.

Yup.

>  > mouse+xfns.diff, on the other hand, is more broken. First of all, it
>  > didn't help resizing child frames (not discernible
>  > difference).
> 
> With GTK you mean.

Yes.

>  > Second, it's very broken with desktop scaling (my 200%
>  > makes dragging the frame behave very wildly). Without scaling it
>  > almost works as well as the other patch, but not quite. For instance,
>  > when mouse dragging by the bottom-right corner, at first the corner
>  > jumps a little away from the cursor in the top-left direction, and
>  > then follows it, more or less correctly, from that distance.
> 
> I didn't care about the scaling factors.  The most important aspect of
> the second patch is that it should solve the X issue with slow child
> frame resizing and moving (at least it does so here).  So you would have
> to try it with a Lucid child frame, unscaled first.  I'll try to fix the
> scaling issues later.

Okay, but actually the Lucid build doesn't have that problem with the 
scaled desktop. It "just works", or seems to. So I'm testing it with 
200% scaling.

So, Lucid build, under Mutter:

- Resizing works, more or less. Moving a frame by its mode-line works as 
well without stutters.
- The right-bottom corner still jumps away. When I drag the frame by the 
mode-line, it (the corner) also jumps at first, the same distance.
- Same with moving or resizing a child frame.
- tumashu's child frame moving test scenario is still slow.

E.g.

   (benchmark 1 `(set-frame-position ,test-frame 50 50))
   => 0.5s



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-31  1:22                                                                                                           ` Dmitry Gutov
@ 2020-01-31  9:29                                                                                                             ` martin rudalics
  2020-01-31 11:52                                                                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-31  9:29 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 775 bytes --]

 > So, Lucid build, under Mutter:
 >
 > - Resizing works, more or less. Moving a frame by its mode-line works as well without stutters.
 > - The right-bottom corner still jumps away. When I drag the frame by the mode-line, it (the corner) also jumps at first, the same distance.
 > - Same with moving or resizing a child frame.

I reworked the code as attached.  This includes scaling support and the
jump away issue.  GTK resizing will probably still fail, the rest should
work now.

 > - tumashu's child frame moving test scenario is still slow.
 >
 > E.g.
 >
 >    (benchmark 1 `(set-frame-position ,test-frame 50 50))
 >    => 0.5s

Nothing changed in this regard.  But here

(benchmark 1 `(x-set-frame-size-and-position ,test-frame nil nil 50 50))

=> 0.100523s

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mouse+xfns.diff --]
[-- Type: text/x-patch; name="mouse+xfns.diff", Size: 40975 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index e58a2e6da1..9a0e2b28e4 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -552,7 +552,7 @@ mouse-drag-mode-line
              (not (eq (window-frame minibuffer-window) frame))))
       ;; Drag frame when the window is on the bottom of its frame and
       ;; there is no minibuffer window below.
-      (mouse-drag-frame start-event 'move)))))
+      (mouse-drag-frame-move start-event)))))
 
 (defun mouse-drag-header-line (start-event)
   "Change the height of a window by dragging on its header line.
@@ -569,7 +569,7 @@ mouse-drag-header-line
         (mouse-drag-line start-event 'header)
       (let ((frame (window-frame window)))
         (when (frame-parameter frame 'drag-with-header-line)
-          (mouse-drag-frame start-event 'move))))))
+          (mouse-drag-frame-move start-event))))))
 
 (defun mouse-drag-vertical-line (start-event)
   "Change the width of a window by dragging on a vertical line.
@@ -577,46 +577,7 @@ mouse-drag-vertical-line
   (interactive "e")
   (mouse-drag-line start-event 'vertical))
 \f
-(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move)
-  "Helper function for `mouse-drag-frame'."
-  (let* ((frame-x-y (frame-position frame))
-         (frame-x (car frame-x-y))
-         (frame-y (cdr frame-x-y))
-         alist)
-    (if (> x-diff 0)
-        (when x-move
-          (setq x-diff (min x-diff frame-x))
-          (setq x-move (- frame-x x-diff)))
-      (let* ((min-width (frame-windows-min-size frame t nil t))
-             (min-diff (max 0 (- (frame-inner-width frame) min-width))))
-        (setq x-diff (max x-diff (- min-diff)))
-        (when x-move
-          (setq x-move (+ frame-x (- x-diff))))))
-
-    (if (> y-diff 0)
-        (when y-move
-          (setq y-diff (min y-diff frame-y))
-          (setq y-move (- frame-y y-diff)))
-      (let* ((min-height (frame-windows-min-size frame nil nil t))
-             (min-diff (max 0 (- (frame-inner-height frame) min-height))))
-        (setq y-diff (max y-diff (- min-diff)))
-        (when y-move
-          (setq y-move (+ frame-y (- y-diff))))))
-
-    (unless (zerop x-diff)
-      (when x-move
-        (push `(left . ,x-move) alist))
-      (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff)))
-            alist))
-    (unless (zerop y-diff)
-      (when y-move
-        (push `(top . ,y-move) alist))
-      (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff)))
-            alist))
-    (when alist
-      (modify-frame-parameters frame alist))))
-
-(defun mouse-drag-frame (start-event part)
+(defun mouse-drag-frame-resize (start-event part)
   "Drag a frame or one of its edges with the mouse.
 START-EVENT is the starting mouse event of the drag action.  Its
 position window denotes the frame that will be dragged.
@@ -635,9 +596,168 @@ mouse-drag-frame
          (frame (if (window-live-p window)
                     (window-frame window)
                   window))
-         (width (frame-native-width frame))
-         (height (frame-native-height frame))
-         ;; PARENT is the parent frame of FRAME or, if FRAME is a
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+         (x-left first-left)
+         (first-top (cdr first-pos))
+         (x-top first-top)
+	 (first-width (frame-text-width frame))
+         (x-width first-width)
+	 (first-height (frame-text-height frame))
+         (x-height first-height)
+	 ;; Don't let FRAME become less large than the size needed to
+	 ;; fit all of its windows.
+	 (min-text-width
+	  (+ (frame-windows-min-size frame t nil t)
+	     (- (frame-inner-width frame) first-width)))
+	 (min-text-height
+	  (+ (frame-windows-min-size frame nil nil t)
+	     (- (frame-inner-height frame) first-height)))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
+         ;; top-level frame, FRAME's workarea.
+         (parent (frame-parent frame))
+         (parent-edges
+          (if parent
+              (frame-edges parent)
+            (let* ((attributes
+                    (car (display-monitor-attributes-list)))
+                   (workarea (assq 'workarea attributes)))
+              (and workarea
+                   `(,(nth 1 workarea) ,(nth 2 workarea)
+                     ,(+ (nth 1 workarea) (nth 3 workarea))
+                     ,(+ (nth 2 workarea) (nth 4 workarea)))))))
+         (parent-left (and parent-edges (nth 0 parent-edges)))
+         (parent-top (and parent-edges (nth 1 parent-edges)))
+         (parent-right (and parent-edges (nth 2 parent-edges)))
+         (parent-bottom (and parent-edges (nth 3 parent-edges)))
+	 ;; Drag types.  drag-left/drag-right and drag-top/drag-bottom
+	 ;; are mutually exclusive.
+	 (drag-left (memq part '(bottom-left left top-left)))
+	 (drag-top (memq part '(top-left top top-right)))
+	 (drag-right (memq part '(top-right right bottom-right)))
+	 (drag-bottom (memq part '(bottom-right bottom bottom-left)))
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         (exitfun nil)
+         (move
+          (lambda (event)
+            (interactive "e")
+            (when (consp event)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+		     alist)
+                ;; We never want to warp the mouse position here.  When
+                ;; moving the mouse leftward or upward, then with a wide
+                ;; border the calculated left or top position of the
+                ;; frame could drop to a value less than zero depending
+                ;; on where precisely the mouse within the border.  We
+                ;; guard against this by never allowing the frame to
+                ;; move to a position less than zero here.  No such
+                ;; precautions are used for the right and bottom borders
+                ;; so with a large internal border parts of that border
+                ;; may disappear.
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (progn
+                      (when (and drag-left (>= last-x parent-left)
+                                 (>= (- first-width left) min-text-width))
+		        (setq x-left (max (+ first-left left) 0))
+		        (setq x-width (- first-width left)))
+	              (when (and drag-top (>= last-y parent-top)
+                                 (>= (- first-height top) min-text-height))
+		        (setq x-top (max 0 (+ first-top top)))
+		        (setq x-height (- first-height top)))
+	              (when (and drag-right (<= last-x parent-right)
+                                 (>= (+ first-width left) min-text-width))
+		        (setq x-width (+ first-width left)))
+	              (when (and drag-bottom (<= last-y parent-bottom)
+                                 (>= (+ first-height top) min-text-height))
+		        (setq x-height (+ first-height top)))
+                      (x-set-frame-size-and-position
+                       frame x-width x-height x-left x-top))
+                  (when (and drag-left (>= last-x parent-left)
+                             (>= (- first-width left) min-text-width))
+		    (push `(left . ,(max (+ first-left left) 0)) alist)
+		    (push `(width . (text-pixels . ,(- first-width left)))
+                          alist))
+	          (when (and drag-top (>= last-y parent-top)
+                             (>= (- first-height top) min-text-height))
+		    (push `(top . ,(max 0 (+ first-top top))) alist)
+		    (push `(height . (text-pixels . ,(- first-height top)))
+                          alist))
+	          (when (and drag-right (<= last-x parent-right)
+                             (>= (+ first-width left) min-text-width))
+		    (push `(width . (text-pixels . ,(+ first-width left)))
+                          alist))
+	          (when (and drag-bottom (<= last-y parent-bottom)
+                             (>= (+ first-height top) min-text-height))
+		    (push `(height . (text-pixels . ,(+ first-height top)))
+                          alist))
+	          (modify-frame-parameters frame alist))))))
+         (old-track-mouse track-mouse))
+    ;; Start tracking.  The special value 'dragging' signals the
+    ;; display engine to freeze the mouse pointer shape for as long
+    ;; as we drag.
+    (setq track-mouse 'dragging)
+    ;; Loop reading events and sampling the position of the mouse.
+    (setq exitfun
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [scroll-bar-movement] #'ignore)
+             (define-key map [mouse-movement] move)
+             ;; Swallow drag-mouse-1 events to avoid selecting some other window.
+             (define-key map [drag-mouse-1]
+               (lambda () (interactive) (funcall exitfun)))
+             ;; Some of the events will of course end up looked up
+             ;; with a mode-line, header-line or vertical-line prefix ...
+             (define-key map [mode-line] map)
+             (define-key map [header-line] map)
+             (define-key map [vertical-line] map)
+             ;; ... and some maybe even with a right- or bottom-divider
+             ;; prefix.
+             (define-key map [right-divider] map)
+             (define-key map [bottom-divider] map)
+             map)
+           t (lambda () (setq track-mouse old-track-mouse))))))
+
+(defun mouse-drag-frame-move (start-event)
+  "Drag a frame or one of its edges with the mouse.
+START-EVENT is the starting mouse event of the drag action.  Its
+position window denotes the frame that will be dragged.
+
+PART specifies the part that has been dragged and must be one of
+the symbols `left', `top', `right', `bottom', `top-left',
+`top-right', `bottom-left', `bottom-right' to drag an internal
+border or edge.  If PART equals `move', this means to move the
+frame with the mouse."
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
+  (let* ((echo-keystrokes 0)
+	 (start (event-start start-event))
+         (window (posn-window start))
+         ;; FRAME is the frame to drag.
+         (frame (if (window-live-p window)
+                    (window-frame window)
+                  window))
+         (native-width (frame-native-width frame))
+         (native-height (frame-native-height frame))
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+	 (first-top (cdr first-pos))
+	 (first-width (frame-text-width frame))
+	 (first-height (frame-text-height frame))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
          ;; top-level frame, FRAME's workarea.
          (parent (frame-parent frame))
          (parent-edges
@@ -654,19 +774,16 @@ mouse-drag-frame
          (parent-top (and parent-edges (nth 1 parent-edges)))
          (parent-right (and parent-edges (nth 2 parent-edges)))
          (parent-bottom (and parent-edges (nth 3 parent-edges)))
-         ;; `pos-x' and `pos-y' record the x- and y-coordinates of the
-	 ;; last sampled mouse position.  Note that we sample absolute
-	 ;; mouse positions to avoid that moving the mouse from one
-	 ;; frame into another gets into our way.  `last-x' and `last-y'
-	 ;; records the x- and y-coordinates of the previously sampled
-	 ;; position.  The differences between `last-x' and `pos-x' as
-	 ;; well as `last-y' and `pos-y' determine the amount the mouse
-	 ;; has been dragged between the last two samples.
-         pos-x-y pos-x pos-y
-         (last-x-y (mouse-absolute-pixel-position))
-         (last-x (car last-x-y))
-         (last-y (cdr last-x-y))
-         ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         ;; `snap-width' (maybe also a yet to be provided `snap-height')
+         ;; could become floats to handle proportionality wrt PARENT.
+         ;; We don't do any checks on this parameter so far.
+         (snap-width (frame-parameter frame 'snap-width))
+	 ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
          ;; mouse position when FRAME snapped.  As soon as the
          ;; difference between `pos-x' and `snap-x' (or `pos-y' and
          ;; `snap-y') exceeds the value of FRAME's `snap-width'
@@ -678,176 +795,144 @@ mouse-drag-frame
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (setq pos-x-y (mouse-absolute-pixel-position))
-              (setq pos-x (car pos-x-y))
-              (setq pos-y (cdr pos-x-y))
-              (cond
-               ((eq part 'left)
-                (mouse-resize-frame frame (- last-x pos-x) 0 t))
-               ((eq part 'top)
-                (mouse-resize-frame frame 0 (- last-y pos-y) nil t))
-               ((eq part 'right)
-                (mouse-resize-frame frame (- pos-x last-x) 0))
-               ((eq part 'bottom)
-                (mouse-resize-frame frame 0 (- pos-y last-y)))
-               ((eq part 'top-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- last-y pos-y) t t))
-               ((eq part 'top-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- last-y pos-y) nil t))
-               ((eq part 'bottom-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- pos-y last-y) t))
-               ((eq part 'bottom-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- pos-y last-y)))
-               ((eq part 'move)
-                (let* ((old-position (frame-position frame))
-                       (old-left (car old-position))
-                       (old-top (cdr old-position))
-                       (left (+ old-left (- pos-x last-x)))
-                       (top (+ old-top (- pos-y last-y)))
-                       right bottom
-                       ;; `snap-width' (maybe also a yet to be provided
-                       ;; `snap-height') could become floats to handle
-                       ;; proportionality wrt PARENT.  We don't do any
-                       ;; checks on this parameter so far.
-                       (snap-width (frame-parameter frame 'snap-width)))
-                  ;; Docking and constraining.
-                  (when (and (numberp snap-width) parent-edges)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+                     right bottom)
+		(setq left (+ first-left left))
+		(setq top (+ first-top top))
+                ;; Docking and constraining.
+                (when (and (numberp snap-width) parent-edges)
+                  (cond
+                   ;; Docking at the left parent edge.
+                   ((< last-x first-x)
                     (cond
-                     ;; Docking at the left parent edge.
-                     ((< pos-x last-x)
-                      (cond
-                       ((and (> left parent-left)
-                             (<= (- left parent-left) snap-width))
-                        ;; Snap when the mouse moved leftward and
-                        ;; FRAME's left edge would end up within
-                        ;; `snap-width' pixels from PARENT's left edge.
-                        (setq snap-x pos-x)
-                        (setq left parent-left))
-                       ((and (<= left parent-left)
-                             (<= (- parent-left left) snap-width)
-                             snap-x (<= (- snap-x pos-x) snap-width))
-                        ;; Stay snapped when the mouse moved leftward
-                        ;; but not more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq left parent-left))
-                       (t
-                        ;; Unsnap when the mouse moved more than
-                        ;; `snap-width' pixels leftward from the time
-                        ;; FRAME snapped.
-                        (setq snap-x nil))))
-                     ((> pos-x last-x)
-                      (setq right (+ left width))
-                      (cond
-                       ((and (< right parent-right)
-                             (<= (- parent-right right) snap-width))
-                        ;; Snap when the mouse moved rightward and
-                        ;; FRAME's right edge would end up within
-                        ;; `snap-width' pixels from PARENT's right edge.
-                        (setq snap-x pos-x)
-                        (setq left (- parent-right width)))
-                       ((and (>= right parent-right)
-                             (<= (- right parent-right) snap-width)
-                             snap-x (<= (- pos-x snap-x) snap-width))
-                        ;; Stay snapped when the mouse moved rightward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq left (- parent-right width)))
-                       (t
-                        ;; Unsnap when the mouse moved rightward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-x nil)))))
-
+                     ((and (> left parent-left)
+                           (<= (- left parent-left) snap-width))
+                      ;; Snap when the mouse moved leftward and FRAME's
+                      ;; left edge would end up within `snap-width'
+                      ;; pixels from PARENT's left edge.
+                      (setq snap-x last-x)
+                      (setq left parent-left))
+                     ((and (<= left parent-left)
+                           (<= (- parent-left left) snap-width)
+                           snap-x (<= (- snap-x last-x) snap-width))
+                      ;; Stay snapped when the mouse moved leftward but
+                      ;; not more than `snap-width' pixels from the time
+                      ;; FRAME snapped.
+                      (setq left parent-left))
+                     (t
+                      ;; Unsnap when the mouse moved more than
+                      ;; `snap-width' pixels leftward from the time
+                      ;; FRAME snapped.
+                      (setq snap-x nil))))
+                   ((> last-x first-x)
+                    (setq right (+ left native-width))
                     (cond
-                     ((< pos-y last-y)
-                      (cond
-                       ((and (> top parent-top)
-                             (<= (- top parent-top) snap-width))
-                        ;; Snap when the mouse moved upward and FRAME's
-                        ;; top edge would end up within `snap-width'
-                        ;; pixels from PARENT's top edge.
-                        (setq snap-y pos-y)
-                        (setq top parent-top))
-                       ((and (<= top parent-top)
-                             (<= (- parent-top top) snap-width)
-                             snap-y (<= (- snap-y pos-y) snap-width))
-                        ;; Stay snapped when the mouse moved upward but
-                        ;; not more more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq top parent-top))
-                       (t
-                        ;; Unsnap when the mouse moved upward more than
-                        ;; `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))
-                     ((> pos-y last-y)
-                      (setq bottom (+ top height))
-                      (cond
-                       ((and (< bottom parent-bottom)
-                             (<= (- parent-bottom bottom) snap-width))
-                        ;; Snap when the mouse moved downward and
-                        ;; FRAME's bottom edge would end up within
-                        ;; `snap-width' pixels from PARENT's bottom
-                        ;; edge.
-                        (setq snap-y pos-y)
-                        (setq top (- parent-bottom height)))
-                       ((and (>= bottom parent-bottom)
-                             (<= (- bottom parent-bottom) snap-width)
-                             snap-y (<= (- pos-y snap-y) snap-width))
-                        ;; Stay snapped when the mouse moved downward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq top (- parent-bottom height)))
-                       (t
-                        ;; Unsnap when the mouse moved downward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))))
-
-                  ;; If requested, constrain FRAME's draggable areas to
-                  ;; PARENT's edges.  The `top-visible' parameter should
-                  ;; be set when FRAME has a draggable header-line.  If
-                  ;; set to a number, it ascertains that the top of
-                  ;; FRAME is always constrained to the top of PARENT
-                  ;; and that at least as many pixels of FRAME as
-                  ;; specified by that number are visible on each of the
-                  ;; three remaining sides of PARENT.
-                  ;;
-                  ;; The `bottom-visible' parameter should be set when
-                  ;; FRAME has a draggable mode-line.  If set to a
-                  ;; number, it ascertains that the bottom of FRAME is
-                  ;; always constrained to the bottom of PARENT and that
-                  ;; at least as many pixels of FRAME as specified by
-                  ;; that number are visible on each of the three
-                  ;; remaining sides of PARENT.
-                  (let ((par (frame-parameter frame 'top-visible))
-                        bottom-visible)
-                    (unless par
-                      (setq par (frame-parameter frame 'bottom-visible))
-                      (setq bottom-visible t))
-                    (when (and (numberp par) parent-edges)
-                      (setq left
-                            (max (min (- parent-right par) left)
-                                 (+ (- parent-left width) par)))
-                      (setq top
-                            (if bottom-visible
-                                (min (max top (- parent-top (- height par)))
-                                     (- parent-bottom height))
-                              (min (max top parent-top)
-                                   (- parent-bottom par))))))
-
-                  ;; Use `modify-frame-parameters' since `left' and
-                  ;; `top' may want to move FRAME out of its PARENT.
-                  (modify-frame-parameters
-                   frame
-                   `((left . (+ ,left)) (top . (+ ,top)))))))
-              (setq last-x pos-x)
-              (setq last-y pos-y))))
-         (old-track-mouse track-mouse))
+                     ((and (< right parent-right)
+                           (<= (- parent-right right) snap-width))
+                      ;; Snap when the mouse moved rightward and FRAME's
+                      ;; right edge would end up within `snap-width'
+                      ;; pixels from PARENT's right edge.
+                      (setq snap-x last-x)
+                      (setq left (- parent-right native-width)))
+                     ((and (>= right parent-right)
+                           (<= (- right parent-right) snap-width)
+                           snap-x (<= (- last-x snap-x) snap-width))
+                      ;; Stay snapped when the mouse moved rightward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq left (- parent-right native-width)))
+                     (t
+                      ;; Unsnap when the mouse moved rightward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-x nil)))))
+                  (cond
+                   ((< last-y first-y)
+                    (cond
+                     ((and (> top parent-top)
+                           (<= (- top parent-top) snap-width))
+                      ;; Snap when the mouse moved upward and FRAME's
+                      ;; top edge would end up within `snap-width'
+                      ;; pixels from PARENT's top edge.
+                      (setq snap-y last-y)
+                      (setq top parent-top))
+                     ((and (<= top parent-top)
+                           (<= (- parent-top top) snap-width)
+                           snap-y (<= (- snap-y last-y) snap-width))
+                      ;; Stay snapped when the mouse moved upward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top parent-top))
+                     (t
+                      ;; Unsnap when the mouse moved upward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))
+                   ((> last-y first-y)
+                    (setq bottom (+ top native-height))
+                    (cond
+                     ((and (< bottom parent-bottom)
+                           (<= (- parent-bottom bottom) snap-width))
+                      ;; Snap when the mouse moved downward and FRAME's
+                      ;; bottom edge would end up within `snap-width'
+                      ;; pixels from PARENT's bottom edge.
+                      (setq snap-y last-y)
+                      (setq top (- parent-bottom native-height)))
+                     ((and (>= bottom parent-bottom)
+                           (<= (- bottom parent-bottom) snap-width)
+                           snap-y (<= (- last-y snap-y) snap-width))
+                      ;; Stay snapped when the mouse moved downward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top (- parent-bottom native-height)))
+                     (t
+                      ;; Unsnap when the mouse moved downward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))))
+
+                ;; If requested, constrain FRAME's draggable areas to
+                ;; PARENT's edges.  The `top-visible' parameter should
+                ;; be set when FRAME has a draggable header-line.  If
+                ;; set to a number, it ascertains that the top of FRAME
+                ;; is always constrained to the top of PARENT and that
+                ;; at least as many pixels of FRAME as specified by that
+                ;; number are visible on each of the three remaining
+                ;; sides of PARENT.
+                ;;
+                ;; The `bottom-visible' parameter should be set when
+                ;; FRAME has a draggable mode-line.  If set to a number,
+                ;; it ascertains that the bottom of FRAME is always
+                ;; constrained to the bottom of PARENT and that at least
+                ;; as many pixels of FRAME as specified by that number
+                ;; are visible on each of the three remaining sides of
+                ;; PARENT.
+                (let ((par (frame-parameter frame 'top-visible))
+                      bottom-visible)
+                  (unless par
+                    (setq par (frame-parameter frame 'bottom-visible))
+                    (setq bottom-visible t))
+                  (when (and (numberp par) parent-edges)
+                    (setq left
+                          (max (min (- parent-right par) left)
+                               (+ (- parent-left native-width) par)))
+                    (setq top
+                          (if bottom-visible
+                              (min (max top (- parent-top (- native-height par)))
+                                   (- parent-bottom native-height))
+                            (min (max top parent-top)
+                                 (- parent-bottom par))))))
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (x-set-frame-size-and-position
+                     frame first-width first-height left top)
+                  ;; Use `modify-frame-parameters' since `left' and `top'
+                  ;; may want to move FRAME out of its PARENT.
+                  (modify-frame-parameters frame `((left . (+ ,left)) (top . (+ ,top)))))))))
+	 (old-track-mouse track-mouse))
     ;; Start tracking.  The special value 'dragging' signals the
     ;; display engine to freeze the mouse pointer shape for as long
     ;; as we drag.
@@ -879,49 +964,49 @@ mouse-drag-left-edge
   "Drag left edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'left))
+  (mouse-drag-frame-resize start-event 'left))
 
 (defun mouse-drag-top-left-corner (start-event)
   "Drag top left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-left))
+  (mouse-drag-frame-resize start-event 'top-left))
 
 (defun mouse-drag-top-edge (start-event)
   "Drag top edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top))
+  (mouse-drag-frame-resize start-event 'top))
 
 (defun mouse-drag-top-right-corner (start-event)
   "Drag top right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-right))
+  (mouse-drag-frame-resize start-event 'top-right))
 
 (defun mouse-drag-right-edge (start-event)
   "Drag right edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'right))
+  (mouse-drag-frame-resize start-event 'right))
 
 (defun mouse-drag-bottom-right-corner (start-event)
   "Drag bottom right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-right))
+  (mouse-drag-frame-resize start-event 'bottom-right))
 
 (defun mouse-drag-bottom-edge (start-event)
   "Drag bottom edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom))
+  (mouse-drag-frame-resize start-event 'bottom))
 
 (defun mouse-drag-bottom-left-corner (start-event)
   "Drag bottom left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-left))
+  (mouse-drag-frame-resize start-event 'bottom-left))
 
 (defcustom mouse-select-region-move-to-beginning nil
   "Effect of selecting a region extending backward from double click.
diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..bf5aac0ac0 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4203,6 +4203,225 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
  return unbind_to (count, frame);
 }
 
+
+static void
+x_set_frame_size_and_position (struct frame *f, int width, int height, int left, int top)
+{
+  int unit_width = FRAME_COLUMN_WIDTH (f);
+  int unit_height = FRAME_LINE_HEIGHT (f);
+  int old_pixel_width = FRAME_PIXEL_WIDTH (f);
+  int old_pixel_height = FRAME_PIXEL_HEIGHT (f);
+  int old_cols = FRAME_COLS (f);
+  int old_lines = FRAME_LINES (f);
+  int new_pixel_width = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
+  int new_pixel_height = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
+  struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f));
+  int old_windows_width = WINDOW_PIXEL_WIDTH (r);
+  int old_windows_height
+    = (WINDOW_PIXEL_HEIGHT (r)
+       + ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
+	  ? WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_MINIBUF_WINDOW (f)))
+	  : 0));
+  int new_windows_width, new_windows_height;
+  int new_cols, new_lines;
+  Lisp_Object frame;
+#ifdef USE_GTK
+  int scale = xg_get_scale (f);
+#endif
+
+  XSETFRAME (frame, f);
+
+  frame_size_history_add
+    (f, Qx_set_frame_size_and_position_1, new_pixel_width,
+     new_pixel_height, Qnil);
+
+  new_windows_width = new_pixel_width - 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
+  new_windows_height = (new_pixel_height
+			- FRAME_TOP_MARGIN_HEIGHT (f)
+			- 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
+  new_cols = width / unit_width;
+  new_lines = height / unit_height;
+
+  block_input ();
+  if (FRAME_WINDOW_P (f) && f->can_set_window_size)
+    {
+#ifdef USE_GTK
+      GdkWindow *window = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+
+      x_wm_set_size_hint (f, 0, 1);
+      gdk_window_move_resize
+	(window, left / scale, top / scale, new_pixel_width / scale,
+	 new_pixel_height / scale);
+      SET_FRAME_GARBAGED (f);
+      cancel_mouse_face (f);
+
+      if (FRAME_VISIBLE_P (f))
+	{
+	  /* Must call this to flush out events */
+	  (void)gtk_events_pending ();
+	  gdk_flush ();
+	  x_wait_for_event (f, ConfigureNotify);
+	}
+      else
+	{
+	  change_frame_size (f, new_pixel_width, new_pixel_height,
+			     false, true, false, true);
+	  x_sync (f);
+	}
+#else
+      f->win_gravity = NorthWestGravity;
+      x_wm_set_size_hint (f, 0, true);
+
+      XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+			 left, top, new_pixel_width,
+			 new_pixel_height + FRAME_MENUBAR_HEIGHT (f));
+
+      SET_FRAME_GARBAGED (f);
+
+      if (FRAME_VISIBLE_P (f))
+	x_wait_for_event (f, ConfigureNotify);
+      else
+	{
+	  change_frame_size (f,new_pixel_width, new_pixel_height,
+			     false, true, false, true);
+	  x_sync (f);
+	}
+
+      x_clear_under_internal_border (f);
+#endif
+
+      mark_window_cursors_off (XWINDOW (f->root_window));
+
+      cancel_mouse_face (f);
+
+      unblock_input ();
+
+      do_pending_window_change (false);
+
+    }
+
+  f->resized_p = true;
+
+  block_input ();
+  if (new_windows_width != old_windows_width)
+    {
+      resize_frame_windows (f, new_windows_width, true);
+      if (WINDOWP (f->tab_bar_window))
+	{
+	  XWINDOW (f->tab_bar_window)->pixel_width = new_windows_width;
+	  XWINDOW (f->tab_bar_window)->total_cols
+	    = new_windows_width / unit_width;
+	}
+
+#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
+      if (WINDOWP (f->tool_bar_window))
+	{
+	  XWINDOW (f->tool_bar_window)->pixel_width = new_windows_width;
+	  XWINDOW (f->tool_bar_window)->total_cols
+	    = new_windows_width / unit_width;
+	}
+#endif
+    }
+  else if (new_cols != old_cols)
+    call2 (Qwindow__pixel_to_total, frame, Qt);
+
+  if (new_windows_height != old_windows_height
+      || WINDOW_TOP_PIXEL_EDGE (r) != FRAME_TOP_MARGIN_HEIGHT (f))
+    resize_frame_windows (f, new_windows_height, false);
+  else if (new_lines != old_lines)
+    call2 (Qwindow__pixel_to_total, frame, Qnil);
+
+  frame_size_history_add
+    (f, Qx_set_frame_size_and_position_3, width, height, Qnil);
+
+  /* Assign new sizes.  */
+  FRAME_TEXT_WIDTH (f) = width;
+  FRAME_TEXT_HEIGHT (f) = height;
+  FRAME_PIXEL_WIDTH (f) = new_pixel_width;
+  FRAME_PIXEL_HEIGHT (f) = new_pixel_height;
+  SET_FRAME_COLS (f, new_cols);
+  SET_FRAME_LINES (f, new_lines);
+  SET_FRAME_COLS (f, new_cols);
+  SET_FRAME_LINES (f, new_lines);
+
+  {
+    struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+    int text_area_x, text_area_y, text_area_width, text_area_height;
+
+    window_box (w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width,
+		&text_area_height);
+    if (w->cursor.x >= text_area_x + text_area_width)
+      w->cursor.hpos = w->cursor.x = 0;
+    if (w->cursor.y >= text_area_y + text_area_height)
+      w->cursor.vpos = w->cursor.y = 0;
+  }
+
+  /* Sanitize window sizes.  */
+  sanitize_window_sizes (Qt);
+  sanitize_window_sizes (Qnil);
+
+  adjust_frame_glyphs (f);
+  calculate_costs (f);
+  SET_FRAME_GARBAGED (f);
+
+  /* A frame was "resized" if one of its pixelsizes changed, even if its
+     X window wasn't resized at all.  */
+  f->resized_p = (new_pixel_width != old_pixel_width
+		  || new_pixel_height != old_pixel_height);
+
+  unblock_input ();
+}
+
+
+DEFUN ("x-set-frame-size-and-position", Fx_set_frame_size_and_position,
+       Sx_set_frame_size_and_position, 0, 5, 0,
+       doc: /* Set position of FRAME to (LEFT, TOP) and size to (WIDTH, HEIGHT).
+FRAME must be a live frame and defaults to the selected one.  The
+remaining values must be either nil (which means to not change the
+respective size or position) or specify a pixel value.  */)
+  (Lisp_Object frame, Lisp_Object width, Lisp_Object height,
+   Lisp_Object left, Lisp_Object top)
+{
+  struct frame *f = decode_live_frame (frame);
+  int text_width, text_height, outer_left, outer_top;
+
+  if (EQ (width, Qnil))
+    text_width = FRAME_TEXT_WIDTH (f);
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, width);
+      text_width = XFIXNUM (width);
+    }
+
+  if (EQ (height, Qnil))
+    text_height = FRAME_TEXT_HEIGHT (f);
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, height);
+      text_height = XFIXNUM (height);
+    }
+
+  if (EQ (left, Qnil))
+    outer_left = f->left_pos;
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, left);
+      outer_left = XFIXNUM (left);
+    }
+
+  if (EQ (top, Qnil))
+    outer_top = f->top_pos;
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, top);
+      outer_top = XFIXNUM (top);
+    }
+
+  x_set_frame_size_and_position
+    (f, text_width, text_height, outer_left, outer_top);
+
+  return Qnil;
+}
 \f
 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
        doc: /* Internal function called by `color-defined-p'.
@@ -7810,6 +8029,9 @@ syms_of_xfns (void)
   DEFSYM (Qfont_parameter, "font-parameter");
   DEFSYM (Qmono, "mono");
   DEFSYM (Qassq_delete_all, "assq-delete-all");
+  DEFSYM (Qx_set_frame_size_and_position_1, "x-set-frame-size-and-position-1");
+  DEFSYM (Qx_set_frame_size_and_position_2, "x-set-frame-size-and-position-2");
+  DEFSYM (Qx_set_frame_size_and_position_3, "x-set-frame-size-and-position-3");
 
 #ifdef USE_CAIRO
   DEFSYM (Qpdf, "pdf");
@@ -8065,6 +8287,7 @@ syms_of_xfns (void)
   defsubr (&Sx_set_mouse_absolute_pixel_position);
   defsubr (&Sx_wm_set_size_hint);
   defsubr (&Sx_create_frame);
+  defsubr (&Sx_set_frame_size_and_position);
   defsubr (&Sx_open_connection);
   defsubr (&Sx_close_connection);
   defsubr (&Sx_display_list);

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-31  9:29                                                                                                             ` martin rudalics
@ 2020-01-31 11:52                                                                                                               ` Dmitry Gutov
  2020-01-31 15:44                                                                                                                 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-31 11:52 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 31.01.2020 12:29, martin rudalics wrote:
>  > So, Lucid build, under Mutter:
>  >
>  > - Resizing works, more or less. Moving a frame by its mode-line works 
> as well without stutters.
>  > - The right-bottom corner still jumps away. When I drag the frame by 
> the mode-line, it (the corner) also jumps at first, the same distance.
>  > - Same with moving or resizing a child frame.
> 
> I reworked the code as attached.  This includes scaling support and the
> jump away issue.

Yes, jumping away seems to be gone. Resizing and moving by the mode-line 
is still smooth.

 > GTK resizing will probably still fail, the rest should
 > work now.

Considering scaling was only a problem for GTK, that doesn't sound like 
success. Anyway, resizing normal undecorated frames in GTK seems to work 
just as well now. Resizing child frame (with scaling on) is still broken 
(but looks a bit different, no jumping around, at least).

With GTK build frame resizing also doesn't honor non-pixelwise resizing. 
When frame-resize-pixelwise is nil, resizing routinely eats into 
internal borders (right and bottom ones).

>  > - tumashu's child frame moving test scenario is still slow.
>  >
>  > E.g.
>  >
>  >    (benchmark 1 `(set-frame-position ,test-frame 50 50))
>  >    => 0.5s
> 
> Nothing changed in this regard.  But here
> 
> (benchmark 1 `(x-set-frame-size-and-position ,test-frame nil nil 50 50))
> 
> => 0.100523s

Seems like a possible improvement, but still much slower than 
set-frame-position with the GTK build.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-31 11:52                                                                                                               ` Dmitry Gutov
@ 2020-01-31 15:44                                                                                                                 ` martin rudalics
  2020-01-31 22:22                                                                                                                   ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-01-31 15:44 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1439 bytes --]

 > Considering scaling was only a problem for GTK, that doesn't sound
 > like success. Anyway, resizing normal undecorated frames in GTK seems
 > to work just as well now. Resizing child frame (with scaling on) is
 > still broken (but looks a bit different, no jumping around, at least).

Presumably resizing child frames is still broken with scaling off too.

 > With GTK build frame resizing also doesn't honor non-pixelwise
 > resizing. When frame-resize-pixelwise is nil, resizing routinely eats
 > into internal borders (right and bottom ones).

Right.  I'll attach a patch that fixes it.  Maybe we'll have to
investigate the size hints issue next.  The whole emacsgtkfixed.c stuff
(which I do not understand) troubles me considerably.  Could you try
building with GTK 2?

 >>  > - tumashu's child frame moving test scenario is still slow.
 >>  >
 >>  > E.g.
 >>  >
 >>  >    (benchmark 1 `(set-frame-position ,test-frame 50 50))
 >>  >    => 0.5s
 >>
 >> Nothing changed in this regard.  But here
 >>
 >> (benchmark 1 `(x-set-frame-size-and-position ,test-frame nil nil 50 50))
 >>
 >> => 0.100523s
 >
 > Seems like a possible improvement, but still much slower than set-frame-position with the GTK build.

Neither of these benchmarks seems meaningful in the first place.  What
would it measure?  Maybe tumashu can check with a version that uses
'x-set-frame-size-and-position' whether it's still too slow on non-GTK
builds.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mouse+xfns.diff --]
[-- Type: text/x-patch; name="mouse+xfns.diff", Size: 41255 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index e58a2e6da1..9a0e2b28e4 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -552,7 +552,7 @@ mouse-drag-mode-line
              (not (eq (window-frame minibuffer-window) frame))))
       ;; Drag frame when the window is on the bottom of its frame and
       ;; there is no minibuffer window below.
-      (mouse-drag-frame start-event 'move)))))
+      (mouse-drag-frame-move start-event)))))
 
 (defun mouse-drag-header-line (start-event)
   "Change the height of a window by dragging on its header line.
@@ -569,7 +569,7 @@ mouse-drag-header-line
         (mouse-drag-line start-event 'header)
       (let ((frame (window-frame window)))
         (when (frame-parameter frame 'drag-with-header-line)
-          (mouse-drag-frame start-event 'move))))))
+          (mouse-drag-frame-move start-event))))))
 
 (defun mouse-drag-vertical-line (start-event)
   "Change the width of a window by dragging on a vertical line.
@@ -577,46 +577,7 @@ mouse-drag-vertical-line
   (interactive "e")
   (mouse-drag-line start-event 'vertical))
 \f
-(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move)
-  "Helper function for `mouse-drag-frame'."
-  (let* ((frame-x-y (frame-position frame))
-         (frame-x (car frame-x-y))
-         (frame-y (cdr frame-x-y))
-         alist)
-    (if (> x-diff 0)
-        (when x-move
-          (setq x-diff (min x-diff frame-x))
-          (setq x-move (- frame-x x-diff)))
-      (let* ((min-width (frame-windows-min-size frame t nil t))
-             (min-diff (max 0 (- (frame-inner-width frame) min-width))))
-        (setq x-diff (max x-diff (- min-diff)))
-        (when x-move
-          (setq x-move (+ frame-x (- x-diff))))))
-
-    (if (> y-diff 0)
-        (when y-move
-          (setq y-diff (min y-diff frame-y))
-          (setq y-move (- frame-y y-diff)))
-      (let* ((min-height (frame-windows-min-size frame nil nil t))
-             (min-diff (max 0 (- (frame-inner-height frame) min-height))))
-        (setq y-diff (max y-diff (- min-diff)))
-        (when y-move
-          (setq y-move (+ frame-y (- y-diff))))))
-
-    (unless (zerop x-diff)
-      (when x-move
-        (push `(left . ,x-move) alist))
-      (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff)))
-            alist))
-    (unless (zerop y-diff)
-      (when y-move
-        (push `(top . ,y-move) alist))
-      (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff)))
-            alist))
-    (when alist
-      (modify-frame-parameters frame alist))))
-
-(defun mouse-drag-frame (start-event part)
+(defun mouse-drag-frame-resize (start-event part)
   "Drag a frame or one of its edges with the mouse.
 START-EVENT is the starting mouse event of the drag action.  Its
 position window denotes the frame that will be dragged.
@@ -635,9 +596,168 @@ mouse-drag-frame
          (frame (if (window-live-p window)
                     (window-frame window)
                   window))
-         (width (frame-native-width frame))
-         (height (frame-native-height frame))
-         ;; PARENT is the parent frame of FRAME or, if FRAME is a
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+         (x-left first-left)
+         (first-top (cdr first-pos))
+         (x-top first-top)
+	 (first-width (frame-text-width frame))
+         (x-width first-width)
+	 (first-height (frame-text-height frame))
+         (x-height first-height)
+	 ;; Don't let FRAME become less large than the size needed to
+	 ;; fit all of its windows.
+	 (min-text-width
+	  (+ (frame-windows-min-size frame t nil t)
+	     (- (frame-inner-width frame) first-width)))
+	 (min-text-height
+	  (+ (frame-windows-min-size frame nil nil t)
+	     (- (frame-inner-height frame) first-height)))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
+         ;; top-level frame, FRAME's workarea.
+         (parent (frame-parent frame))
+         (parent-edges
+          (if parent
+              (frame-edges parent)
+            (let* ((attributes
+                    (car (display-monitor-attributes-list)))
+                   (workarea (assq 'workarea attributes)))
+              (and workarea
+                   `(,(nth 1 workarea) ,(nth 2 workarea)
+                     ,(+ (nth 1 workarea) (nth 3 workarea))
+                     ,(+ (nth 2 workarea) (nth 4 workarea)))))))
+         (parent-left (and parent-edges (nth 0 parent-edges)))
+         (parent-top (and parent-edges (nth 1 parent-edges)))
+         (parent-right (and parent-edges (nth 2 parent-edges)))
+         (parent-bottom (and parent-edges (nth 3 parent-edges)))
+	 ;; Drag types.  drag-left/drag-right and drag-top/drag-bottom
+	 ;; are mutually exclusive.
+	 (drag-left (memq part '(bottom-left left top-left)))
+	 (drag-top (memq part '(top-left top top-right)))
+	 (drag-right (memq part '(top-right right bottom-right)))
+	 (drag-bottom (memq part '(bottom-right bottom bottom-left)))
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         (exitfun nil)
+         (move
+          (lambda (event)
+            (interactive "e")
+            (when (consp event)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+		     alist)
+                ;; We never want to warp the mouse position here.  When
+                ;; moving the mouse leftward or upward, then with a wide
+                ;; border the calculated left or top position of the
+                ;; frame could drop to a value less than zero depending
+                ;; on where precisely the mouse within the border.  We
+                ;; guard against this by never allowing the frame to
+                ;; move to a position less than zero here.  No such
+                ;; precautions are used for the right and bottom borders
+                ;; so with a large internal border parts of that border
+                ;; may disappear.
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (progn
+                      (when (and drag-left (>= last-x parent-left)
+                                 (>= (- first-width left) min-text-width))
+		        (setq x-left (max (+ first-left left) 0))
+		        (setq x-width (- first-width left)))
+	              (when (and drag-top (>= last-y parent-top)
+                                 (>= (- first-height top) min-text-height))
+		        (setq x-top (max 0 (+ first-top top)))
+		        (setq x-height (- first-height top)))
+	              (when (and drag-right (<= last-x parent-right)
+                                 (>= (+ first-width left) min-text-width))
+		        (setq x-width (+ first-width left)))
+	              (when (and drag-bottom (<= last-y parent-bottom)
+                                 (>= (+ first-height top) min-text-height))
+		        (setq x-height (+ first-height top)))
+                      (x-set-frame-size-and-position
+                       frame x-width x-height x-left x-top))
+                  (when (and drag-left (>= last-x parent-left)
+                             (>= (- first-width left) min-text-width))
+		    (push `(left . ,(max (+ first-left left) 0)) alist)
+		    (push `(width . (text-pixels . ,(- first-width left)))
+                          alist))
+	          (when (and drag-top (>= last-y parent-top)
+                             (>= (- first-height top) min-text-height))
+		    (push `(top . ,(max 0 (+ first-top top))) alist)
+		    (push `(height . (text-pixels . ,(- first-height top)))
+                          alist))
+	          (when (and drag-right (<= last-x parent-right)
+                             (>= (+ first-width left) min-text-width))
+		    (push `(width . (text-pixels . ,(+ first-width left)))
+                          alist))
+	          (when (and drag-bottom (<= last-y parent-bottom)
+                             (>= (+ first-height top) min-text-height))
+		    (push `(height . (text-pixels . ,(+ first-height top)))
+                          alist))
+	          (modify-frame-parameters frame alist))))))
+         (old-track-mouse track-mouse))
+    ;; Start tracking.  The special value 'dragging' signals the
+    ;; display engine to freeze the mouse pointer shape for as long
+    ;; as we drag.
+    (setq track-mouse 'dragging)
+    ;; Loop reading events and sampling the position of the mouse.
+    (setq exitfun
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [scroll-bar-movement] #'ignore)
+             (define-key map [mouse-movement] move)
+             ;; Swallow drag-mouse-1 events to avoid selecting some other window.
+             (define-key map [drag-mouse-1]
+               (lambda () (interactive) (funcall exitfun)))
+             ;; Some of the events will of course end up looked up
+             ;; with a mode-line, header-line or vertical-line prefix ...
+             (define-key map [mode-line] map)
+             (define-key map [header-line] map)
+             (define-key map [vertical-line] map)
+             ;; ... and some maybe even with a right- or bottom-divider
+             ;; prefix.
+             (define-key map [right-divider] map)
+             (define-key map [bottom-divider] map)
+             map)
+           t (lambda () (setq track-mouse old-track-mouse))))))
+
+(defun mouse-drag-frame-move (start-event)
+  "Drag a frame or one of its edges with the mouse.
+START-EVENT is the starting mouse event of the drag action.  Its
+position window denotes the frame that will be dragged.
+
+PART specifies the part that has been dragged and must be one of
+the symbols `left', `top', `right', `bottom', `top-left',
+`top-right', `bottom-left', `bottom-right' to drag an internal
+border or edge.  If PART equals `move', this means to move the
+frame with the mouse."
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
+  (let* ((echo-keystrokes 0)
+	 (start (event-start start-event))
+         (window (posn-window start))
+         ;; FRAME is the frame to drag.
+         (frame (if (window-live-p window)
+                    (window-frame window)
+                  window))
+         (native-width (frame-native-width frame))
+         (native-height (frame-native-height frame))
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+	 (first-top (cdr first-pos))
+	 (first-width (frame-text-width frame))
+	 (first-height (frame-text-height frame))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
          ;; top-level frame, FRAME's workarea.
          (parent (frame-parent frame))
          (parent-edges
@@ -654,19 +774,16 @@ mouse-drag-frame
          (parent-top (and parent-edges (nth 1 parent-edges)))
          (parent-right (and parent-edges (nth 2 parent-edges)))
          (parent-bottom (and parent-edges (nth 3 parent-edges)))
-         ;; `pos-x' and `pos-y' record the x- and y-coordinates of the
-	 ;; last sampled mouse position.  Note that we sample absolute
-	 ;; mouse positions to avoid that moving the mouse from one
-	 ;; frame into another gets into our way.  `last-x' and `last-y'
-	 ;; records the x- and y-coordinates of the previously sampled
-	 ;; position.  The differences between `last-x' and `pos-x' as
-	 ;; well as `last-y' and `pos-y' determine the amount the mouse
-	 ;; has been dragged between the last two samples.
-         pos-x-y pos-x pos-y
-         (last-x-y (mouse-absolute-pixel-position))
-         (last-x (car last-x-y))
-         (last-y (cdr last-x-y))
-         ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         ;; `snap-width' (maybe also a yet to be provided `snap-height')
+         ;; could become floats to handle proportionality wrt PARENT.
+         ;; We don't do any checks on this parameter so far.
+         (snap-width (frame-parameter frame 'snap-width))
+	 ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
          ;; mouse position when FRAME snapped.  As soon as the
          ;; difference between `pos-x' and `snap-x' (or `pos-y' and
          ;; `snap-y') exceeds the value of FRAME's `snap-width'
@@ -678,176 +795,144 @@ mouse-drag-frame
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (setq pos-x-y (mouse-absolute-pixel-position))
-              (setq pos-x (car pos-x-y))
-              (setq pos-y (cdr pos-x-y))
-              (cond
-               ((eq part 'left)
-                (mouse-resize-frame frame (- last-x pos-x) 0 t))
-               ((eq part 'top)
-                (mouse-resize-frame frame 0 (- last-y pos-y) nil t))
-               ((eq part 'right)
-                (mouse-resize-frame frame (- pos-x last-x) 0))
-               ((eq part 'bottom)
-                (mouse-resize-frame frame 0 (- pos-y last-y)))
-               ((eq part 'top-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- last-y pos-y) t t))
-               ((eq part 'top-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- last-y pos-y) nil t))
-               ((eq part 'bottom-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- pos-y last-y) t))
-               ((eq part 'bottom-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- pos-y last-y)))
-               ((eq part 'move)
-                (let* ((old-position (frame-position frame))
-                       (old-left (car old-position))
-                       (old-top (cdr old-position))
-                       (left (+ old-left (- pos-x last-x)))
-                       (top (+ old-top (- pos-y last-y)))
-                       right bottom
-                       ;; `snap-width' (maybe also a yet to be provided
-                       ;; `snap-height') could become floats to handle
-                       ;; proportionality wrt PARENT.  We don't do any
-                       ;; checks on this parameter so far.
-                       (snap-width (frame-parameter frame 'snap-width)))
-                  ;; Docking and constraining.
-                  (when (and (numberp snap-width) parent-edges)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+                     right bottom)
+		(setq left (+ first-left left))
+		(setq top (+ first-top top))
+                ;; Docking and constraining.
+                (when (and (numberp snap-width) parent-edges)
+                  (cond
+                   ;; Docking at the left parent edge.
+                   ((< last-x first-x)
                     (cond
-                     ;; Docking at the left parent edge.
-                     ((< pos-x last-x)
-                      (cond
-                       ((and (> left parent-left)
-                             (<= (- left parent-left) snap-width))
-                        ;; Snap when the mouse moved leftward and
-                        ;; FRAME's left edge would end up within
-                        ;; `snap-width' pixels from PARENT's left edge.
-                        (setq snap-x pos-x)
-                        (setq left parent-left))
-                       ((and (<= left parent-left)
-                             (<= (- parent-left left) snap-width)
-                             snap-x (<= (- snap-x pos-x) snap-width))
-                        ;; Stay snapped when the mouse moved leftward
-                        ;; but not more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq left parent-left))
-                       (t
-                        ;; Unsnap when the mouse moved more than
-                        ;; `snap-width' pixels leftward from the time
-                        ;; FRAME snapped.
-                        (setq snap-x nil))))
-                     ((> pos-x last-x)
-                      (setq right (+ left width))
-                      (cond
-                       ((and (< right parent-right)
-                             (<= (- parent-right right) snap-width))
-                        ;; Snap when the mouse moved rightward and
-                        ;; FRAME's right edge would end up within
-                        ;; `snap-width' pixels from PARENT's right edge.
-                        (setq snap-x pos-x)
-                        (setq left (- parent-right width)))
-                       ((and (>= right parent-right)
-                             (<= (- right parent-right) snap-width)
-                             snap-x (<= (- pos-x snap-x) snap-width))
-                        ;; Stay snapped when the mouse moved rightward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq left (- parent-right width)))
-                       (t
-                        ;; Unsnap when the mouse moved rightward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-x nil)))))
-
+                     ((and (> left parent-left)
+                           (<= (- left parent-left) snap-width))
+                      ;; Snap when the mouse moved leftward and FRAME's
+                      ;; left edge would end up within `snap-width'
+                      ;; pixels from PARENT's left edge.
+                      (setq snap-x last-x)
+                      (setq left parent-left))
+                     ((and (<= left parent-left)
+                           (<= (- parent-left left) snap-width)
+                           snap-x (<= (- snap-x last-x) snap-width))
+                      ;; Stay snapped when the mouse moved leftward but
+                      ;; not more than `snap-width' pixels from the time
+                      ;; FRAME snapped.
+                      (setq left parent-left))
+                     (t
+                      ;; Unsnap when the mouse moved more than
+                      ;; `snap-width' pixels leftward from the time
+                      ;; FRAME snapped.
+                      (setq snap-x nil))))
+                   ((> last-x first-x)
+                    (setq right (+ left native-width))
                     (cond
-                     ((< pos-y last-y)
-                      (cond
-                       ((and (> top parent-top)
-                             (<= (- top parent-top) snap-width))
-                        ;; Snap when the mouse moved upward and FRAME's
-                        ;; top edge would end up within `snap-width'
-                        ;; pixels from PARENT's top edge.
-                        (setq snap-y pos-y)
-                        (setq top parent-top))
-                       ((and (<= top parent-top)
-                             (<= (- parent-top top) snap-width)
-                             snap-y (<= (- snap-y pos-y) snap-width))
-                        ;; Stay snapped when the mouse moved upward but
-                        ;; not more more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq top parent-top))
-                       (t
-                        ;; Unsnap when the mouse moved upward more than
-                        ;; `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))
-                     ((> pos-y last-y)
-                      (setq bottom (+ top height))
-                      (cond
-                       ((and (< bottom parent-bottom)
-                             (<= (- parent-bottom bottom) snap-width))
-                        ;; Snap when the mouse moved downward and
-                        ;; FRAME's bottom edge would end up within
-                        ;; `snap-width' pixels from PARENT's bottom
-                        ;; edge.
-                        (setq snap-y pos-y)
-                        (setq top (- parent-bottom height)))
-                       ((and (>= bottom parent-bottom)
-                             (<= (- bottom parent-bottom) snap-width)
-                             snap-y (<= (- pos-y snap-y) snap-width))
-                        ;; Stay snapped when the mouse moved downward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq top (- parent-bottom height)))
-                       (t
-                        ;; Unsnap when the mouse moved downward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))))
-
-                  ;; If requested, constrain FRAME's draggable areas to
-                  ;; PARENT's edges.  The `top-visible' parameter should
-                  ;; be set when FRAME has a draggable header-line.  If
-                  ;; set to a number, it ascertains that the top of
-                  ;; FRAME is always constrained to the top of PARENT
-                  ;; and that at least as many pixels of FRAME as
-                  ;; specified by that number are visible on each of the
-                  ;; three remaining sides of PARENT.
-                  ;;
-                  ;; The `bottom-visible' parameter should be set when
-                  ;; FRAME has a draggable mode-line.  If set to a
-                  ;; number, it ascertains that the bottom of FRAME is
-                  ;; always constrained to the bottom of PARENT and that
-                  ;; at least as many pixels of FRAME as specified by
-                  ;; that number are visible on each of the three
-                  ;; remaining sides of PARENT.
-                  (let ((par (frame-parameter frame 'top-visible))
-                        bottom-visible)
-                    (unless par
-                      (setq par (frame-parameter frame 'bottom-visible))
-                      (setq bottom-visible t))
-                    (when (and (numberp par) parent-edges)
-                      (setq left
-                            (max (min (- parent-right par) left)
-                                 (+ (- parent-left width) par)))
-                      (setq top
-                            (if bottom-visible
-                                (min (max top (- parent-top (- height par)))
-                                     (- parent-bottom height))
-                              (min (max top parent-top)
-                                   (- parent-bottom par))))))
-
-                  ;; Use `modify-frame-parameters' since `left' and
-                  ;; `top' may want to move FRAME out of its PARENT.
-                  (modify-frame-parameters
-                   frame
-                   `((left . (+ ,left)) (top . (+ ,top)))))))
-              (setq last-x pos-x)
-              (setq last-y pos-y))))
-         (old-track-mouse track-mouse))
+                     ((and (< right parent-right)
+                           (<= (- parent-right right) snap-width))
+                      ;; Snap when the mouse moved rightward and FRAME's
+                      ;; right edge would end up within `snap-width'
+                      ;; pixels from PARENT's right edge.
+                      (setq snap-x last-x)
+                      (setq left (- parent-right native-width)))
+                     ((and (>= right parent-right)
+                           (<= (- right parent-right) snap-width)
+                           snap-x (<= (- last-x snap-x) snap-width))
+                      ;; Stay snapped when the mouse moved rightward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq left (- parent-right native-width)))
+                     (t
+                      ;; Unsnap when the mouse moved rightward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-x nil)))))
+                  (cond
+                   ((< last-y first-y)
+                    (cond
+                     ((and (> top parent-top)
+                           (<= (- top parent-top) snap-width))
+                      ;; Snap when the mouse moved upward and FRAME's
+                      ;; top edge would end up within `snap-width'
+                      ;; pixels from PARENT's top edge.
+                      (setq snap-y last-y)
+                      (setq top parent-top))
+                     ((and (<= top parent-top)
+                           (<= (- parent-top top) snap-width)
+                           snap-y (<= (- snap-y last-y) snap-width))
+                      ;; Stay snapped when the mouse moved upward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top parent-top))
+                     (t
+                      ;; Unsnap when the mouse moved upward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))
+                   ((> last-y first-y)
+                    (setq bottom (+ top native-height))
+                    (cond
+                     ((and (< bottom parent-bottom)
+                           (<= (- parent-bottom bottom) snap-width))
+                      ;; Snap when the mouse moved downward and FRAME's
+                      ;; bottom edge would end up within `snap-width'
+                      ;; pixels from PARENT's bottom edge.
+                      (setq snap-y last-y)
+                      (setq top (- parent-bottom native-height)))
+                     ((and (>= bottom parent-bottom)
+                           (<= (- bottom parent-bottom) snap-width)
+                           snap-y (<= (- last-y snap-y) snap-width))
+                      ;; Stay snapped when the mouse moved downward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top (- parent-bottom native-height)))
+                     (t
+                      ;; Unsnap when the mouse moved downward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))))
+
+                ;; If requested, constrain FRAME's draggable areas to
+                ;; PARENT's edges.  The `top-visible' parameter should
+                ;; be set when FRAME has a draggable header-line.  If
+                ;; set to a number, it ascertains that the top of FRAME
+                ;; is always constrained to the top of PARENT and that
+                ;; at least as many pixels of FRAME as specified by that
+                ;; number are visible on each of the three remaining
+                ;; sides of PARENT.
+                ;;
+                ;; The `bottom-visible' parameter should be set when
+                ;; FRAME has a draggable mode-line.  If set to a number,
+                ;; it ascertains that the bottom of FRAME is always
+                ;; constrained to the bottom of PARENT and that at least
+                ;; as many pixels of FRAME as specified by that number
+                ;; are visible on each of the three remaining sides of
+                ;; PARENT.
+                (let ((par (frame-parameter frame 'top-visible))
+                      bottom-visible)
+                  (unless par
+                    (setq par (frame-parameter frame 'bottom-visible))
+                    (setq bottom-visible t))
+                  (when (and (numberp par) parent-edges)
+                    (setq left
+                          (max (min (- parent-right par) left)
+                               (+ (- parent-left native-width) par)))
+                    (setq top
+                          (if bottom-visible
+                              (min (max top (- parent-top (- native-height par)))
+                                   (- parent-bottom native-height))
+                            (min (max top parent-top)
+                                 (- parent-bottom par))))))
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (x-set-frame-size-and-position
+                     frame first-width first-height left top)
+                  ;; Use `modify-frame-parameters' since `left' and `top'
+                  ;; may want to move FRAME out of its PARENT.
+                  (modify-frame-parameters frame `((left . (+ ,left)) (top . (+ ,top)))))))))
+	 (old-track-mouse track-mouse))
     ;; Start tracking.  The special value 'dragging' signals the
     ;; display engine to freeze the mouse pointer shape for as long
     ;; as we drag.
@@ -879,49 +964,49 @@ mouse-drag-left-edge
   "Drag left edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'left))
+  (mouse-drag-frame-resize start-event 'left))
 
 (defun mouse-drag-top-left-corner (start-event)
   "Drag top left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-left))
+  (mouse-drag-frame-resize start-event 'top-left))
 
 (defun mouse-drag-top-edge (start-event)
   "Drag top edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top))
+  (mouse-drag-frame-resize start-event 'top))
 
 (defun mouse-drag-top-right-corner (start-event)
   "Drag top right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-right))
+  (mouse-drag-frame-resize start-event 'top-right))
 
 (defun mouse-drag-right-edge (start-event)
   "Drag right edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'right))
+  (mouse-drag-frame-resize start-event 'right))
 
 (defun mouse-drag-bottom-right-corner (start-event)
   "Drag bottom right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-right))
+  (mouse-drag-frame-resize start-event 'bottom-right))
 
 (defun mouse-drag-bottom-edge (start-event)
   "Drag bottom edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom))
+  (mouse-drag-frame-resize start-event 'bottom))
 
 (defun mouse-drag-bottom-left-corner (start-event)
   "Drag bottom left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-left))
+  (mouse-drag-frame-resize start-event 'bottom-left))
 
 (defcustom mouse-select-region-move-to-beginning nil
   "Effect of selecting a region extending backward from double click.
diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..d8387f66bf 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4203,6 +4203,231 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
  return unbind_to (count, frame);
 }
 
+
+static void
+x_set_frame_size_and_position (struct frame *f, int width, int height, int left, int top)
+{
+  int unit_width = FRAME_COLUMN_WIDTH (f);
+  int unit_height = FRAME_LINE_HEIGHT (f);
+  int old_pixel_width = FRAME_PIXEL_WIDTH (f);
+  int old_pixel_height = FRAME_PIXEL_HEIGHT (f);
+  int old_cols = FRAME_COLS (f);
+  int old_lines = FRAME_LINES (f);
+  int new_pixel_width = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
+  int new_pixel_height = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
+  struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f));
+  int old_windows_width = WINDOW_PIXEL_WIDTH (r);
+  int old_windows_height
+    = (WINDOW_PIXEL_HEIGHT (r)
+       + ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
+	  ? WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_MINIBUF_WINDOW (f)))
+	  : 0));
+  int new_windows_width, new_windows_height;
+  int new_cols, new_lines;
+  Lisp_Object frame;
+  bool old_frame_resize_pixelwise = frame_resize_pixelwise;
+#ifdef USE_GTK
+  int scale = xg_get_scale (f);
+#endif
+
+  XSETFRAME (frame, f);
+
+  frame_size_history_add
+    (f, Qx_set_frame_size_and_position_1, new_pixel_width,
+     new_pixel_height, Qnil);
+
+  new_windows_width = new_pixel_width - 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
+  new_windows_height = (new_pixel_height
+			- FRAME_TOP_MARGIN_HEIGHT (f)
+			- 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
+  new_cols = width / unit_width;
+  new_lines = height / unit_height;
+
+  if (FRAME_WINDOW_P (f) && f->can_set_window_size)
+    {
+      block_input ();
+
+#ifdef USE_GTK
+      GdkWindow *window = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+
+      frame_resize_pixelwise = true;
+      x_wm_set_size_hint (f, 0, true);
+      frame_resize_pixelwise = old_frame_resize_pixelwise;
+      gdk_window_move_resize
+	(window, left / scale, top / scale, new_pixel_width / scale,
+	 new_pixel_height / scale);
+      SET_FRAME_GARBAGED (f);
+      cancel_mouse_face (f);
+
+      if (FRAME_VISIBLE_P (f))
+	{
+	  /* Must call this to flush out events */
+	  (void)gtk_events_pending ();
+	  gdk_flush ();
+	  x_wait_for_event (f, ConfigureNotify);
+	}
+      else
+	{
+	  change_frame_size (f, new_pixel_width, new_pixel_height,
+			     false, true, false, true);
+	  x_sync (f);
+	}
+#else
+      f->win_gravity = NorthWestGravity;
+      frame_resize_pixelwise = true;
+      x_wm_set_size_hint (f, 0, true);
+      frame_resize_pixelwise = old_frame_resize_pixelwise;
+
+      XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+			 left, top, new_pixel_width,
+			 new_pixel_height + FRAME_MENUBAR_HEIGHT (f));
+
+      SET_FRAME_GARBAGED (f);
+
+      if (FRAME_VISIBLE_P (f))
+	x_wait_for_event (f, ConfigureNotify);
+      else
+	{
+	  change_frame_size (f,new_pixel_width, new_pixel_height,
+			     false, true, false, true);
+	  x_sync (f);
+	}
+
+      x_clear_under_internal_border (f);
+#endif
+
+      mark_window_cursors_off (XWINDOW (f->root_window));
+
+      cancel_mouse_face (f);
+
+      unblock_input ();
+
+      do_pending_window_change (false);
+
+      f->resized_p = true;
+
+      block_input ();
+    }
+
+  if (new_windows_width != old_windows_width)
+    {
+      resize_frame_windows (f, new_windows_width, true);
+      if (WINDOWP (f->tab_bar_window))
+	{
+	  XWINDOW (f->tab_bar_window)->pixel_width = new_windows_width;
+	  XWINDOW (f->tab_bar_window)->total_cols
+	    = new_windows_width / unit_width;
+	}
+
+#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
+      if (WINDOWP (f->tool_bar_window))
+	{
+	  XWINDOW (f->tool_bar_window)->pixel_width = new_windows_width;
+	  XWINDOW (f->tool_bar_window)->total_cols
+	    = new_windows_width / unit_width;
+	}
+#endif
+    }
+  else if (new_cols != old_cols)
+    call2 (Qwindow__pixel_to_total, frame, Qt);
+
+  if (new_windows_height != old_windows_height
+      || WINDOW_TOP_PIXEL_EDGE (r) != FRAME_TOP_MARGIN_HEIGHT (f))
+    resize_frame_windows (f, new_windows_height, false);
+  else if (new_lines != old_lines)
+    call2 (Qwindow__pixel_to_total, frame, Qnil);
+
+  frame_size_history_add
+    (f, Qx_set_frame_size_and_position_3, width, height, Qnil);
+
+  /* Assign new sizes.  */
+  FRAME_TEXT_WIDTH (f) = width;
+  FRAME_TEXT_HEIGHT (f) = height;
+  FRAME_PIXEL_WIDTH (f) = new_pixel_width;
+  FRAME_PIXEL_HEIGHT (f) = new_pixel_height;
+  SET_FRAME_COLS (f, new_cols);
+  SET_FRAME_LINES (f, new_lines);
+  SET_FRAME_COLS (f, new_cols);
+  SET_FRAME_LINES (f, new_lines);
+
+  {
+    struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+    int text_area_x, text_area_y, text_area_width, text_area_height;
+
+    window_box (w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width,
+		&text_area_height);
+    if (w->cursor.x >= text_area_x + text_area_width)
+      w->cursor.hpos = w->cursor.x = 0;
+    if (w->cursor.y >= text_area_y + text_area_height)
+      w->cursor.vpos = w->cursor.y = 0;
+  }
+
+  /* Sanitize window sizes.  */
+  sanitize_window_sizes (Qt);
+  sanitize_window_sizes (Qnil);
+
+  adjust_frame_glyphs (f);
+  calculate_costs (f);
+  SET_FRAME_GARBAGED (f);
+
+  /* A frame was "resized" if one of its pixelsizes changed, even if its
+     X window wasn't resized at all.  */
+  f->resized_p = (new_pixel_width != old_pixel_width
+		  || new_pixel_height != old_pixel_height);
+
+  unblock_input ();
+}
+
+
+DEFUN ("x-set-frame-size-and-position", Fx_set_frame_size_and_position,
+       Sx_set_frame_size_and_position, 0, 5, 0,
+       doc: /* Set position of FRAME to (LEFT, TOP) and size to (WIDTH, HEIGHT).
+FRAME must be a live frame and defaults to the selected one.  The
+remaining values must be either nil (which means to not change the
+respective size or position) or specify a pixel value.  */)
+  (Lisp_Object frame, Lisp_Object width, Lisp_Object height,
+   Lisp_Object left, Lisp_Object top)
+{
+  struct frame *f = decode_live_frame (frame);
+  int text_width, text_height, outer_left, outer_top;
+
+  if (EQ (width, Qnil))
+    text_width = FRAME_TEXT_WIDTH (f);
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, width);
+      text_width = XFIXNUM (width);
+    }
+
+  if (EQ (height, Qnil))
+    text_height = FRAME_TEXT_HEIGHT (f);
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, height);
+      text_height = XFIXNUM (height);
+    }
+
+  if (EQ (left, Qnil))
+    outer_left = f->left_pos;
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, left);
+      outer_left = XFIXNUM (left);
+    }
+
+  if (EQ (top, Qnil))
+    outer_top = f->top_pos;
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, top);
+      outer_top = XFIXNUM (top);
+    }
+
+  x_set_frame_size_and_position
+    (f, text_width, text_height, outer_left, outer_top);
+
+  return Qnil;
+}
 \f
 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
        doc: /* Internal function called by `color-defined-p'.
@@ -7810,6 +8035,9 @@ syms_of_xfns (void)
   DEFSYM (Qfont_parameter, "font-parameter");
   DEFSYM (Qmono, "mono");
   DEFSYM (Qassq_delete_all, "assq-delete-all");
+  DEFSYM (Qx_set_frame_size_and_position_1, "x-set-frame-size-and-position-1");
+  DEFSYM (Qx_set_frame_size_and_position_2, "x-set-frame-size-and-position-2");
+  DEFSYM (Qx_set_frame_size_and_position_3, "x-set-frame-size-and-position-3");
 
 #ifdef USE_CAIRO
   DEFSYM (Qpdf, "pdf");
@@ -8065,6 +8293,7 @@ syms_of_xfns (void)
   defsubr (&Sx_set_mouse_absolute_pixel_position);
   defsubr (&Sx_wm_set_size_hint);
   defsubr (&Sx_create_frame);
+  defsubr (&Sx_set_frame_size_and_position);
   defsubr (&Sx_open_connection);
   defsubr (&Sx_close_connection);
   defsubr (&Sx_display_list);

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-31 15:44                                                                                                                 ` martin rudalics
@ 2020-01-31 22:22                                                                                                                   ` Dmitry Gutov
  2020-02-01  9:35                                                                                                                     ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-01-31 22:22 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 31.01.2020 18:44, martin rudalics wrote:
>  > Considering scaling was only a problem for GTK, that doesn't sound
>  > like success. Anyway, resizing normal undecorated frames in GTK seems
>  > to work just as well now. Resizing child frame (with scaling on) is
>  > still broken (but looks a bit different, no jumping around, at least).
> 
> Presumably resizing child frames is still broken with scaling off too.

I somehow forgot we had that problem with GTK builds. There is a change:

I can now resize a child frame with the mouse to a size *smaller* than 
it was originally. As well as move its top-left corner, within certain 
parameters. Further than that, either Emacs stops me, or the right (or 
bottom, or both) border hides from view.

>  > With GTK build frame resizing also doesn't honor non-pixelwise
>  > resizing. When frame-resize-pixelwise is nil, resizing routinely eats
>  > into internal borders (right and bottom ones).
> 
> Right.  I'll attach a patch that fixes it. 

That seems fixed, thank you.

> Maybe we'll have to
> investigate the size hints issue next.  The whole emacsgtkfixed.c stuff
> (which I do not understand) troubles me considerably.  Could you try
> building with GTK 2?

Done that.

The GTK 2 build seems all-around fine, with almost none of the issues 
described in this thread: child frames both move and resize fine.

It works fine with scaling aside from thin scrollbars and small toolbar 
icons (Lucid has basically the same issues).

It has similar mouse-resizing problems with undecorated frames, but your 
recent patch seems to have fixed that as well.

So I think we could recommend using it as the workaround.

>  >> (benchmark 1 `(x-set-frame-size-and-position ,test-frame nil nil 50 
> 50))
>  >>
>  >> => 0.100523s
>  >
>  > Seems like a possible improvement, but still much slower than 
> set-frame-position with the GTK build.
> 
> Neither of these benchmarks seems meaningful in the first place.  What
> would it measure?

The seemingly slowest part of operations "show popup" and "reposition 
popup". FWIW, it certain situations a popup will have to be repositioned 
every time the user types something.

> Maybe tumashu can check with a version that uses
> 'x-set-frame-size-and-position' whether it's still too slow on non-GTK
> builds.

I'd welcome such a test, yes.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-01-31 22:22                                                                                                                   ` Dmitry Gutov
@ 2020-02-01  9:35                                                                                                                     ` martin rudalics
  2020-02-05  1:39                                                                                                                       ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-01  9:35 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 3309 bytes --]

 > I somehow forgot we had that problem with GTK builds.

It's the problem that sparked this thread.

 > There is a change:
 >
 > I can now resize a child frame with the mouse to a size *smaller* than
 > it was originally. As well as move its top-left corner, within certain
 > parameters. Further than that, either Emacs stops me, or the right (or
 > bottom, or both) border hides from view.

This hints at some ill max_width and/or max_height size hints.  Are
both, width and height, constrained?  Can you re-enlarge a child frame
once you have shrunk it?  Does making the initial child frame very large
give you more room to move?

 > The GTK 2 build seems all-around fine, with almost none of the issues described in this thread: child frames both move and resize fine.
 >
 > It works fine with scaling aside from thin scrollbars and small toolbar icons (Lucid has basically the same issues).

We should be able to fix these - after all, some people still build with
GTK 2.

 > It has similar mouse-resizing problems with undecorated frames, but your recent patch seems to have fixed that as well.
 >
 > So I think we could recommend using it as the workaround.

"One" workaround, hopefully.

 > The seemingly slowest part of operations "show popup" and "reposition
 > popup". FWIW, it certain situations a popup will have to be
 > repositioned every time the user types something.

It will neither measure the time Emacs needs for redrawing the popup nor
the time for exposing the part of the parent frame that gets revealed.

 >> Maybe tumashu can check with a version that uses
 >> 'x-set-frame-size-and-position' whether it's still too slow on non-GTK
 >> builds.
 >
 > I'd welcome such a test, yes.

tumashu, if you have any questions, please ask.


Meanwhile, let's try to proceed on two axes:

(1) Pursue the previous idea to use X calls instead of gtk calls for
resizing child frames.  For this purpose, on top of mouse+xfns.diff
please change the

	gdk_window_move_resize
	  (window, left / scale, top / scale, new_pixel_width / scale,
	   new_pixel_height / scale);

call to

       if (FRAME_PARENT_FRAME (f))
	XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
			   left / scale, top / scale, new_pixel_width / scale,
			   new_pixel_height / scale);
       else
	gdk_window_move_resize
	  (window, left / scale, top / scale, new_pixel_width / scale,
	   new_pixel_height / scale);

If this works but gives problem with scaling, then drop all " / scale"
instances in the XMoveResizeWindow call.

(2) Look into the size hints issue.  I suspect that what we see here is
Bug#8919 raising its ugly head again.  To fix that bug, Jan has
rewritten XSetWMNormalHints to use his XSetWMSizeHints from
emacsgtkfixed.c, which is a gross hack in a dual sense: It (i) replaces
an X function (ii) for the purpose of fixing the behavior of a gtk
function.

Let's try the following.  Apply the attached frame-size-history.diff
from a pristine repository.  Then start with 'test-frame' created, eval
the following forms (positions and sizes may need adapting)

(setq frame-size-history '(100))
(x-set-frame-size-and-position test-frame 400 200 100 50)
(frame--size-history test-frame)
(display-buffer "*frame-size-history*")

and post the history here (unless your Emacs crashed before).

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: frame-size-history.diff --]
[-- Type: text/x-patch; name="frame-size-history.diff", Size: 42895 bytes --]

diff --git a/lisp/frame.el b/lisp/frame.el
index 16ee7580f8..6b9823b59f 100644
--- a/lisp/frame.el
+++ b/lisp/frame.el
@@ -1659,7 +1659,7 @@ frame--size-history
 	(when (eq (car entry) frame)
           (pop entry)
           (insert (format "%s" (pop entry)))
-          (move-to-column 24 t)
+          (move-to-column 32 t)
           (while entry
             (insert (format " %s" (pop entry))))
           (insert "\n")))
diff --git a/lisp/mouse.el b/lisp/mouse.el
index e58a2e6da1..9a0e2b28e4 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -552,7 +552,7 @@ mouse-drag-mode-line
              (not (eq (window-frame minibuffer-window) frame))))
       ;; Drag frame when the window is on the bottom of its frame and
       ;; there is no minibuffer window below.
-      (mouse-drag-frame start-event 'move)))))
+      (mouse-drag-frame-move start-event)))))
 
 (defun mouse-drag-header-line (start-event)
   "Change the height of a window by dragging on its header line.
@@ -569,7 +569,7 @@ mouse-drag-header-line
         (mouse-drag-line start-event 'header)
       (let ((frame (window-frame window)))
         (when (frame-parameter frame 'drag-with-header-line)
-          (mouse-drag-frame start-event 'move))))))
+          (mouse-drag-frame-move start-event))))))
 
 (defun mouse-drag-vertical-line (start-event)
   "Change the width of a window by dragging on a vertical line.
@@ -577,46 +577,7 @@ mouse-drag-vertical-line
   (interactive "e")
   (mouse-drag-line start-event 'vertical))
 \f
-(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move)
-  "Helper function for `mouse-drag-frame'."
-  (let* ((frame-x-y (frame-position frame))
-         (frame-x (car frame-x-y))
-         (frame-y (cdr frame-x-y))
-         alist)
-    (if (> x-diff 0)
-        (when x-move
-          (setq x-diff (min x-diff frame-x))
-          (setq x-move (- frame-x x-diff)))
-      (let* ((min-width (frame-windows-min-size frame t nil t))
-             (min-diff (max 0 (- (frame-inner-width frame) min-width))))
-        (setq x-diff (max x-diff (- min-diff)))
-        (when x-move
-          (setq x-move (+ frame-x (- x-diff))))))
-
-    (if (> y-diff 0)
-        (when y-move
-          (setq y-diff (min y-diff frame-y))
-          (setq y-move (- frame-y y-diff)))
-      (let* ((min-height (frame-windows-min-size frame nil nil t))
-             (min-diff (max 0 (- (frame-inner-height frame) min-height))))
-        (setq y-diff (max y-diff (- min-diff)))
-        (when y-move
-          (setq y-move (+ frame-y (- y-diff))))))
-
-    (unless (zerop x-diff)
-      (when x-move
-        (push `(left . ,x-move) alist))
-      (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff)))
-            alist))
-    (unless (zerop y-diff)
-      (when y-move
-        (push `(top . ,y-move) alist))
-      (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff)))
-            alist))
-    (when alist
-      (modify-frame-parameters frame alist))))
-
-(defun mouse-drag-frame (start-event part)
+(defun mouse-drag-frame-resize (start-event part)
   "Drag a frame or one of its edges with the mouse.
 START-EVENT is the starting mouse event of the drag action.  Its
 position window denotes the frame that will be dragged.
@@ -635,9 +596,168 @@ mouse-drag-frame
          (frame (if (window-live-p window)
                     (window-frame window)
                   window))
-         (width (frame-native-width frame))
-         (height (frame-native-height frame))
-         ;; PARENT is the parent frame of FRAME or, if FRAME is a
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+         (x-left first-left)
+         (first-top (cdr first-pos))
+         (x-top first-top)
+	 (first-width (frame-text-width frame))
+         (x-width first-width)
+	 (first-height (frame-text-height frame))
+         (x-height first-height)
+	 ;; Don't let FRAME become less large than the size needed to
+	 ;; fit all of its windows.
+	 (min-text-width
+	  (+ (frame-windows-min-size frame t nil t)
+	     (- (frame-inner-width frame) first-width)))
+	 (min-text-height
+	  (+ (frame-windows-min-size frame nil nil t)
+	     (- (frame-inner-height frame) first-height)))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
+         ;; top-level frame, FRAME's workarea.
+         (parent (frame-parent frame))
+         (parent-edges
+          (if parent
+              (frame-edges parent)
+            (let* ((attributes
+                    (car (display-monitor-attributes-list)))
+                   (workarea (assq 'workarea attributes)))
+              (and workarea
+                   `(,(nth 1 workarea) ,(nth 2 workarea)
+                     ,(+ (nth 1 workarea) (nth 3 workarea))
+                     ,(+ (nth 2 workarea) (nth 4 workarea)))))))
+         (parent-left (and parent-edges (nth 0 parent-edges)))
+         (parent-top (and parent-edges (nth 1 parent-edges)))
+         (parent-right (and parent-edges (nth 2 parent-edges)))
+         (parent-bottom (and parent-edges (nth 3 parent-edges)))
+	 ;; Drag types.  drag-left/drag-right and drag-top/drag-bottom
+	 ;; are mutually exclusive.
+	 (drag-left (memq part '(bottom-left left top-left)))
+	 (drag-top (memq part '(top-left top top-right)))
+	 (drag-right (memq part '(top-right right bottom-right)))
+	 (drag-bottom (memq part '(bottom-right bottom bottom-left)))
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         (exitfun nil)
+         (move
+          (lambda (event)
+            (interactive "e")
+            (when (consp event)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+		     alist)
+                ;; We never want to warp the mouse position here.  When
+                ;; moving the mouse leftward or upward, then with a wide
+                ;; border the calculated left or top position of the
+                ;; frame could drop to a value less than zero depending
+                ;; on where precisely the mouse within the border.  We
+                ;; guard against this by never allowing the frame to
+                ;; move to a position less than zero here.  No such
+                ;; precautions are used for the right and bottom borders
+                ;; so with a large internal border parts of that border
+                ;; may disappear.
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (progn
+                      (when (and drag-left (>= last-x parent-left)
+                                 (>= (- first-width left) min-text-width))
+		        (setq x-left (max (+ first-left left) 0))
+		        (setq x-width (- first-width left)))
+	              (when (and drag-top (>= last-y parent-top)
+                                 (>= (- first-height top) min-text-height))
+		        (setq x-top (max 0 (+ first-top top)))
+		        (setq x-height (- first-height top)))
+	              (when (and drag-right (<= last-x parent-right)
+                                 (>= (+ first-width left) min-text-width))
+		        (setq x-width (+ first-width left)))
+	              (when (and drag-bottom (<= last-y parent-bottom)
+                                 (>= (+ first-height top) min-text-height))
+		        (setq x-height (+ first-height top)))
+                      (x-set-frame-size-and-position
+                       frame x-width x-height x-left x-top))
+                  (when (and drag-left (>= last-x parent-left)
+                             (>= (- first-width left) min-text-width))
+		    (push `(left . ,(max (+ first-left left) 0)) alist)
+		    (push `(width . (text-pixels . ,(- first-width left)))
+                          alist))
+	          (when (and drag-top (>= last-y parent-top)
+                             (>= (- first-height top) min-text-height))
+		    (push `(top . ,(max 0 (+ first-top top))) alist)
+		    (push `(height . (text-pixels . ,(- first-height top)))
+                          alist))
+	          (when (and drag-right (<= last-x parent-right)
+                             (>= (+ first-width left) min-text-width))
+		    (push `(width . (text-pixels . ,(+ first-width left)))
+                          alist))
+	          (when (and drag-bottom (<= last-y parent-bottom)
+                             (>= (+ first-height top) min-text-height))
+		    (push `(height . (text-pixels . ,(+ first-height top)))
+                          alist))
+	          (modify-frame-parameters frame alist))))))
+         (old-track-mouse track-mouse))
+    ;; Start tracking.  The special value 'dragging' signals the
+    ;; display engine to freeze the mouse pointer shape for as long
+    ;; as we drag.
+    (setq track-mouse 'dragging)
+    ;; Loop reading events and sampling the position of the mouse.
+    (setq exitfun
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [scroll-bar-movement] #'ignore)
+             (define-key map [mouse-movement] move)
+             ;; Swallow drag-mouse-1 events to avoid selecting some other window.
+             (define-key map [drag-mouse-1]
+               (lambda () (interactive) (funcall exitfun)))
+             ;; Some of the events will of course end up looked up
+             ;; with a mode-line, header-line or vertical-line prefix ...
+             (define-key map [mode-line] map)
+             (define-key map [header-line] map)
+             (define-key map [vertical-line] map)
+             ;; ... and some maybe even with a right- or bottom-divider
+             ;; prefix.
+             (define-key map [right-divider] map)
+             (define-key map [bottom-divider] map)
+             map)
+           t (lambda () (setq track-mouse old-track-mouse))))))
+
+(defun mouse-drag-frame-move (start-event)
+  "Drag a frame or one of its edges with the mouse.
+START-EVENT is the starting mouse event of the drag action.  Its
+position window denotes the frame that will be dragged.
+
+PART specifies the part that has been dragged and must be one of
+the symbols `left', `top', `right', `bottom', `top-left',
+`top-right', `bottom-left', `bottom-right' to drag an internal
+border or edge.  If PART equals `move', this means to move the
+frame with the mouse."
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
+  (let* ((echo-keystrokes 0)
+	 (start (event-start start-event))
+         (window (posn-window start))
+         ;; FRAME is the frame to drag.
+         (frame (if (window-live-p window)
+                    (window-frame window)
+                  window))
+         (native-width (frame-native-width frame))
+         (native-height (frame-native-height frame))
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+	 (first-top (cdr first-pos))
+	 (first-width (frame-text-width frame))
+	 (first-height (frame-text-height frame))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
          ;; top-level frame, FRAME's workarea.
          (parent (frame-parent frame))
          (parent-edges
@@ -654,19 +774,16 @@ mouse-drag-frame
          (parent-top (and parent-edges (nth 1 parent-edges)))
          (parent-right (and parent-edges (nth 2 parent-edges)))
          (parent-bottom (and parent-edges (nth 3 parent-edges)))
-         ;; `pos-x' and `pos-y' record the x- and y-coordinates of the
-	 ;; last sampled mouse position.  Note that we sample absolute
-	 ;; mouse positions to avoid that moving the mouse from one
-	 ;; frame into another gets into our way.  `last-x' and `last-y'
-	 ;; records the x- and y-coordinates of the previously sampled
-	 ;; position.  The differences between `last-x' and `pos-x' as
-	 ;; well as `last-y' and `pos-y' determine the amount the mouse
-	 ;; has been dragged between the last two samples.
-         pos-x-y pos-x pos-y
-         (last-x-y (mouse-absolute-pixel-position))
-         (last-x (car last-x-y))
-         (last-y (cdr last-x-y))
-         ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         ;; `snap-width' (maybe also a yet to be provided `snap-height')
+         ;; could become floats to handle proportionality wrt PARENT.
+         ;; We don't do any checks on this parameter so far.
+         (snap-width (frame-parameter frame 'snap-width))
+	 ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
          ;; mouse position when FRAME snapped.  As soon as the
          ;; difference between `pos-x' and `snap-x' (or `pos-y' and
          ;; `snap-y') exceeds the value of FRAME's `snap-width'
@@ -678,176 +795,144 @@ mouse-drag-frame
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (setq pos-x-y (mouse-absolute-pixel-position))
-              (setq pos-x (car pos-x-y))
-              (setq pos-y (cdr pos-x-y))
-              (cond
-               ((eq part 'left)
-                (mouse-resize-frame frame (- last-x pos-x) 0 t))
-               ((eq part 'top)
-                (mouse-resize-frame frame 0 (- last-y pos-y) nil t))
-               ((eq part 'right)
-                (mouse-resize-frame frame (- pos-x last-x) 0))
-               ((eq part 'bottom)
-                (mouse-resize-frame frame 0 (- pos-y last-y)))
-               ((eq part 'top-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- last-y pos-y) t t))
-               ((eq part 'top-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- last-y pos-y) nil t))
-               ((eq part 'bottom-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- pos-y last-y) t))
-               ((eq part 'bottom-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- pos-y last-y)))
-               ((eq part 'move)
-                (let* ((old-position (frame-position frame))
-                       (old-left (car old-position))
-                       (old-top (cdr old-position))
-                       (left (+ old-left (- pos-x last-x)))
-                       (top (+ old-top (- pos-y last-y)))
-                       right bottom
-                       ;; `snap-width' (maybe also a yet to be provided
-                       ;; `snap-height') could become floats to handle
-                       ;; proportionality wrt PARENT.  We don't do any
-                       ;; checks on this parameter so far.
-                       (snap-width (frame-parameter frame 'snap-width)))
-                  ;; Docking and constraining.
-                  (when (and (numberp snap-width) parent-edges)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+                     right bottom)
+		(setq left (+ first-left left))
+		(setq top (+ first-top top))
+                ;; Docking and constraining.
+                (when (and (numberp snap-width) parent-edges)
+                  (cond
+                   ;; Docking at the left parent edge.
+                   ((< last-x first-x)
                     (cond
-                     ;; Docking at the left parent edge.
-                     ((< pos-x last-x)
-                      (cond
-                       ((and (> left parent-left)
-                             (<= (- left parent-left) snap-width))
-                        ;; Snap when the mouse moved leftward and
-                        ;; FRAME's left edge would end up within
-                        ;; `snap-width' pixels from PARENT's left edge.
-                        (setq snap-x pos-x)
-                        (setq left parent-left))
-                       ((and (<= left parent-left)
-                             (<= (- parent-left left) snap-width)
-                             snap-x (<= (- snap-x pos-x) snap-width))
-                        ;; Stay snapped when the mouse moved leftward
-                        ;; but not more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq left parent-left))
-                       (t
-                        ;; Unsnap when the mouse moved more than
-                        ;; `snap-width' pixels leftward from the time
-                        ;; FRAME snapped.
-                        (setq snap-x nil))))
-                     ((> pos-x last-x)
-                      (setq right (+ left width))
-                      (cond
-                       ((and (< right parent-right)
-                             (<= (- parent-right right) snap-width))
-                        ;; Snap when the mouse moved rightward and
-                        ;; FRAME's right edge would end up within
-                        ;; `snap-width' pixels from PARENT's right edge.
-                        (setq snap-x pos-x)
-                        (setq left (- parent-right width)))
-                       ((and (>= right parent-right)
-                             (<= (- right parent-right) snap-width)
-                             snap-x (<= (- pos-x snap-x) snap-width))
-                        ;; Stay snapped when the mouse moved rightward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq left (- parent-right width)))
-                       (t
-                        ;; Unsnap when the mouse moved rightward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-x nil)))))
-
+                     ((and (> left parent-left)
+                           (<= (- left parent-left) snap-width))
+                      ;; Snap when the mouse moved leftward and FRAME's
+                      ;; left edge would end up within `snap-width'
+                      ;; pixels from PARENT's left edge.
+                      (setq snap-x last-x)
+                      (setq left parent-left))
+                     ((and (<= left parent-left)
+                           (<= (- parent-left left) snap-width)
+                           snap-x (<= (- snap-x last-x) snap-width))
+                      ;; Stay snapped when the mouse moved leftward but
+                      ;; not more than `snap-width' pixels from the time
+                      ;; FRAME snapped.
+                      (setq left parent-left))
+                     (t
+                      ;; Unsnap when the mouse moved more than
+                      ;; `snap-width' pixels leftward from the time
+                      ;; FRAME snapped.
+                      (setq snap-x nil))))
+                   ((> last-x first-x)
+                    (setq right (+ left native-width))
                     (cond
-                     ((< pos-y last-y)
-                      (cond
-                       ((and (> top parent-top)
-                             (<= (- top parent-top) snap-width))
-                        ;; Snap when the mouse moved upward and FRAME's
-                        ;; top edge would end up within `snap-width'
-                        ;; pixels from PARENT's top edge.
-                        (setq snap-y pos-y)
-                        (setq top parent-top))
-                       ((and (<= top parent-top)
-                             (<= (- parent-top top) snap-width)
-                             snap-y (<= (- snap-y pos-y) snap-width))
-                        ;; Stay snapped when the mouse moved upward but
-                        ;; not more more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq top parent-top))
-                       (t
-                        ;; Unsnap when the mouse moved upward more than
-                        ;; `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))
-                     ((> pos-y last-y)
-                      (setq bottom (+ top height))
-                      (cond
-                       ((and (< bottom parent-bottom)
-                             (<= (- parent-bottom bottom) snap-width))
-                        ;; Snap when the mouse moved downward and
-                        ;; FRAME's bottom edge would end up within
-                        ;; `snap-width' pixels from PARENT's bottom
-                        ;; edge.
-                        (setq snap-y pos-y)
-                        (setq top (- parent-bottom height)))
-                       ((and (>= bottom parent-bottom)
-                             (<= (- bottom parent-bottom) snap-width)
-                             snap-y (<= (- pos-y snap-y) snap-width))
-                        ;; Stay snapped when the mouse moved downward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq top (- parent-bottom height)))
-                       (t
-                        ;; Unsnap when the mouse moved downward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))))
-
-                  ;; If requested, constrain FRAME's draggable areas to
-                  ;; PARENT's edges.  The `top-visible' parameter should
-                  ;; be set when FRAME has a draggable header-line.  If
-                  ;; set to a number, it ascertains that the top of
-                  ;; FRAME is always constrained to the top of PARENT
-                  ;; and that at least as many pixels of FRAME as
-                  ;; specified by that number are visible on each of the
-                  ;; three remaining sides of PARENT.
-                  ;;
-                  ;; The `bottom-visible' parameter should be set when
-                  ;; FRAME has a draggable mode-line.  If set to a
-                  ;; number, it ascertains that the bottom of FRAME is
-                  ;; always constrained to the bottom of PARENT and that
-                  ;; at least as many pixels of FRAME as specified by
-                  ;; that number are visible on each of the three
-                  ;; remaining sides of PARENT.
-                  (let ((par (frame-parameter frame 'top-visible))
-                        bottom-visible)
-                    (unless par
-                      (setq par (frame-parameter frame 'bottom-visible))
-                      (setq bottom-visible t))
-                    (when (and (numberp par) parent-edges)
-                      (setq left
-                            (max (min (- parent-right par) left)
-                                 (+ (- parent-left width) par)))
-                      (setq top
-                            (if bottom-visible
-                                (min (max top (- parent-top (- height par)))
-                                     (- parent-bottom height))
-                              (min (max top parent-top)
-                                   (- parent-bottom par))))))
-
-                  ;; Use `modify-frame-parameters' since `left' and
-                  ;; `top' may want to move FRAME out of its PARENT.
-                  (modify-frame-parameters
-                   frame
-                   `((left . (+ ,left)) (top . (+ ,top)))))))
-              (setq last-x pos-x)
-              (setq last-y pos-y))))
-         (old-track-mouse track-mouse))
+                     ((and (< right parent-right)
+                           (<= (- parent-right right) snap-width))
+                      ;; Snap when the mouse moved rightward and FRAME's
+                      ;; right edge would end up within `snap-width'
+                      ;; pixels from PARENT's right edge.
+                      (setq snap-x last-x)
+                      (setq left (- parent-right native-width)))
+                     ((and (>= right parent-right)
+                           (<= (- right parent-right) snap-width)
+                           snap-x (<= (- last-x snap-x) snap-width))
+                      ;; Stay snapped when the mouse moved rightward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq left (- parent-right native-width)))
+                     (t
+                      ;; Unsnap when the mouse moved rightward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-x nil)))))
+                  (cond
+                   ((< last-y first-y)
+                    (cond
+                     ((and (> top parent-top)
+                           (<= (- top parent-top) snap-width))
+                      ;; Snap when the mouse moved upward and FRAME's
+                      ;; top edge would end up within `snap-width'
+                      ;; pixels from PARENT's top edge.
+                      (setq snap-y last-y)
+                      (setq top parent-top))
+                     ((and (<= top parent-top)
+                           (<= (- parent-top top) snap-width)
+                           snap-y (<= (- snap-y last-y) snap-width))
+                      ;; Stay snapped when the mouse moved upward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top parent-top))
+                     (t
+                      ;; Unsnap when the mouse moved upward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))
+                   ((> last-y first-y)
+                    (setq bottom (+ top native-height))
+                    (cond
+                     ((and (< bottom parent-bottom)
+                           (<= (- parent-bottom bottom) snap-width))
+                      ;; Snap when the mouse moved downward and FRAME's
+                      ;; bottom edge would end up within `snap-width'
+                      ;; pixels from PARENT's bottom edge.
+                      (setq snap-y last-y)
+                      (setq top (- parent-bottom native-height)))
+                     ((and (>= bottom parent-bottom)
+                           (<= (- bottom parent-bottom) snap-width)
+                           snap-y (<= (- last-y snap-y) snap-width))
+                      ;; Stay snapped when the mouse moved downward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top (- parent-bottom native-height)))
+                     (t
+                      ;; Unsnap when the mouse moved downward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))))
+
+                ;; If requested, constrain FRAME's draggable areas to
+                ;; PARENT's edges.  The `top-visible' parameter should
+                ;; be set when FRAME has a draggable header-line.  If
+                ;; set to a number, it ascertains that the top of FRAME
+                ;; is always constrained to the top of PARENT and that
+                ;; at least as many pixels of FRAME as specified by that
+                ;; number are visible on each of the three remaining
+                ;; sides of PARENT.
+                ;;
+                ;; The `bottom-visible' parameter should be set when
+                ;; FRAME has a draggable mode-line.  If set to a number,
+                ;; it ascertains that the bottom of FRAME is always
+                ;; constrained to the bottom of PARENT and that at least
+                ;; as many pixels of FRAME as specified by that number
+                ;; are visible on each of the three remaining sides of
+                ;; PARENT.
+                (let ((par (frame-parameter frame 'top-visible))
+                      bottom-visible)
+                  (unless par
+                    (setq par (frame-parameter frame 'bottom-visible))
+                    (setq bottom-visible t))
+                  (when (and (numberp par) parent-edges)
+                    (setq left
+                          (max (min (- parent-right par) left)
+                               (+ (- parent-left native-width) par)))
+                    (setq top
+                          (if bottom-visible
+                              (min (max top (- parent-top (- native-height par)))
+                                   (- parent-bottom native-height))
+                            (min (max top parent-top)
+                                 (- parent-bottom par))))))
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (x-set-frame-size-and-position
+                     frame first-width first-height left top)
+                  ;; Use `modify-frame-parameters' since `left' and `top'
+                  ;; may want to move FRAME out of its PARENT.
+                  (modify-frame-parameters frame `((left . (+ ,left)) (top . (+ ,top)))))))))
+	 (old-track-mouse track-mouse))
     ;; Start tracking.  The special value 'dragging' signals the
     ;; display engine to freeze the mouse pointer shape for as long
     ;; as we drag.
@@ -879,49 +964,49 @@ mouse-drag-left-edge
   "Drag left edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'left))
+  (mouse-drag-frame-resize start-event 'left))
 
 (defun mouse-drag-top-left-corner (start-event)
   "Drag top left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-left))
+  (mouse-drag-frame-resize start-event 'top-left))
 
 (defun mouse-drag-top-edge (start-event)
   "Drag top edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top))
+  (mouse-drag-frame-resize start-event 'top))
 
 (defun mouse-drag-top-right-corner (start-event)
   "Drag top right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-right))
+  (mouse-drag-frame-resize start-event 'top-right))
 
 (defun mouse-drag-right-edge (start-event)
   "Drag right edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'right))
+  (mouse-drag-frame-resize start-event 'right))
 
 (defun mouse-drag-bottom-right-corner (start-event)
   "Drag bottom right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-right))
+  (mouse-drag-frame-resize start-event 'bottom-right))
 
 (defun mouse-drag-bottom-edge (start-event)
   "Drag bottom edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom))
+  (mouse-drag-frame-resize start-event 'bottom))
 
 (defun mouse-drag-bottom-left-corner (start-event)
   "Drag bottom left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-left))
+  (mouse-drag-frame-resize start-event 'bottom-left))
 
 (defcustom mouse-select-region-move-to-beginning nil
   "Effect of selecting a region extending backward from double click.
diff --git a/src/emacsgtkfixed.c b/src/emacsgtkfixed.c
index ea9465d553..8aef7a958e 100644
--- a/src/emacsgtkfixed.c
+++ b/src/emacsgtkfixed.c
@@ -242,6 +242,14 @@ XSetWMSizeHints (Display *d,
 
   XChangeProperty (d, w, prop, XA_WM_SIZE_HINTS, 32, PropModeReplace,
 		   (unsigned char *) data, 18);
+
+  if (f && FRAME_PARENT_FRAME (f))
+    frame_size_history_add
+      (f, Quser_size, hints->width, hints->height,
+       Fcons (make_fixnum (hints->base_width),
+	      Fcons (make_fixnum (hints->base_height),
+		     list4i (hints->min_width, hints->min_height,
+			     hints->max_width, hints->max_height))));
 }
 
 /* Override this X11 function.
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..69597c6843 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1401,8 +1401,7 @@ x_wm_set_size_hint (struct frame *f, long int flags, bool user_position)
      to a race condition.  See the thread at
      https://lists.gnu.org/r/emacs-devel/2008-10/msg00033.html  */
   if (NILP (Vafter_init_time)
-      || !FRAME_GTK_OUTER_WIDGET (f)
-      || FRAME_PARENT_FRAME (f))
+      || !FRAME_GTK_OUTER_WIDGET (f))
     return;
 
   XSETFRAME (frame, f);
diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..d8387f66bf 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4203,6 +4203,231 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
  return unbind_to (count, frame);
 }
 
+
+static void
+x_set_frame_size_and_position (struct frame *f, int width, int height, int left, int top)
+{
+  int unit_width = FRAME_COLUMN_WIDTH (f);
+  int unit_height = FRAME_LINE_HEIGHT (f);
+  int old_pixel_width = FRAME_PIXEL_WIDTH (f);
+  int old_pixel_height = FRAME_PIXEL_HEIGHT (f);
+  int old_cols = FRAME_COLS (f);
+  int old_lines = FRAME_LINES (f);
+  int new_pixel_width = FRAME_TEXT_TO_PIXEL_WIDTH (f, width);
+  int new_pixel_height = FRAME_TEXT_TO_PIXEL_HEIGHT (f, height);
+  struct window *r = XWINDOW (FRAME_ROOT_WINDOW (f));
+  int old_windows_width = WINDOW_PIXEL_WIDTH (r);
+  int old_windows_height
+    = (WINDOW_PIXEL_HEIGHT (r)
+       + ((FRAME_HAS_MINIBUF_P (f) && !FRAME_MINIBUF_ONLY_P (f))
+	  ? WINDOW_PIXEL_HEIGHT (XWINDOW (FRAME_MINIBUF_WINDOW (f)))
+	  : 0));
+  int new_windows_width, new_windows_height;
+  int new_cols, new_lines;
+  Lisp_Object frame;
+  bool old_frame_resize_pixelwise = frame_resize_pixelwise;
+#ifdef USE_GTK
+  int scale = xg_get_scale (f);
+#endif
+
+  XSETFRAME (frame, f);
+
+  frame_size_history_add
+    (f, Qx_set_frame_size_and_position_1, new_pixel_width,
+     new_pixel_height, Qnil);
+
+  new_windows_width = new_pixel_width - 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
+  new_windows_height = (new_pixel_height
+			- FRAME_TOP_MARGIN_HEIGHT (f)
+			- 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
+  new_cols = width / unit_width;
+  new_lines = height / unit_height;
+
+  if (FRAME_WINDOW_P (f) && f->can_set_window_size)
+    {
+      block_input ();
+
+#ifdef USE_GTK
+      GdkWindow *window = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+
+      frame_resize_pixelwise = true;
+      x_wm_set_size_hint (f, 0, true);
+      frame_resize_pixelwise = old_frame_resize_pixelwise;
+      gdk_window_move_resize
+	(window, left / scale, top / scale, new_pixel_width / scale,
+	 new_pixel_height / scale);
+      SET_FRAME_GARBAGED (f);
+      cancel_mouse_face (f);
+
+      if (FRAME_VISIBLE_P (f))
+	{
+	  /* Must call this to flush out events */
+	  (void)gtk_events_pending ();
+	  gdk_flush ();
+	  x_wait_for_event (f, ConfigureNotify);
+	}
+      else
+	{
+	  change_frame_size (f, new_pixel_width, new_pixel_height,
+			     false, true, false, true);
+	  x_sync (f);
+	}
+#else
+      f->win_gravity = NorthWestGravity;
+      frame_resize_pixelwise = true;
+      x_wm_set_size_hint (f, 0, true);
+      frame_resize_pixelwise = old_frame_resize_pixelwise;
+
+      XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+			 left, top, new_pixel_width,
+			 new_pixel_height + FRAME_MENUBAR_HEIGHT (f));
+
+      SET_FRAME_GARBAGED (f);
+
+      if (FRAME_VISIBLE_P (f))
+	x_wait_for_event (f, ConfigureNotify);
+      else
+	{
+	  change_frame_size (f,new_pixel_width, new_pixel_height,
+			     false, true, false, true);
+	  x_sync (f);
+	}
+
+      x_clear_under_internal_border (f);
+#endif
+
+      mark_window_cursors_off (XWINDOW (f->root_window));
+
+      cancel_mouse_face (f);
+
+      unblock_input ();
+
+      do_pending_window_change (false);
+
+      f->resized_p = true;
+
+      block_input ();
+    }
+
+  if (new_windows_width != old_windows_width)
+    {
+      resize_frame_windows (f, new_windows_width, true);
+      if (WINDOWP (f->tab_bar_window))
+	{
+	  XWINDOW (f->tab_bar_window)->pixel_width = new_windows_width;
+	  XWINDOW (f->tab_bar_window)->total_cols
+	    = new_windows_width / unit_width;
+	}
+
+#if defined (HAVE_WINDOW_SYSTEM) && ! defined (HAVE_EXT_TOOL_BAR)
+      if (WINDOWP (f->tool_bar_window))
+	{
+	  XWINDOW (f->tool_bar_window)->pixel_width = new_windows_width;
+	  XWINDOW (f->tool_bar_window)->total_cols
+	    = new_windows_width / unit_width;
+	}
+#endif
+    }
+  else if (new_cols != old_cols)
+    call2 (Qwindow__pixel_to_total, frame, Qt);
+
+  if (new_windows_height != old_windows_height
+      || WINDOW_TOP_PIXEL_EDGE (r) != FRAME_TOP_MARGIN_HEIGHT (f))
+    resize_frame_windows (f, new_windows_height, false);
+  else if (new_lines != old_lines)
+    call2 (Qwindow__pixel_to_total, frame, Qnil);
+
+  frame_size_history_add
+    (f, Qx_set_frame_size_and_position_3, width, height, Qnil);
+
+  /* Assign new sizes.  */
+  FRAME_TEXT_WIDTH (f) = width;
+  FRAME_TEXT_HEIGHT (f) = height;
+  FRAME_PIXEL_WIDTH (f) = new_pixel_width;
+  FRAME_PIXEL_HEIGHT (f) = new_pixel_height;
+  SET_FRAME_COLS (f, new_cols);
+  SET_FRAME_LINES (f, new_lines);
+  SET_FRAME_COLS (f, new_cols);
+  SET_FRAME_LINES (f, new_lines);
+
+  {
+    struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
+    int text_area_x, text_area_y, text_area_width, text_area_height;
+
+    window_box (w, TEXT_AREA, &text_area_x, &text_area_y, &text_area_width,
+		&text_area_height);
+    if (w->cursor.x >= text_area_x + text_area_width)
+      w->cursor.hpos = w->cursor.x = 0;
+    if (w->cursor.y >= text_area_y + text_area_height)
+      w->cursor.vpos = w->cursor.y = 0;
+  }
+
+  /* Sanitize window sizes.  */
+  sanitize_window_sizes (Qt);
+  sanitize_window_sizes (Qnil);
+
+  adjust_frame_glyphs (f);
+  calculate_costs (f);
+  SET_FRAME_GARBAGED (f);
+
+  /* A frame was "resized" if one of its pixelsizes changed, even if its
+     X window wasn't resized at all.  */
+  f->resized_p = (new_pixel_width != old_pixel_width
+		  || new_pixel_height != old_pixel_height);
+
+  unblock_input ();
+}
+
+
+DEFUN ("x-set-frame-size-and-position", Fx_set_frame_size_and_position,
+       Sx_set_frame_size_and_position, 0, 5, 0,
+       doc: /* Set position of FRAME to (LEFT, TOP) and size to (WIDTH, HEIGHT).
+FRAME must be a live frame and defaults to the selected one.  The
+remaining values must be either nil (which means to not change the
+respective size or position) or specify a pixel value.  */)
+  (Lisp_Object frame, Lisp_Object width, Lisp_Object height,
+   Lisp_Object left, Lisp_Object top)
+{
+  struct frame *f = decode_live_frame (frame);
+  int text_width, text_height, outer_left, outer_top;
+
+  if (EQ (width, Qnil))
+    text_width = FRAME_TEXT_WIDTH (f);
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, width);
+      text_width = XFIXNUM (width);
+    }
+
+  if (EQ (height, Qnil))
+    text_height = FRAME_TEXT_HEIGHT (f);
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, height);
+      text_height = XFIXNUM (height);
+    }
+
+  if (EQ (left, Qnil))
+    outer_left = f->left_pos;
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, left);
+      outer_left = XFIXNUM (left);
+    }
+
+  if (EQ (top, Qnil))
+    outer_top = f->top_pos;
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, top);
+      outer_top = XFIXNUM (top);
+    }
+
+  x_set_frame_size_and_position
+    (f, text_width, text_height, outer_left, outer_top);
+
+  return Qnil;
+}
 \f
 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
        doc: /* Internal function called by `color-defined-p'.
@@ -7810,6 +8035,9 @@ syms_of_xfns (void)
   DEFSYM (Qfont_parameter, "font-parameter");
   DEFSYM (Qmono, "mono");
   DEFSYM (Qassq_delete_all, "assq-delete-all");
+  DEFSYM (Qx_set_frame_size_and_position_1, "x-set-frame-size-and-position-1");
+  DEFSYM (Qx_set_frame_size_and_position_2, "x-set-frame-size-and-position-2");
+  DEFSYM (Qx_set_frame_size_and_position_3, "x-set-frame-size-and-position-3");
 
 #ifdef USE_CAIRO
   DEFSYM (Qpdf, "pdf");
@@ -8065,6 +8293,7 @@ syms_of_xfns (void)
   defsubr (&Sx_set_mouse_absolute_pixel_position);
   defsubr (&Sx_wm_set_size_hint);
   defsubr (&Sx_create_frame);
+  defsubr (&Sx_set_frame_size_and_position);
   defsubr (&Sx_open_connection);
   defsubr (&Sx_close_connection);
   defsubr (&Sx_display_list);

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-01  9:35                                                                                                                     ` martin rudalics
@ 2020-02-05  1:39                                                                                                                       ` Dmitry Gutov
  2020-02-05  9:15                                                                                                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-05  1:39 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 01.02.2020 12:35, martin rudalics wrote:
>  > I somehow forgot we had that problem with GTK builds.
> 
> It's the problem that sparked this thread.

Yes, of course.

>  > There is a change:
>  >
>  > I can now resize a child frame with the mouse to a size *smaller* than
>  > it was originally. As well as move its top-left corner, within certain
>  > parameters. Further than that, either Emacs stops me, or the right (or
>  > bottom, or both) border hides from view.
> 
> This hints at some ill max_width and/or max_height size hints.  Are
> both, width and height, constrained?

Yes.

> Can you re-enlarge a child frame
> once you have shrunk it?

Yes, but only within the original bounds.

> Does making the initial child frame very large
> give you more room to move?

Yes, as per the above.

>  > The GTK 2 build seems all-around fine, with almost none of the issues 
> described in this thread: child frames both move and resize fine.
>  >
>  > It works fine with scaling aside from thin scrollbars and small 
> toolbar icons (Lucid has basically the same issues).
> 
> We should be able to fix these - after all, some people still build with
> GTK 2.

Sounds good, but IME GTK2 applications don't work well with scaling. So 
maybe leave it alone unless it's really easy to do.

>  > It has similar mouse-resizing problems with undecorated frames, but 
> your recent patch seems to have fixed that as well.
>  >
>  > So I think we could recommend using it as the workaround.
> 
> "One" workaround, hopefully.

The one all-around good one, so far.

>  > The seemingly slowest part of operations "show popup" and "reposition
>  > popup". FWIW, it certain situations a popup will have to be
>  > repositioned every time the user types something.
> 
> It will neither measure the time Emacs needs for redrawing the popup nor
> the time for exposing the part of the parent frame that gets revealed.

It measures one bottleneck. But, of course, there can be other ones.

> Meanwhile, let's try to proceed on two axes:
> 
> (1) Pursue the previous idea to use X calls instead of gtk calls for
> resizing child frames.  For this purpose, on top of mouse+xfns.diff
> please change the
> 
>      gdk_window_move_resize
>        (window, left / scale, top / scale, new_pixel_width / scale,
>         new_pixel_height / scale);
> 
> call to
> 
>        if (FRAME_PARENT_FRAME (f))
>      XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
>                 left / scale, top / scale, new_pixel_width / scale,
>                 new_pixel_height / scale);
>        else
>      gdk_window_move_resize
>        (window, left / scale, top / scale, new_pixel_width / scale,
>         new_pixel_height / scale);
> 
> If this works but gives problem with scaling, then drop all " / scale"
> instances in the XMoveResizeWindow call.

Didn't help. The patch, as-is, introduced a scaling problem. And 
dropping "/ scale" instances made it go back to the previous stage of 
affairs (resizing is limited by the original child frame bounds).

> (2) Look into the size hints issue.  I suspect that what we see here is
> Bug#8919 raising its ugly head again.  To fix that bug, Jan has
> rewritten XSetWMNormalHints to use his XSetWMSizeHints from
> emacsgtkfixed.c, which is a gross hack in a dual sense: It (i) replaces
> an X function (ii) for the purpose of fixing the behavior of a gtk
> function.
> 
> Let's try the following.  Apply the attached frame-size-history.diff
> from a pristine repository.  Then start with 'test-frame' created, eval
> the following forms (positions and sizes may need adapting)
> 
> (setq frame-size-history '(100))
> (x-set-frame-size-and-position test-frame 400 200 100 50)
> (frame--size-history test-frame)
> (display-buffer "*frame-size-history*")
> 
> and post the history here (unless your Emacs crashed before).

No crash. Does this look right?

Frame size history of #<frame test child-frame 0x55ebb491a630>
x-set-frame-size-and-position-1	 (720 360 448 200) nil
x-set-frame-size-and-position-3	 (720 360 400 200) nil

The child frame got resized to a smaller size, though.

Should I try a bigger width and height? The history looks pretty much 
the same in that case.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-05  1:39                                                                                                                       ` Dmitry Gutov
@ 2020-02-05  9:15                                                                                                                         ` martin rudalics
  2020-02-10  7:06                                                                                                                           ` Dmitry Gutov
  2020-02-10  7:22                                                                                                                           ` Dmitry Gutov
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-02-05  9:15 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 4298 bytes --]

 >> Does making the initial child frame very large
 >> give you more room to move?
 >
 > Yes, as per the above.

So you could make the initial child frame 10000 pixel wide and high and
resizing would never fail?

 >> (1) Pursue the previous idea to use X calls instead of gtk calls for
 >> resizing child frames.  For this purpose, on top of mouse+xfns.diff
 >> please change the
 >>
 >>      gdk_window_move_resize
 >>        (window, left / scale, top / scale, new_pixel_width / scale,
 >>         new_pixel_height / scale);
 >>
 >> call to
 >>
 >>        if (FRAME_PARENT_FRAME (f))
 >>      XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 >>                 left / scale, top / scale, new_pixel_width / scale,
 >>                 new_pixel_height / scale);
 >>        else
 >>      gdk_window_move_resize
 >>        (window, left / scale, top / scale, new_pixel_width / scale,
 >>         new_pixel_height / scale);
 >>
 >> If this works but gives problem with scaling, then drop all " / scale"
 >> instances in the XMoveResizeWindow call.
 >
 > Didn't help. The patch, as-is, introduced a scaling problem. And
 > dropping "/ scale" instances

Which ones did you drop - all?  The ones in the gdk_window_move_resize
call should remain, only the ones from the XMoveResizeWindow call should
be dropped.

 > made it go back to the previous stage of affairs (resizing is limited by the original child frame bounds).
 >
 >> (2) Look into the size hints issue.  I suspect that what we see here is
 >> Bug#8919 raising its ugly head again.  To fix that bug, Jan has
 >> rewritten XSetWMNormalHints to use his XSetWMSizeHints from
 >> emacsgtkfixed.c, which is a gross hack in a dual sense: It (i) replaces
 >> an X function (ii) for the purpose of fixing the behavior of a gtk
 >> function.
 >>
 >> Let's try the following.  Apply the attached frame-size-history.diff
 >> from a pristine repository.  Then start with 'test-frame' created, eval
 >> the following forms (positions and sizes may need adapting)
 >>
 >> (setq frame-size-history '(100))
 >> (x-set-frame-size-and-position test-frame 400 200 100 50)
 >> (frame--size-history test-frame)
 >> (display-buffer "*frame-size-history*")
 >>
 >> and post the history here (unless your Emacs crashed before).
 >
 > No crash. Does this look right?
 >
 > Frame size history of #<frame test child-frame 0x55ebb491a630>
 > x-set-frame-size-and-position-1     (720 360 448 200) nil
 > x-set-frame-size-and-position-3     (720 360 400 200) nil
 >
 > The child frame got resized to a smaller size, though.
 >
 > Should I try a bigger width and height? The history looks pretty much the same in that case.

No.  You apparently don't get anything from the XSetWMSizeHints calls.


I meanwhile installed mutter here.  Debian apparently doesn't resolve
the dependencies well so I had to manually install some additional
gnomish features.  The whole thing still looks incomplete though.

The frame positioning behavior of mutter is a pain for me and renders my
usual Emacs frame setup practically unusable.  It's possibly a
consequence of making borders invisible and having the frame minimize
and maximize when it's pushed against the bottom or top edge of the
display.  Visible child frames never resize, I cannot even shrink them.
Also, I can't get vertical scroll bars for them.  In one case I was told

Window manager warning: Window 0x4a0003d (Terminal) sets an MWM hint indicating it isn't resizable, but sets min size 1 x 1 and max size 2147483647 x 2147483647; this doesn't make much sense.

but I'm not even sure whether these resulted from an Emacs frame - the
max size values are not ours AFAICT.  Also we set MWM hints only from
within non-GTK builds, maybe I've been running one of them.


Anyway, I meanwhile further rewrote the code for mouse dragging and
'x-set-frame-size-and-position', patch attached.  I also added an
interface to the gtk inspector, you can enable it via

(when (fboundp 'x-gtk-debug)
   (x-gtk-debug t))

Maybe you can derive something from running it.  At least here, when
under "visual" turning on "graphics actualizations", I can clearly see
that GTK processes and passes on the resize requests for child frames
(by turning the frame red) and that they are later apparently dismissed
by mutter.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: mouse+xfns.diff --]
[-- Type: text/x-patch; name="mouse+xfns.diff", Size: 43167 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index e58a2e6da1..9a0e2b28e4 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -552,7 +552,7 @@ mouse-drag-mode-line
              (not (eq (window-frame minibuffer-window) frame))))
       ;; Drag frame when the window is on the bottom of its frame and
       ;; there is no minibuffer window below.
-      (mouse-drag-frame start-event 'move)))))
+      (mouse-drag-frame-move start-event)))))
 
 (defun mouse-drag-header-line (start-event)
   "Change the height of a window by dragging on its header line.
@@ -569,7 +569,7 @@ mouse-drag-header-line
         (mouse-drag-line start-event 'header)
       (let ((frame (window-frame window)))
         (when (frame-parameter frame 'drag-with-header-line)
-          (mouse-drag-frame start-event 'move))))))
+          (mouse-drag-frame-move start-event))))))
 
 (defun mouse-drag-vertical-line (start-event)
   "Change the width of a window by dragging on a vertical line.
@@ -577,46 +577,7 @@ mouse-drag-vertical-line
   (interactive "e")
   (mouse-drag-line start-event 'vertical))
 \f
-(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move)
-  "Helper function for `mouse-drag-frame'."
-  (let* ((frame-x-y (frame-position frame))
-         (frame-x (car frame-x-y))
-         (frame-y (cdr frame-x-y))
-         alist)
-    (if (> x-diff 0)
-        (when x-move
-          (setq x-diff (min x-diff frame-x))
-          (setq x-move (- frame-x x-diff)))
-      (let* ((min-width (frame-windows-min-size frame t nil t))
-             (min-diff (max 0 (- (frame-inner-width frame) min-width))))
-        (setq x-diff (max x-diff (- min-diff)))
-        (when x-move
-          (setq x-move (+ frame-x (- x-diff))))))
-
-    (if (> y-diff 0)
-        (when y-move
-          (setq y-diff (min y-diff frame-y))
-          (setq y-move (- frame-y y-diff)))
-      (let* ((min-height (frame-windows-min-size frame nil nil t))
-             (min-diff (max 0 (- (frame-inner-height frame) min-height))))
-        (setq y-diff (max y-diff (- min-diff)))
-        (when y-move
-          (setq y-move (+ frame-y (- y-diff))))))
-
-    (unless (zerop x-diff)
-      (when x-move
-        (push `(left . ,x-move) alist))
-      (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff)))
-            alist))
-    (unless (zerop y-diff)
-      (when y-move
-        (push `(top . ,y-move) alist))
-      (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff)))
-            alist))
-    (when alist
-      (modify-frame-parameters frame alist))))
-
-(defun mouse-drag-frame (start-event part)
+(defun mouse-drag-frame-resize (start-event part)
   "Drag a frame or one of its edges with the mouse.
 START-EVENT is the starting mouse event of the drag action.  Its
 position window denotes the frame that will be dragged.
@@ -635,9 +596,168 @@ mouse-drag-frame
          (frame (if (window-live-p window)
                     (window-frame window)
                   window))
-         (width (frame-native-width frame))
-         (height (frame-native-height frame))
-         ;; PARENT is the parent frame of FRAME or, if FRAME is a
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+         (x-left first-left)
+         (first-top (cdr first-pos))
+         (x-top first-top)
+	 (first-width (frame-text-width frame))
+         (x-width first-width)
+	 (first-height (frame-text-height frame))
+         (x-height first-height)
+	 ;; Don't let FRAME become less large than the size needed to
+	 ;; fit all of its windows.
+	 (min-text-width
+	  (+ (frame-windows-min-size frame t nil t)
+	     (- (frame-inner-width frame) first-width)))
+	 (min-text-height
+	  (+ (frame-windows-min-size frame nil nil t)
+	     (- (frame-inner-height frame) first-height)))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
+         ;; top-level frame, FRAME's workarea.
+         (parent (frame-parent frame))
+         (parent-edges
+          (if parent
+              (frame-edges parent)
+            (let* ((attributes
+                    (car (display-monitor-attributes-list)))
+                   (workarea (assq 'workarea attributes)))
+              (and workarea
+                   `(,(nth 1 workarea) ,(nth 2 workarea)
+                     ,(+ (nth 1 workarea) (nth 3 workarea))
+                     ,(+ (nth 2 workarea) (nth 4 workarea)))))))
+         (parent-left (and parent-edges (nth 0 parent-edges)))
+         (parent-top (and parent-edges (nth 1 parent-edges)))
+         (parent-right (and parent-edges (nth 2 parent-edges)))
+         (parent-bottom (and parent-edges (nth 3 parent-edges)))
+	 ;; Drag types.  drag-left/drag-right and drag-top/drag-bottom
+	 ;; are mutually exclusive.
+	 (drag-left (memq part '(bottom-left left top-left)))
+	 (drag-top (memq part '(top-left top top-right)))
+	 (drag-right (memq part '(top-right right bottom-right)))
+	 (drag-bottom (memq part '(bottom-right bottom bottom-left)))
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         (exitfun nil)
+         (move
+          (lambda (event)
+            (interactive "e")
+            (when (consp event)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+		     alist)
+                ;; We never want to warp the mouse position here.  When
+                ;; moving the mouse leftward or upward, then with a wide
+                ;; border the calculated left or top position of the
+                ;; frame could drop to a value less than zero depending
+                ;; on where precisely the mouse within the border.  We
+                ;; guard against this by never allowing the frame to
+                ;; move to a position less than zero here.  No such
+                ;; precautions are used for the right and bottom borders
+                ;; so with a large internal border parts of that border
+                ;; may disappear.
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (progn
+                      (when (and drag-left (>= last-x parent-left)
+                                 (>= (- first-width left) min-text-width))
+		        (setq x-left (max (+ first-left left) 0))
+		        (setq x-width (- first-width left)))
+	              (when (and drag-top (>= last-y parent-top)
+                                 (>= (- first-height top) min-text-height))
+		        (setq x-top (max 0 (+ first-top top)))
+		        (setq x-height (- first-height top)))
+	              (when (and drag-right (<= last-x parent-right)
+                                 (>= (+ first-width left) min-text-width))
+		        (setq x-width (+ first-width left)))
+	              (when (and drag-bottom (<= last-y parent-bottom)
+                                 (>= (+ first-height top) min-text-height))
+		        (setq x-height (+ first-height top)))
+                      (x-set-frame-size-and-position
+                       frame x-width x-height x-left x-top))
+                  (when (and drag-left (>= last-x parent-left)
+                             (>= (- first-width left) min-text-width))
+		    (push `(left . ,(max (+ first-left left) 0)) alist)
+		    (push `(width . (text-pixels . ,(- first-width left)))
+                          alist))
+	          (when (and drag-top (>= last-y parent-top)
+                             (>= (- first-height top) min-text-height))
+		    (push `(top . ,(max 0 (+ first-top top))) alist)
+		    (push `(height . (text-pixels . ,(- first-height top)))
+                          alist))
+	          (when (and drag-right (<= last-x parent-right)
+                             (>= (+ first-width left) min-text-width))
+		    (push `(width . (text-pixels . ,(+ first-width left)))
+                          alist))
+	          (when (and drag-bottom (<= last-y parent-bottom)
+                             (>= (+ first-height top) min-text-height))
+		    (push `(height . (text-pixels . ,(+ first-height top)))
+                          alist))
+	          (modify-frame-parameters frame alist))))))
+         (old-track-mouse track-mouse))
+    ;; Start tracking.  The special value 'dragging' signals the
+    ;; display engine to freeze the mouse pointer shape for as long
+    ;; as we drag.
+    (setq track-mouse 'dragging)
+    ;; Loop reading events and sampling the position of the mouse.
+    (setq exitfun
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [scroll-bar-movement] #'ignore)
+             (define-key map [mouse-movement] move)
+             ;; Swallow drag-mouse-1 events to avoid selecting some other window.
+             (define-key map [drag-mouse-1]
+               (lambda () (interactive) (funcall exitfun)))
+             ;; Some of the events will of course end up looked up
+             ;; with a mode-line, header-line or vertical-line prefix ...
+             (define-key map [mode-line] map)
+             (define-key map [header-line] map)
+             (define-key map [vertical-line] map)
+             ;; ... and some maybe even with a right- or bottom-divider
+             ;; prefix.
+             (define-key map [right-divider] map)
+             (define-key map [bottom-divider] map)
+             map)
+           t (lambda () (setq track-mouse old-track-mouse))))))
+
+(defun mouse-drag-frame-move (start-event)
+  "Drag a frame or one of its edges with the mouse.
+START-EVENT is the starting mouse event of the drag action.  Its
+position window denotes the frame that will be dragged.
+
+PART specifies the part that has been dragged and must be one of
+the symbols `left', `top', `right', `bottom', `top-left',
+`top-right', `bottom-left', `bottom-right' to drag an internal
+border or edge.  If PART equals `move', this means to move the
+frame with the mouse."
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
+  (let* ((echo-keystrokes 0)
+	 (start (event-start start-event))
+         (window (posn-window start))
+         ;; FRAME is the frame to drag.
+         (frame (if (window-live-p window)
+                    (window-frame window)
+                  window))
+         (native-width (frame-native-width frame))
+         (native-height (frame-native-height frame))
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+	 (first-top (cdr first-pos))
+	 (first-width (frame-text-width frame))
+	 (first-height (frame-text-height frame))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
          ;; top-level frame, FRAME's workarea.
          (parent (frame-parent frame))
          (parent-edges
@@ -654,19 +774,16 @@ mouse-drag-frame
          (parent-top (and parent-edges (nth 1 parent-edges)))
          (parent-right (and parent-edges (nth 2 parent-edges)))
          (parent-bottom (and parent-edges (nth 3 parent-edges)))
-         ;; `pos-x' and `pos-y' record the x- and y-coordinates of the
-	 ;; last sampled mouse position.  Note that we sample absolute
-	 ;; mouse positions to avoid that moving the mouse from one
-	 ;; frame into another gets into our way.  `last-x' and `last-y'
-	 ;; records the x- and y-coordinates of the previously sampled
-	 ;; position.  The differences between `last-x' and `pos-x' as
-	 ;; well as `last-y' and `pos-y' determine the amount the mouse
-	 ;; has been dragged between the last two samples.
-         pos-x-y pos-x pos-y
-         (last-x-y (mouse-absolute-pixel-position))
-         (last-x (car last-x-y))
-         (last-y (cdr last-x-y))
-         ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         ;; `snap-width' (maybe also a yet to be provided `snap-height')
+         ;; could become floats to handle proportionality wrt PARENT.
+         ;; We don't do any checks on this parameter so far.
+         (snap-width (frame-parameter frame 'snap-width))
+	 ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
          ;; mouse position when FRAME snapped.  As soon as the
          ;; difference between `pos-x' and `snap-x' (or `pos-y' and
          ;; `snap-y') exceeds the value of FRAME's `snap-width'
@@ -678,176 +795,144 @@ mouse-drag-frame
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (setq pos-x-y (mouse-absolute-pixel-position))
-              (setq pos-x (car pos-x-y))
-              (setq pos-y (cdr pos-x-y))
-              (cond
-               ((eq part 'left)
-                (mouse-resize-frame frame (- last-x pos-x) 0 t))
-               ((eq part 'top)
-                (mouse-resize-frame frame 0 (- last-y pos-y) nil t))
-               ((eq part 'right)
-                (mouse-resize-frame frame (- pos-x last-x) 0))
-               ((eq part 'bottom)
-                (mouse-resize-frame frame 0 (- pos-y last-y)))
-               ((eq part 'top-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- last-y pos-y) t t))
-               ((eq part 'top-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- last-y pos-y) nil t))
-               ((eq part 'bottom-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- pos-y last-y) t))
-               ((eq part 'bottom-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- pos-y last-y)))
-               ((eq part 'move)
-                (let* ((old-position (frame-position frame))
-                       (old-left (car old-position))
-                       (old-top (cdr old-position))
-                       (left (+ old-left (- pos-x last-x)))
-                       (top (+ old-top (- pos-y last-y)))
-                       right bottom
-                       ;; `snap-width' (maybe also a yet to be provided
-                       ;; `snap-height') could become floats to handle
-                       ;; proportionality wrt PARENT.  We don't do any
-                       ;; checks on this parameter so far.
-                       (snap-width (frame-parameter frame 'snap-width)))
-                  ;; Docking and constraining.
-                  (when (and (numberp snap-width) parent-edges)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+                     right bottom)
+		(setq left (+ first-left left))
+		(setq top (+ first-top top))
+                ;; Docking and constraining.
+                (when (and (numberp snap-width) parent-edges)
+                  (cond
+                   ;; Docking at the left parent edge.
+                   ((< last-x first-x)
                     (cond
-                     ;; Docking at the left parent edge.
-                     ((< pos-x last-x)
-                      (cond
-                       ((and (> left parent-left)
-                             (<= (- left parent-left) snap-width))
-                        ;; Snap when the mouse moved leftward and
-                        ;; FRAME's left edge would end up within
-                        ;; `snap-width' pixels from PARENT's left edge.
-                        (setq snap-x pos-x)
-                        (setq left parent-left))
-                       ((and (<= left parent-left)
-                             (<= (- parent-left left) snap-width)
-                             snap-x (<= (- snap-x pos-x) snap-width))
-                        ;; Stay snapped when the mouse moved leftward
-                        ;; but not more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq left parent-left))
-                       (t
-                        ;; Unsnap when the mouse moved more than
-                        ;; `snap-width' pixels leftward from the time
-                        ;; FRAME snapped.
-                        (setq snap-x nil))))
-                     ((> pos-x last-x)
-                      (setq right (+ left width))
-                      (cond
-                       ((and (< right parent-right)
-                             (<= (- parent-right right) snap-width))
-                        ;; Snap when the mouse moved rightward and
-                        ;; FRAME's right edge would end up within
-                        ;; `snap-width' pixels from PARENT's right edge.
-                        (setq snap-x pos-x)
-                        (setq left (- parent-right width)))
-                       ((and (>= right parent-right)
-                             (<= (- right parent-right) snap-width)
-                             snap-x (<= (- pos-x snap-x) snap-width))
-                        ;; Stay snapped when the mouse moved rightward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq left (- parent-right width)))
-                       (t
-                        ;; Unsnap when the mouse moved rightward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-x nil)))))
-
+                     ((and (> left parent-left)
+                           (<= (- left parent-left) snap-width))
+                      ;; Snap when the mouse moved leftward and FRAME's
+                      ;; left edge would end up within `snap-width'
+                      ;; pixels from PARENT's left edge.
+                      (setq snap-x last-x)
+                      (setq left parent-left))
+                     ((and (<= left parent-left)
+                           (<= (- parent-left left) snap-width)
+                           snap-x (<= (- snap-x last-x) snap-width))
+                      ;; Stay snapped when the mouse moved leftward but
+                      ;; not more than `snap-width' pixels from the time
+                      ;; FRAME snapped.
+                      (setq left parent-left))
+                     (t
+                      ;; Unsnap when the mouse moved more than
+                      ;; `snap-width' pixels leftward from the time
+                      ;; FRAME snapped.
+                      (setq snap-x nil))))
+                   ((> last-x first-x)
+                    (setq right (+ left native-width))
                     (cond
-                     ((< pos-y last-y)
-                      (cond
-                       ((and (> top parent-top)
-                             (<= (- top parent-top) snap-width))
-                        ;; Snap when the mouse moved upward and FRAME's
-                        ;; top edge would end up within `snap-width'
-                        ;; pixels from PARENT's top edge.
-                        (setq snap-y pos-y)
-                        (setq top parent-top))
-                       ((and (<= top parent-top)
-                             (<= (- parent-top top) snap-width)
-                             snap-y (<= (- snap-y pos-y) snap-width))
-                        ;; Stay snapped when the mouse moved upward but
-                        ;; not more more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq top parent-top))
-                       (t
-                        ;; Unsnap when the mouse moved upward more than
-                        ;; `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))
-                     ((> pos-y last-y)
-                      (setq bottom (+ top height))
-                      (cond
-                       ((and (< bottom parent-bottom)
-                             (<= (- parent-bottom bottom) snap-width))
-                        ;; Snap when the mouse moved downward and
-                        ;; FRAME's bottom edge would end up within
-                        ;; `snap-width' pixels from PARENT's bottom
-                        ;; edge.
-                        (setq snap-y pos-y)
-                        (setq top (- parent-bottom height)))
-                       ((and (>= bottom parent-bottom)
-                             (<= (- bottom parent-bottom) snap-width)
-                             snap-y (<= (- pos-y snap-y) snap-width))
-                        ;; Stay snapped when the mouse moved downward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq top (- parent-bottom height)))
-                       (t
-                        ;; Unsnap when the mouse moved downward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))))
-
-                  ;; If requested, constrain FRAME's draggable areas to
-                  ;; PARENT's edges.  The `top-visible' parameter should
-                  ;; be set when FRAME has a draggable header-line.  If
-                  ;; set to a number, it ascertains that the top of
-                  ;; FRAME is always constrained to the top of PARENT
-                  ;; and that at least as many pixels of FRAME as
-                  ;; specified by that number are visible on each of the
-                  ;; three remaining sides of PARENT.
-                  ;;
-                  ;; The `bottom-visible' parameter should be set when
-                  ;; FRAME has a draggable mode-line.  If set to a
-                  ;; number, it ascertains that the bottom of FRAME is
-                  ;; always constrained to the bottom of PARENT and that
-                  ;; at least as many pixels of FRAME as specified by
-                  ;; that number are visible on each of the three
-                  ;; remaining sides of PARENT.
-                  (let ((par (frame-parameter frame 'top-visible))
-                        bottom-visible)
-                    (unless par
-                      (setq par (frame-parameter frame 'bottom-visible))
-                      (setq bottom-visible t))
-                    (when (and (numberp par) parent-edges)
-                      (setq left
-                            (max (min (- parent-right par) left)
-                                 (+ (- parent-left width) par)))
-                      (setq top
-                            (if bottom-visible
-                                (min (max top (- parent-top (- height par)))
-                                     (- parent-bottom height))
-                              (min (max top parent-top)
-                                   (- parent-bottom par))))))
-
-                  ;; Use `modify-frame-parameters' since `left' and
-                  ;; `top' may want to move FRAME out of its PARENT.
-                  (modify-frame-parameters
-                   frame
-                   `((left . (+ ,left)) (top . (+ ,top)))))))
-              (setq last-x pos-x)
-              (setq last-y pos-y))))
-         (old-track-mouse track-mouse))
+                     ((and (< right parent-right)
+                           (<= (- parent-right right) snap-width))
+                      ;; Snap when the mouse moved rightward and FRAME's
+                      ;; right edge would end up within `snap-width'
+                      ;; pixels from PARENT's right edge.
+                      (setq snap-x last-x)
+                      (setq left (- parent-right native-width)))
+                     ((and (>= right parent-right)
+                           (<= (- right parent-right) snap-width)
+                           snap-x (<= (- last-x snap-x) snap-width))
+                      ;; Stay snapped when the mouse moved rightward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq left (- parent-right native-width)))
+                     (t
+                      ;; Unsnap when the mouse moved rightward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-x nil)))))
+                  (cond
+                   ((< last-y first-y)
+                    (cond
+                     ((and (> top parent-top)
+                           (<= (- top parent-top) snap-width))
+                      ;; Snap when the mouse moved upward and FRAME's
+                      ;; top edge would end up within `snap-width'
+                      ;; pixels from PARENT's top edge.
+                      (setq snap-y last-y)
+                      (setq top parent-top))
+                     ((and (<= top parent-top)
+                           (<= (- parent-top top) snap-width)
+                           snap-y (<= (- snap-y last-y) snap-width))
+                      ;; Stay snapped when the mouse moved upward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top parent-top))
+                     (t
+                      ;; Unsnap when the mouse moved upward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))
+                   ((> last-y first-y)
+                    (setq bottom (+ top native-height))
+                    (cond
+                     ((and (< bottom parent-bottom)
+                           (<= (- parent-bottom bottom) snap-width))
+                      ;; Snap when the mouse moved downward and FRAME's
+                      ;; bottom edge would end up within `snap-width'
+                      ;; pixels from PARENT's bottom edge.
+                      (setq snap-y last-y)
+                      (setq top (- parent-bottom native-height)))
+                     ((and (>= bottom parent-bottom)
+                           (<= (- bottom parent-bottom) snap-width)
+                           snap-y (<= (- last-y snap-y) snap-width))
+                      ;; Stay snapped when the mouse moved downward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top (- parent-bottom native-height)))
+                     (t
+                      ;; Unsnap when the mouse moved downward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))))
+
+                ;; If requested, constrain FRAME's draggable areas to
+                ;; PARENT's edges.  The `top-visible' parameter should
+                ;; be set when FRAME has a draggable header-line.  If
+                ;; set to a number, it ascertains that the top of FRAME
+                ;; is always constrained to the top of PARENT and that
+                ;; at least as many pixels of FRAME as specified by that
+                ;; number are visible on each of the three remaining
+                ;; sides of PARENT.
+                ;;
+                ;; The `bottom-visible' parameter should be set when
+                ;; FRAME has a draggable mode-line.  If set to a number,
+                ;; it ascertains that the bottom of FRAME is always
+                ;; constrained to the bottom of PARENT and that at least
+                ;; as many pixels of FRAME as specified by that number
+                ;; are visible on each of the three remaining sides of
+                ;; PARENT.
+                (let ((par (frame-parameter frame 'top-visible))
+                      bottom-visible)
+                  (unless par
+                    (setq par (frame-parameter frame 'bottom-visible))
+                    (setq bottom-visible t))
+                  (when (and (numberp par) parent-edges)
+                    (setq left
+                          (max (min (- parent-right par) left)
+                               (+ (- parent-left native-width) par)))
+                    (setq top
+                          (if bottom-visible
+                              (min (max top (- parent-top (- native-height par)))
+                                   (- parent-bottom native-height))
+                            (min (max top parent-top)
+                                 (- parent-bottom par))))))
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (x-set-frame-size-and-position
+                     frame first-width first-height left top)
+                  ;; Use `modify-frame-parameters' since `left' and `top'
+                  ;; may want to move FRAME out of its PARENT.
+                  (modify-frame-parameters frame `((left . (+ ,left)) (top . (+ ,top)))))))))
+	 (old-track-mouse track-mouse))
     ;; Start tracking.  The special value 'dragging' signals the
     ;; display engine to freeze the mouse pointer shape for as long
     ;; as we drag.
@@ -879,49 +964,49 @@ mouse-drag-left-edge
   "Drag left edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'left))
+  (mouse-drag-frame-resize start-event 'left))
 
 (defun mouse-drag-top-left-corner (start-event)
   "Drag top left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-left))
+  (mouse-drag-frame-resize start-event 'top-left))
 
 (defun mouse-drag-top-edge (start-event)
   "Drag top edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top))
+  (mouse-drag-frame-resize start-event 'top))
 
 (defun mouse-drag-top-right-corner (start-event)
   "Drag top right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-right))
+  (mouse-drag-frame-resize start-event 'top-right))
 
 (defun mouse-drag-right-edge (start-event)
   "Drag right edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'right))
+  (mouse-drag-frame-resize start-event 'right))
 
 (defun mouse-drag-bottom-right-corner (start-event)
   "Drag bottom right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-right))
+  (mouse-drag-frame-resize start-event 'bottom-right))
 
 (defun mouse-drag-bottom-edge (start-event)
   "Drag bottom edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom))
+  (mouse-drag-frame-resize start-event 'bottom))
 
 (defun mouse-drag-bottom-left-corner (start-event)
   "Drag bottom left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-left))
+  (mouse-drag-frame-resize start-event 'bottom-left))
 
 (defcustom mouse-select-region-move-to-beginning nil
   "Effect of selecting a region extending backward from double click.
diff --git a/src/emacsgtkfixed.c b/src/emacsgtkfixed.c
index ea9465d553..cc04596837 100644
--- a/src/emacsgtkfixed.c
+++ b/src/emacsgtkfixed.c
@@ -242,6 +242,21 @@ XSetWMSizeHints (Display *d,
 
   XChangeProperty (d, w, prop, XA_WM_SIZE_HINTS, 32, PropModeReplace,
 		   (unsigned char *) data, 18);
+
+  if (f && FRAME_PARENT_FRAME (f))
+    frame_size_history_add
+      (f, Quser_size, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
+       listn (10,
+	      make_fixnum (hints->base_width),
+	      make_fixnum (hints->base_height),
+	      make_fixnum (hints->width_inc),
+	      make_fixnum (hints->height_inc),
+	      make_fixnum (hints->min_width),
+	      make_fixnum (hints->min_height),
+	      make_fixnum (f->output_data.x->size_hints.min_width),
+	      make_fixnum (f->output_data.x->size_hints.min_height),
+	      make_fixnum (hints->max_width),
+	      make_fixnum (hints->max_height)));
 }
 
 /* Override this X11 function.
diff --git a/src/frame.c b/src/frame.c
index 88d6f22fc0..7cc9399b31 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -374,7 +374,7 @@ DEFUN ("frame-windows-min-size", Fframe_windows_min_size,
  * additionally limit the minimum frame height to a value large enough
  * to support the menu bar, the mode line, and the echo area.
  */
-static int
+int
 frame_windows_min_size (Lisp_Object frame, Lisp_Object horizontal,
 			Lisp_Object ignore, Lisp_Object pixelwise)
 {
diff --git a/src/frame.h b/src/frame.h
index 6ab690c0ff..42acd92418 100644
--- a/src/frame.h
+++ b/src/frame.h
@@ -1647,6 +1647,7 @@ #define EMACS_CLASS "Emacs"
 extern void free_frame_menubar (struct frame *);
 extern bool frame_ancestor_p (struct frame *af, struct frame *df);
 extern enum internal_border_part frame_internal_border_part (struct frame *f, int x, int y);
+extern int frame_windows_min_size (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object);
 
 #if defined HAVE_X_WINDOWS
 extern void x_wm_set_icon_position (struct frame *, int, int);
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..d85107448d 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1401,8 +1401,7 @@ x_wm_set_size_hint (struct frame *f, long int flags, bool user_position)
      to a race condition.  See the thread at
      https://lists.gnu.org/r/emacs-devel/2008-10/msg00033.html  */
   if (NILP (Vafter_init_time)
-      || !FRAME_GTK_OUTER_WIDGET (f)
-      || FRAME_PARENT_FRAME (f))
+      || !FRAME_GTK_OUTER_WIDGET (f))
     return;
 
   XSETFRAME (frame, f);
@@ -1429,7 +1428,7 @@ x_wm_set_size_hint (struct frame *f, long int flags, bool user_position)
   size_hints = f->output_data.x->size_hints;
   hint_flags = f->output_data.x->hint_flags;
 
-  hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE;
+  hint_flags |= GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE | GDK_HINT_MAX_SIZE;
   size_hints.width_inc = frame_resize_pixelwise ? 1 : FRAME_COLUMN_WIDTH (f);
   size_hints.height_inc = frame_resize_pixelwise ? 1 : FRAME_LINE_HEIGHT (f);
 
@@ -1445,6 +1444,8 @@ x_wm_set_size_hint (struct frame *f, long int flags, bool user_position)
   size_hints.base_height = base_height;
   size_hints.min_width  = base_width;
   size_hints.min_height = base_height;
+  size_hints.max_width = 10000;
+  size_hints.max_height = 10000;
 
   /* These currently have a one to one mapping with the X values, but I
      don't think we should rely on that.  */
diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..5a43797d25 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4203,6 +4203,163 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
  return unbind_to (count, frame);
 }
 
+
+static void
+x_window_move_resize (struct frame *f, int width, int height, int left, int top)
+{
+  int old_pixel_width = FRAME_PIXEL_WIDTH (f);
+  int old_pixel_height = FRAME_PIXEL_HEIGHT (f);
+  int new_pixel_width, new_pixel_height;
+  int min_windows_width, min_windows_height;
+  Lisp_Object frame;
+  bool inhibit_horizontal, inhibit_vertical;
+  bool old_frame_resize_pixelwise = frame_resize_pixelwise;
+#ifdef USE_GTK
+  int scale = xg_get_scale (f);
+#endif
+
+  XSETFRAME (frame, f);
+
+  frame_size_history_add (f, Qx_move_resize_1, width, height, Qnil);
+
+  min_windows_width = frame_windows_min_size (frame, Qt, Qnil, Qt);
+  min_windows_height = frame_windows_min_size (frame, Qnil, Qnil, Qt);
+
+  inhibit_horizontal = frame_inhibit_resize (f, true, Qnil);
+  inhibit_vertical =  frame_inhibit_resize (f, false, Qnil);
+
+  new_pixel_width = (inhibit_horizontal
+		     ? old_pixel_width
+		     : max (FRAME_TEXT_TO_PIXEL_WIDTH (f, width),
+			    min_windows_width
+			    + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)));
+  new_pixel_height = (inhibit_vertical
+		      ? old_pixel_height
+		      : max (FRAME_TEXT_TO_PIXEL_HEIGHT (f, height),
+			     min_windows_height
+			     + FRAME_TOP_MARGIN_HEIGHT (f)
+			     + 2 * FRAME_INTERNAL_BORDER_WIDTH (f)));
+
+  if (FRAME_WINDOW_P (f) && f->can_set_window_size)
+    {
+      block_input ();
+
+#ifdef USE_GTK
+      GdkWindow *window = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+
+      frame_resize_pixelwise = true;
+      x_wm_set_size_hint (f, 0, true);
+      frame_resize_pixelwise = old_frame_resize_pixelwise;
+      FRAME_RIF (f)->clear_under_internal_border (f);
+
+      gdk_window_move_resize
+	(window, left / scale, top / scale, new_pixel_width / scale,
+	 new_pixel_height / scale);
+
+      SET_FRAME_GARBAGED (f);
+
+      frame_size_history_add (f, Qx_move_resize_2, width, height, Qnil);
+
+      if (FRAME_VISIBLE_P (f))
+	{
+	  /* Must call this to flush out events */
+	  (void)gtk_events_pending ();
+	  gdk_flush ();
+	  x_wait_for_event (f, ConfigureNotify);
+	}
+      else
+	{
+	  change_frame_size (f, new_pixel_width, new_pixel_height,
+			     false, true, false, true);
+	  x_sync (f);
+	}
+#else
+      f->win_gravity = NorthWestGravity;
+      frame_resize_pixelwise = true;
+      x_wm_set_size_hint (f, 0, true);
+      frame_resize_pixelwise = old_frame_resize_pixelwise;
+
+      XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
+			 left, top, new_pixel_width,
+			 new_pixel_height + FRAME_MENUBAR_HEIGHT (f));
+
+      SET_FRAME_GARBAGED (f);
+
+      frame_size_history_add (f, Qx_move_resize_2, width, height, Qnil);
+
+      if (FRAME_VISIBLE_P (f))
+	x_wait_for_event (f, ConfigureNotify);
+      else
+	{
+	  change_frame_size (f,new_pixel_width, new_pixel_height,
+			     false, true, false, true);
+	  x_sync (f);
+	}
+
+      x_clear_under_internal_border (f);
+#endif
+
+      mark_window_cursors_off (XWINDOW (f->root_window));
+      cancel_mouse_face (f);
+      unblock_input ();
+
+      do_pending_window_change (false);
+      f->resized_p = true;
+
+      frame_size_history_add (f, Qx_move_resize_3, width, height, Qnil);
+    }
+}
+
+
+DEFUN ("x-set-frame-size-and-position", Fx_set_frame_size_and_position,
+       Sx_set_frame_size_and_position, 0, 5, 0,
+       doc: /* Set position of FRAME to (LEFT, TOP) and size to (WIDTH, HEIGHT).
+FRAME must be a live frame and defaults to the selected one.  The
+remaining values must be either nil (which means to not change the
+respective size or position) or specify a pixel value.  */)
+  (Lisp_Object frame, Lisp_Object width, Lisp_Object height,
+   Lisp_Object left, Lisp_Object top)
+{
+  struct frame *f = decode_live_frame (frame);
+  int text_width, text_height, outer_left, outer_top;
+
+  if (EQ (width, Qnil))
+    text_width = FRAME_TEXT_WIDTH (f);
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, width);
+      text_width = XFIXNUM (width);
+    }
+
+  if (EQ (height, Qnil))
+    text_height = FRAME_TEXT_HEIGHT (f);
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, height);
+      text_height = XFIXNUM (height);
+    }
+
+  if (EQ (left, Qnil))
+    outer_left = f->left_pos;
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, left);
+      outer_left = XFIXNUM (left);
+    }
+
+  if (EQ (top, Qnil))
+    outer_top = f->top_pos;
+  else
+    {
+      CHECK_TYPE_RANGED_INTEGER (int, top);
+      outer_top = XFIXNUM (top);
+    }
+
+  x_window_move_resize
+    (f, text_width, text_height, outer_left, outer_top);
+
+  return Qnil;
+}
 \f
 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
        doc: /* Internal function called by `color-defined-p'.
@@ -7742,6 +7899,20 @@ frames (each of which corresponds to one page).  Each frame should be
 #endif	/* USE_GTK */
 #endif	/* USE_CAIRO */
 
+#ifdef USE_GTK
+DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0,
+       doc: /* Toggle interactive GTK debugging.   */)
+  (Lisp_Object enable)
+{
+  gboolean enable_debug = !NILP (enable);
+
+  block_input ();
+  gtk_window_set_interactive_debugging (enable_debug);
+  unblock_input ();
+
+  return NILP (enable) ? Qnil : Qt;
+}
+#endif	/* USE_GTK */
 \f
 /***********************************************************************
 			    Initialization
@@ -7810,6 +7981,9 @@ syms_of_xfns (void)
   DEFSYM (Qfont_parameter, "font-parameter");
   DEFSYM (Qmono, "mono");
   DEFSYM (Qassq_delete_all, "assq-delete-all");
+  DEFSYM (Qx_move_resize_1, "x-move-resize-1");
+  DEFSYM (Qx_move_resize_2, "x-move-resize-2");
+  DEFSYM (Qx_move_resize_3, "x-move-resize-3");
 
 #ifdef USE_CAIRO
   DEFSYM (Qpdf, "pdf");
@@ -8065,6 +8239,7 @@ syms_of_xfns (void)
   defsubr (&Sx_set_mouse_absolute_pixel_position);
   defsubr (&Sx_wm_set_size_hint);
   defsubr (&Sx_create_frame);
+  defsubr (&Sx_set_frame_size_and_position);
   defsubr (&Sx_open_connection);
   defsubr (&Sx_close_connection);
   defsubr (&Sx_display_list);
@@ -8101,4 +8276,7 @@ syms_of_xfns (void)
   defsubr (&Sx_print_frames_dialog);
 #endif
 #endif
+#ifdef USE_GTK
+  defsubr (&Sx_gtk_debug);
+#endif
 }

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-05  9:15                                                                                                                         ` martin rudalics
@ 2020-02-10  7:06                                                                                                                           ` Dmitry Gutov
  2020-02-10 17:53                                                                                                                             ` martin rudalics
  2020-02-10  7:22                                                                                                                           ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-10  7:06 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 05.02.2020 12:15, martin rudalics wrote:
>  >> Does making the initial child frame very large
>  >> give you more room to move?
>  >
>  > Yes, as per the above.
> 
> So you could make the initial child frame 10000 pixel wide and high and
> resizing would never fail?

Seems like it.

But set-frame-size still does nothing, so I wouldn't know how to take 
advantage of this discovery programmatically.

>  >> (1) Pursue the previous idea to use X calls instead of gtk calls for
>  >> resizing child frames.  For this purpose, on top of mouse+xfns.diff
>  >> please change the
>  >>
>  >>      gdk_window_move_resize
>  >>        (window, left / scale, top / scale, new_pixel_width / scale,
>  >>         new_pixel_height / scale);
>  >>
>  >> call to
>  >>
>  >>        if (FRAME_PARENT_FRAME (f))
>  >>      XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
>  >>                 left / scale, top / scale, new_pixel_width / scale,
>  >>                 new_pixel_height / scale);
>  >>        else
>  >>      gdk_window_move_resize
>  >>        (window, left / scale, top / scale, new_pixel_width / scale,
>  >>         new_pixel_height / scale);
>  >>
>  >> If this works but gives problem with scaling, then drop all " / scale"
>  >> instances in the XMoveResizeWindow call.
>  >
>  > Didn't help. The patch, as-is, introduced a scaling problem. And
>  > dropping "/ scale" instances
> 
> Which ones did you drop - all?  The ones in the gdk_window_move_resize
> call should remain, only the ones from the XMoveResizeWindow call should
> be dropped.

Only the ones from the XMoveResizeWindow call.

> I meanwhile installed mutter here.  Debian apparently doesn't resolve
> the dependencies well so I had to manually install some additional
> gnomish features.  The whole thing still looks incomplete though.

Sounds like trying a Live CD might work better for you. That leaves the 
question of how to get an Emacs build on there, though.

> The frame positioning behavior of mutter is a pain for me and renders my
> usual Emacs frame setup practically unusable.  It's possibly a
> consequence of making borders invisible and having the frame minimize
> and maximize when it's pushed against the bottom or top edge of the
> display.  Visible child frames never resize, I cannot even shrink them.
> Also, I can't get vertical scroll bars for them.  In one case I was told
> 
> Window manager warning: Window 0x4a0003d (Terminal) sets an MWM hint 
> indicating it isn't resizable, but sets min size 1 x 1 and max size 
> 2147483647 x 2147483647; this doesn't make much sense.
> 
> but I'm not even sure whether these resulted from an Emacs frame - the
> max size values are not ours AFAICT.  Also we set MWM hints only from
> within non-GTK builds, maybe I've been running one of them.

Sounds like it's talking about the "Terminal" app?

> Anyway, I meanwhile further rewrote the code for mouse dragging and
> 'x-set-frame-size-and-position', patch attached.  I also added an
> interface to the gtk inspector, you can enable it via
> 
> (when (fboundp 'x-gtk-debug)
>    (x-gtk-debug t))
> 
> Maybe you can derive something from running it.  At least here, when
> under "visual" turning on "graphics actualizations", I can clearly see
> that GTK processes and passes on the resize requests for child frames
> (by turning the frame red) and that they are later apparently dismissed
> by mutter.

Will do! Although it sounds like you probably have all the same 
information now.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-05  9:15                                                                                                                         ` martin rudalics
  2020-02-10  7:06                                                                                                                           ` Dmitry Gutov
@ 2020-02-10  7:22                                                                                                                           ` Dmitry Gutov
  2020-02-10 17:54                                                                                                                             ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-10  7:22 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 05.02.2020 12:15, martin rudalics wrote:
> Anyway, I meanwhile further rewrote the code for mouse dragging and
> 'x-set-frame-size-and-position', patch attached.

The effect of this new patch is weird:

Dragging the right and/or bottom edge now moves the "cutoff" (for lack 
of a better word) instead of resizing the frame. The frame internal 
border, the mode-line, etc, stay in place, and resizing like this can 
cover them partially or completely, making further dragging of the same 
edge impossible. After, the only way to show the internal border again 
is to drag the left or top border. Which will refresh the rendering of 
all the borders.

Also, resizing by the top or left borders looks more like moving the 
frame because its contents do not change size (and the distance between 
borders stays the same; the "extra" space outside is taken by a graphics 
glitch).

> I also added an
> interface to the gtk inspector, you can enable it via
> 
> (when (fboundp 'x-gtk-debug)
>    (x-gtk-debug t))
> 
> Maybe you can derive something from running it.  At least here, when
> under "visual" turning on "graphics actualizations", I can clearly see
> that GTK processes and passes on the resize requests for child frames
> (by turning the frame red) and that they are later apparently dismissed
> by mutter.

If I understood your explanation correctly, I'm seeing the same, yes. 
Although the settings item was called "Show Graphic Updates".



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-10  7:06                                                                                                                           ` Dmitry Gutov
@ 2020-02-10 17:53                                                                                                                             ` martin rudalics
  2020-02-10 22:40                                                                                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-10 17:53 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> So you could make the initial child frame 10000 pixel wide and high and
 >> resizing would never fail?
 >
 > Seems like it.
 >
 > But set-frame-size still does nothing, so I wouldn't know how to take advantage of this discovery programmatically.

Via 'x-set-frame-size-and-position' IIUC.  But elsewhere you say it's
broken.

 >> Which ones did you drop - all?  The ones in the gdk_window_move_resize
 >> call should remain, only the ones from the XMoveResizeWindow call should
 >> be dropped.
 >
 > Only the ones from the XMoveResizeWindow call.

That was the idea.

 >> I meanwhile installed mutter here.  Debian apparently doesn't resolve
 >> the dependencies well so I had to manually install some additional
 >> gnomish features.  The whole thing still looks incomplete though.
 >
 > Sounds like trying a Live CD might work better for you. That leaves the question of how to get an Emacs build on there, though.

I installed a newer Debian from a Live CD a few days ago on another
machine but still with an xfce setup.  There I installed a newer version
of mutter and after installing a thing called pipewire things works more
or less.

 >> Window manager warning: Window 0x4a0003d (Terminal) sets an MWM hint indicating it isn't resizable, but sets min size 1 x 1 and max size 2147483647 x 2147483647; this doesn't make much sense.
 >>
 >> but I'm not even sure whether these resulted from an Emacs frame - the
 >> max size values are not ours AFAICT.  Also we set MWM hints only from
 >> within non-GTK builds, maybe I've been running one of them.
 >
 > Sounds like it's talking about the "Terminal" app?

Unlikely.  It rather belongs to those mutter jokes whenever it finds
"another cracksmoker" (you can find these in their window-props.c).

 > Will do! Although it sounds like you probably have all the same information now.

Not really, yet.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-10  7:22                                                                                                                           ` Dmitry Gutov
@ 2020-02-10 17:54                                                                                                                             ` martin rudalics
  2020-02-10 22:49                                                                                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-10 17:54 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > The effect of this new patch is weird:
 >
 > Dragging the right and/or bottom edge now moves the "cutoff" (for lack
 > of a better word) instead of resizing the frame. The frame internal
 > border, the mode-line, etc, stay in place, and resizing like this can
 > cover them partially or completely, making further dragging of the
 > same edge impossible. After, the only way to show the internal border
 > again is to drag the left or top border. Which will refresh the
 > rendering of all the borders.

I understand only partially but probably we see the same.  When I drag
the right internal border here it disappears.  When I now drag the
bottom border, the right border reappears at its old position, making
the previous drag a noop, and the bottom border disappears.  So in
practice I cannot move any border.

Do you mean that with an earlier patch you could arbitrarily move those
borders (using an insanely large initial child frame)?  If so, please
tell me which patch that was.

 > Also, resizing by the top or left borders looks more like moving the
 > frame because its contents do not change size (and the distance
 > between borders stays the same; the "extra" space outside is taken by
 > a graphics glitch).

Here nothing happens in this regard.

 > If I understood your explanation correctly, I'm seeing the same,
 > yes. Although the settings item was called "Show Graphic Updates".

Probably so.  I tried to translate from my locale.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-10 17:53                                                                                                                             ` martin rudalics
@ 2020-02-10 22:40                                                                                                                               ` Dmitry Gutov
  0 siblings, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-10 22:40 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 10.02.2020 19:53, martin rudalics wrote:
> I installed a newer Debian from a Live CD a few days ago on another
> machine but still with an xfce setup.  There I installed a newer version
> of mutter and after installing a thing called pipewire things works more
> or less.

Well, I'm on Ubuntu (last April's release), and the last time I used 
Debian on a desktop was more than a decade ago. So I'd recommend the 
former, but I guess that would disrupt your workflows even more.

(I thought PipeWire is still experimental, and not used as a replacement 
for PulseAudio...)

 > Unlikely.  It rather belongs to those mutter jokes whenever it finds
 > "another cracksmoker" (you can find these in their window-props.c).

Could it be Mutter talking about Terminal?

Anyway, I'm not sure where Mutter logs to on my machine.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-10 17:54                                                                                                                             ` martin rudalics
@ 2020-02-10 22:49                                                                                                                               ` Dmitry Gutov
  2020-02-13 18:42                                                                                                                                 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-10 22:49 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 10.02.2020 19:54, martin rudalics wrote:
>  > The effect of this new patch is weird:
>  >
>  > Dragging the right and/or bottom edge now moves the "cutoff" (for lack
>  > of a better word) instead of resizing the frame. The frame internal
>  > border, the mode-line, etc, stay in place, and resizing like this can
>  > cover them partially or completely, making further dragging of the
>  > same edge impossible. After, the only way to show the internal border
>  > again is to drag the left or top border. Which will refresh the
>  > rendering of all the borders.
> 
> I understand only partially but probably we see the same.  When I drag
> the right internal border here it disappears.  When I now drag the
> bottom border, the right border reappears at its old position, making
> the previous drag a noop, and the bottom border disappears.  So in
> practice I cannot move any border.

Sounds similar, if not 100% exact.

> Do you mean that with an earlier patch you could arbitrarily move those
> borders (using an insanely large initial child frame)?  If so, please
> tell me which patch that was.

Just the previous version of the patch with the same filename. The one 
in this email:

https://lists.gnu.org/archive/html/emacs-devel/2020-01/msg00971.html



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-10 22:49                                                                                                                               ` Dmitry Gutov
@ 2020-02-13 18:42                                                                                                                                 ` martin rudalics
  2020-02-13 23:48                                                                                                                                   ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-13 18:42 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1337 bytes --]

 > Just the previous version of the patch with the same filename. The one in this email:
 >
 > https://lists.gnu.org/archive/html/emacs-devel/2020-01/msg00971.html

This one adjusted our windows before issuing the resize request so it
was cheating, in some sense.  It turned out here that we have to issue a
gdk_window_resize request instead of a gtk_window_resize request in
order to have mutter respond at all.  In addition, we have to process
ConfigureNotify differently.  The attached use_gdk_resize.diff does that
so you should be able to run a normal 'set-frame-size' and be able to
resize the child frame within its initial size.  Making the child frame
sufficiently large initially, the patch can handle all resizes here.
It's not a feasible solution and breaks redisplay with xfwm4 though.

I also attach a second patch called hide-child-frame-during-resize.diff
which does nothing else but hiding a child frame during resizing.  You
have to toggle 'x-gtk-hide-child-frame-during-resize' to make it work.
It will cause flicker but is probably the one only thing we could do for
Emacs 27.

Neither of these solutions is practicable so we still have to contact
the mutter people.  Unfortunately, there are probably a number of
additional issues as well so in their present form Emacs and mutter are
not really compatible.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: use_gdk_resize.diff --]
[-- Type: text/x-patch; name="use_gdk_resize.diff", Size: 1676 bytes --]

diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..a77810141a 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -997,12 +997,13 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
     }
   else
     {
+      GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+
       frame_size_history_add
 	(f, Qxg_frame_set_char_size_3, width, height,
 	 list2i (totalwidth, totalheight));

-      gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-			 totalwidth, totalheight);
+      gdk_window_resize (gwin, (gint)totalwidth, (gint)totalheight);
       fullscreen = Qnil;
     }

diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..a90e3e0a98 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -8953,6 +8953,22 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef USE_CAIRO
 	  x_cr_update_surface_desired_size (f, configureEvent.xconfigure.width,
 					    configureEvent.xconfigure.height);
+#endif
+          f = 0;
+        }
+      else if (f && FRAME_PARENT_FRAME (f)
+	       && (configureEvent.xconfigure.width != FRAME_PIXEL_WIDTH (f)
+		   || configureEvent.xconfigure.height != FRAME_PIXEL_HEIGHT (f)))
+        {
+          block_input ();
+          if (FRAME_X_DOUBLE_BUFFERED_P (f))
+            font_drop_xrender_surfaces (f);
+          unblock_input ();
+          xg_frame_resized (f, configureEvent.xconfigure.width,
+                            configureEvent.xconfigure.height);
+#ifdef USE_CAIRO
+	  x_cr_update_surface_desired_size (f, configureEvent.xconfigure.width,
+					    configureEvent.xconfigure.height);
 #endif
           f = 0;
         }

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: hide-child-frame-during-resize.diff --]
[-- Type: text/x-patch; name="hide-child-frame-during-resize.diff", Size: 2362 bytes --]

diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..0b2f597c2b 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -953,6 +953,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
   int totalheight
     = pixelheight + FRAME_TOOLBAR_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
   int totalwidth = pixelwidth + FRAME_TOOLBAR_WIDTH (f);
+  bool was_visible = false;

   if (FRAME_PIXEL_HEIGHT (f) == 0)
     return;
@@ -1001,8 +1002,28 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
 	(f, Qxg_frame_set_char_size_3, width, height,
 	 list2i (totalwidth, totalheight));

+      if (FRAME_PARENT_FRAME (f) && FRAME_VISIBLE_P (f)
+	  && x_gtk_hide_child_frame_during_resize)
+	{
+	  was_visible = true;
+	  block_input ();
+	  gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
+	  unblock_input ();
+	}
+
       gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 			 totalwidth, totalheight);
+
+      if (was_visible)
+	{
+	  block_input ();
+	  gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
+	  /* Let's hope the following is not needed.  */
+/** 	  XMoveWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f), **/
+/** 		       f->left_pos, f->top_pos); **/
+	  unblock_input ();
+	}
+
       fullscreen = Qnil;
     }

@@ -1016,7 +1037,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
      size as fast as possible.
      For unmapped windows, we can set rows/cols.  When
      the frame is mapped again we will (hopefully) get the correct size.  */
-  if (FRAME_VISIBLE_P (f))
+  if (FRAME_VISIBLE_P (f) && !was_visible)
     {
       /* Must call this to flush out events */
       (void)gtk_events_pending ();
diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..95109baf46 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13747,4 +13747,9 @@ syms_of_xterm (void)
 consuming frame position adjustments.  In newer versions of GTK, Emacs
 always uses gtk_window_move and ignores the value of this variable.  */);
   x_gtk_use_window_move = true;
+
+  DEFVAR_BOOL ("x-gtk-hide-child-frame-during-resize", x_gtk_hide_child_frame_during_resize,
+    doc: /* Non-nil means hide child frame during resize.
+Set this only if your window manager refuses to resize child frames.  */);
+  x_gtk_hide_child_frame_during_resize = false;
 }

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-13 18:42                                                                                                                                 ` martin rudalics
@ 2020-02-13 23:48                                                                                                                                   ` Dmitry Gutov
  2020-02-14  8:48                                                                                                                                     ` martin rudalics
  2020-02-14  9:52                                                                                                                                     ` martin rudalics
  0 siblings, 2 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-13 23:48 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

Hi Martin,

On 13.02.2020 20:42, martin rudalics wrote:
>  > Just the previous version of the patch with the same filename. The 
> one in this email:
>  >
>  > https://lists.gnu.org/archive/html/emacs-devel/2020-01/msg00971.html
> 
> This one adjusted our windows before issuing the resize request so it
> was cheating, in some sense.  It turned out here that we have to issue a
> gdk_window_resize request instead of a gtk_window_resize request in
> order to have mutter respond at all.  In addition, we have to process
> ConfigureNotify differently.  The attached use_gdk_resize.diff does that
> so you should be able to run a normal 'set-frame-size' and be able to
> resize the child frame within its initial size.  Making the child frame
> sufficiently large initially, the patch can handle all resizes here.
> It's not a feasible solution and breaks redisplay with xfwm4 though.
> 
> I also attach a second patch called hide-child-frame-during-resize.diff
> which does nothing else but hiding a child frame during resizing.  You
> have to toggle 'x-gtk-hide-child-frame-during-resize' to make it work.
> It will cause flicker but is probably the one only thing we could do for
> Emacs 27.

Sounds like posframe could make this work if both patches could be 
pushed to emacs-27, and if they didn't break any other window managers.

(Hiding the child frame during resizing could be used only when resizing 
down from the unreasolable large size, for example).

BTW, are they supposed to be applied on top of current emacs-27? The 
second one fails with:

$ patch -p1 < hide-child-frame-during-resize.diff
patching file src/gtkutil.c
Hunk #2 FAILED at 1002.
Hunk #3 succeeded at 1018 (offset 1 line).
1 out of 3 hunks FAILED -- saving rejects to file src/gtkutil.c.rej
patching file src/xterm.c
Hunk #1 succeeded at 13763 (offset 16 lines).

> Neither of these solutions is practicable so we still have to contact
> the mutter people.  Unfortunately, there are probably a number of
> additional issues as well so in their present form Emacs and mutter are
> not really compatible.

I think we have made out due diligence and studied the problem with some 
detail, and we can write the details out to the Mutter bug report.

Maybe we'll have some luck, and one of the developers replies with a 
simple alternative fix? That happened to me before with other projects.

I won't be holding my breath, of course.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-13 23:48                                                                                                                                   ` Dmitry Gutov
@ 2020-02-14  8:48                                                                                                                                     ` martin rudalics
  2020-02-15 22:31                                                                                                                                       ` Dmitry Gutov
  2020-02-14  9:52                                                                                                                                     ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-14  8:48 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > Sounds like posframe could make this work if both patches could be
 > pushed to emacs-27, and if they didn't break any other window
 > managers.

We could add another variable to control the behavior of the
use_gdk_resize variant.  It's a really awful hack in either case,
though.

 > (Hiding the child frame during resizing could be used only when resizing down from the unreasolable large size, for example).

"down"?  Conceptually, the patches are mutually exclusive.  I don't know
whether it's possible to reconcile them the way you sketch above.

 > BTW, are they supposed to be applied on top of current emacs-27? The second one fails with:
 >
 > $ patch -p1 < hide-child-frame-during-resize.diff
 > patching file src/gtkutil.c
 > Hunk #2 FAILED at 1002.
 > Hunk #3 succeeded at 1018 (offset 1 line).
 > 1 out of 3 hunks FAILED -- saving rejects to file src/gtkutil.c.rej
 > patching file src/xterm.c
 > Hunk #1 succeeded at 13763 (offset 16 lines).

They apply here properly against latest Emacs 27 (using git apply) but
_not_ on top of each other.

Both patches are based on your earlier observations.  I have not found
out anything new in this area.  Perhaps you (and maybe someone else)
could try to run either of them for a while and tell us whether they
render the overall behavior unbearable.  Also, I have no idea whether
any kind of eventual unmapping or hiding a child frame may render
further enlargings impossible again.  In particular, I don't know who
stores that "initial" frame size someone uses to compare the requested
frame size against and refuses to grant the request when the latter is
larger.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-13 23:48                                                                                                                                   ` Dmitry Gutov
  2020-02-14  8:48                                                                                                                                     ` martin rudalics
@ 2020-02-14  9:52                                                                                                                                     ` martin rudalics
  2020-02-15 22:49                                                                                                                                       ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-14  9:52 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > I think we have made out due diligence and studied the problem with some detail, and we can write the details out to the Mutter bug report.
 >
 > Maybe we'll have some luck, and one of the developers replies with a simple alternative fix? That happened to me before with other projects.
 >
 > I won't be holding my breath, of course.

I had a glimpse at

https://gitlab.gnome.org/GNOME/gnome-shell/issues/1733

but its Javascript use annoys me and I'm not very enthusiastic about
registering or signing in to post a reply.  So, if possible, please
pass along the information below to them.

Thanks, martin


Below find some additional informations wrt the issue at hand.

Emacs makes the child window via XReparentWindow and asks to resize it
via gtk_window_resize.  The initial resize request gives the child
window the expected initial size and position when it is subsequently
mapped.  Further resize requests fail however.  There's no visible
feedback after the gtk_window_resize request has been issued and Emacs
never receives a ConfigureNotify event for it.

The problem does not occur for Lucid, Motif and GTK2 builds, it happens
with GTK3 builds only.

The following two workarounds are currently tested:

(1) Use gdk_window_resize instead of gtk_window_resize.  This requires
to tweak our handling of ConfigureNotify events in a way that is
incompatible with other window managers.  Hence we would have to
special-case mutter in a very queer fashion.  What's worse, however, is
that the child window cannot be enlarged beyond its "initial" size -
apparently the one given to it when it was mapped for the first time.
So one has to make a child window very large initially in order to
handle all future resize requests.  We have no idea as to who manages
that "initial" size and refuses our requests to make the child window
larger.

(2) Make child windows temporarily invisible when resizing them.  This
means that for every resize request we have to invoke gtk_widget_hide
first, then apply gtk_window_resize and finally call gtk_widget_show_all
to show the window again.  This usually will cause the child window to
flicker whenever it gets resized.

Neither of these solutions appear satisfactory so your help in this
matter would be highly appreciated.

Thanks in advance



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-14  8:48                                                                                                                                     ` martin rudalics
@ 2020-02-15 22:31                                                                                                                                       ` Dmitry Gutov
  2020-02-16 10:01                                                                                                                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-15 22:31 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 14.02.2020 10:48, martin rudalics wrote:
>  > Sounds like posframe could make this work if both patches could be
>  > pushed to emacs-27, and if they didn't break any other window
>  > managers.
> 
> We could add another variable to control the behavior of the
> use_gdk_resize variant.  It's a really awful hack in either case,
> though.
> 
>  > (Hiding the child frame during resizing could be used only when 
> resizing down from the unreasolable large size, for example).
> 
> "down"?  Conceptually, the patches are mutually exclusive.  I don't know
> whether it's possible to reconcile them the way you sketch above.

Hmm, I think I see now.

But anyway, the second patch is equivalent to my workaround 
(hiding/showing the frame), so it doesn't seem strictly necessary. The 
downside is the same: flickering. I guess the only part that could be 
improved there is to avoid resizing (and flicker) if the target size 
stays the same.

Another thing: judging by the file names, at least, that change in the 
behavior would also affect the gtk2 build. But it's already working 
fine. We certainly don't want to introduce flickering on resize to it.

>  > BTW, are they supposed to be applied on top of current emacs-27? The 
> second one fails with:
>  >
>  > $ patch -p1 < hide-child-frame-during-resize.diff
>  > patching file src/gtkutil.c
>  > Hunk #2 FAILED at 1002.
>  > Hunk #3 succeeded at 1018 (offset 1 line).
>  > 1 out of 3 hunks FAILED -- saving rejects to file src/gtkutil.c.rej
>  > patching file src/xterm.c
>  > Hunk #1 succeeded at 13763 (offset 16 lines).
> 
> They apply here properly against latest Emacs 27 (using git apply) but
> _not_ on top of each other.
> 
> Both patches are based on your earlier observations.  I have not found
> out anything new in this area.

To clarify: would you consider the patch #1 for inclusion in Emacs 27?

I rather hate flickering, so #2 seems out of the question, IMHO.

> Perhaps you (and maybe someone else)
> could try to run either of them for a while and tell us whether they
> render the overall behavior unbearable.  Also, I have no idea whether
> any kind of eventual unmapping or hiding a child frame may render
> further enlargings impossible again.  In particular, I don't know who
> stores that "initial" frame size someone uses to compare the requested
> frame size against and refuses to grant the request when the latter is
> larger.

We're going to ask the Mutter developers.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-14  9:52                                                                                                                                     ` martin rudalics
@ 2020-02-15 22:49                                                                                                                                       ` Dmitry Gutov
  2020-02-16 10:01                                                                                                                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-15 22:49 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 14.02.2020 11:52, martin rudalics wrote:
>  > I think we have made out due diligence and studied the problem with 
> some detail, and we can write the details out to the Mutter bug report.
>  >
>  > Maybe we'll have some luck, and one of the developers replies with a 
> simple alternative fix? That happened to me before with other projects.
>  >
>  > I won't be holding my breath, of course.
> 
> I had a glimpse at
> 
> https://gitlab.gnome.org/GNOME/gnome-shell/issues/1733
> 
> but its Javascript use annoys me and I'm not very enthusiastic about
> registering or signing in to post a reply.  So, if possible, please
> pass along the information below to them.

That makes me sad regarding our chances to get off Debbugs someday, but 
sure.

At least I was going to, but Stefan beat me to it. So let's wait for 
their response now.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-15 22:31                                                                                                                                       ` Dmitry Gutov
@ 2020-02-16 10:01                                                                                                                                         ` martin rudalics
  2020-02-16 20:47                                                                                                                                           ` Dmitry Gutov
  2020-02-16 23:01                                                                                                                                           ` Dmitry Gutov
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-02-16 10:01 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1218 bytes --]

 > But anyway, the second patch is equivalent to my workaround
 > (hiding/showing the frame), so it doesn't seem strictly necessary. The
 > downside is the same: flickering.

That's what I wanted to know - whether the flickering is just the same
as with your Lisp solution.

 > I guess the only part that could be
 > improved there is to avoid resizing (and flicker) if the target size
 > stays the same.

We could try that.

 > Another thing: judging by the file names, at least, that change in the
 > behavior would also affect the gtk2 build. But it's already working
 > fine. We certainly don't want to introduce flickering on resize to it.

Hiding is controlled by 'x-gtk-hide-child-frame-during-resize' which you
can toggle at any time during a session.

 > To clarify: would you consider the patch #1 for inclusion in Emacs 27?

Not in its present form.  I attach another variant based on a variable
'x-resize-child-frame-special'.  But I cannot test it any more because
since yesterday mutter --replace crashes here with

mutter[1053]: segfault at 88 ip 00007fe0cd3f05f5 sp 00007ffdb7e46470 error 6 in libmutter-3.so.0.0.0[7fe0cd3ba000+db000]

so that patch likely needs tweaking (if it works at all).

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: x-resize-child-frame-special.diff --]
[-- Type: text/x-patch; name="x-resize-child-frame-special.diff", Size: 2765 bytes --]

diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..a77810141a 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -997,12 +997,13 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
     }
   else
     {
+      GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+
       frame_size_history_add
 	(f, Qxg_frame_set_char_size_3, width, height,
 	 list2i (totalwidth, totalheight));

-      gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-			 totalwidth, totalheight);
+      gdk_window_resize (gwin, (gint)totalwidth, (gint)totalheight);
       fullscreen = Qnil;
     }

diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..cfe4e7a2c0 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4125,6 +4125,9 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
   x_wm_set_size_hint (f, window_prompting, false);
   unblock_input ();

+  if (FRAME_PARENT_FRAME (f) && x_resize_child_frame_special)
+    adjust_frame_size (f, 1000, 1000, 0, true, Qx_create_frame_2);
+
   adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
 		     0, true, Qx_create_frame_2);

diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..84b154f8fc 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -8953,6 +8953,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef USE_CAIRO
 	  x_cr_update_surface_desired_size (f, configureEvent.xconfigure.width,
 					    configureEvent.xconfigure.height);
+#endif
+          f = 0;
+        }
+      else if (f && FRAME_PARENT_FRAME (f)
+	       && x_resize_child_frame_special
+	       && (configureEvent.xconfigure.width != FRAME_PIXEL_WIDTH (f)
+		   || configureEvent.xconfigure.height != FRAME_PIXEL_HEIGHT (f)))
+        {
+          block_input ();
+          if (FRAME_X_DOUBLE_BUFFERED_P (f))
+            font_drop_xrender_surfaces (f);
+          unblock_input ();
+          xg_frame_resized (f, configureEvent.xconfigure.width,
+                            configureEvent.xconfigure.height);
+#ifdef USE_CAIRO
+	  x_cr_update_surface_desired_size (f, configureEvent.xconfigure.width,
+					    configureEvent.xconfigure.height);
 #endif
           f = 0;
         }
@@ -13747,4 +13764,10 @@ syms_of_xterm (void)
 consuming frame position adjustments.  In newer versions of GTK, Emacs
 always uses gtk_window_move and ignores the value of this variable.  */);
   x_gtk_use_window_move = true;
+
+  DEFVAR_BOOL ("x-resize-child-frame-special", x_resize_child_frame_special,
+    doc: /* Non-nil means treat child frames specially during resizing.
+Set this if and only if your window manager refuses to resize child
+frames as expected.  */);
+  x_resize_child_frame_special = false;
 }

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-15 22:49                                                                                                                                       ` Dmitry Gutov
@ 2020-02-16 10:01                                                                                                                                         ` martin rudalics
  0 siblings, 0 replies; 196+ messages in thread
From: martin rudalics @ 2020-02-16 10:01 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > That makes me sad regarding our chances to get off Debbugs someday, but sure.

I'm kind of allergic in this regard.

 > At least I was going to, but Stefan beat me to it. So let's wait for their response now.

I also read the lines you added.  Let's hope for the best.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-16 10:01                                                                                                                                         ` martin rudalics
@ 2020-02-16 20:47                                                                                                                                           ` Dmitry Gutov
  2020-02-17 18:20                                                                                                                                             ` martin rudalics
  2020-02-16 23:01                                                                                                                                           ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-16 20:47 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 16.02.2020 12:01, martin rudalics wrote:
> Not in its present form.  I attach another variant based on a variable
> 'x-resize-child-frame-special'.  But I cannot test it any more because
> since yesterday mutter --replace crashes here with
> 
> mutter[1053]: segfault at 88 ip 00007fe0cd3f05f5 sp 00007ffdb7e46470 
> error 6 in libmutter-3.so.0.0.0[7fe0cd3ba000+db000]
> 
> so that patch likely needs tweaking (if it works at all).

Indeed, it does *something*, but not the intended effect yet: apparently 
the window as seen by WM is extended by the Emacs child frame is not 
(similar to what we had using one of the intermediary patches).

So it looks like the child frame is not enlarged, but e.g. clicks on the 
area that should have been added to it don't go through to the frame 
below it.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-16 10:01                                                                                                                                         ` martin rudalics
  2020-02-16 20:47                                                                                                                                           ` Dmitry Gutov
@ 2020-02-16 23:01                                                                                                                                           ` Dmitry Gutov
  2020-02-17 18:21                                                                                                                                             ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-16 23:01 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 16.02.2020 12:01, martin rudalics wrote:
> That's what I wanted to know - whether the flickering is just the same
> as with your Lisp solution.

Having tried it out, it looks like an okay workaround.

It seems like the optimization I described is sort of already there, at 
least as far as fit-frame-to-buffer is concerned. So it's better than 
explicitly cycling frame visibility like I tried before.

When the frame does need to be resized, the flicker is there, of course.

But with the current implementation of company-posframe, at least, it 
might look better than the current behavior also with a GTK2 build. 
Like, with the new var set to nil (default), the frame is seemingly 
resized in two steps (*):

  - Resize the frame.
    (redisplay, apparently, but show the previous contents of the buffer)
  - Update the contents of the frame.
    (redisplay again, apparently)

The whole process is fast, but not fast enough for me to miss this 
transition.

It's either a bug in company-posframe or in Emacs itself, but setting 
x-gtk-hide-child-frame-during-resize to t at least makes it happen in 
one move, at the cost of having the whole popup blink at the same time.

(*) Tried to see the same problem with a Lucid build but couldn't. Maybe 
just because it resizes faster, IDK.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-16 20:47                                                                                                                                           ` Dmitry Gutov
@ 2020-02-17 18:20                                                                                                                                             ` martin rudalics
  2020-02-21 11:03                                                                                                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-17 18:20 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > Indeed, it does *something*, but not the intended effect yet:
 > apparently the window as seen by WM is extended by the Emacs child
                                                ^ but? ^

 > frame is not (similar to what we had using one of the intermediary
 > patches).

Does shrinking work in the sense that the internal borders of the child
frame are redrawn?

 > So it looks like the child frame is not enlarged, but e.g. clicks on
 > the area that should have been added to it don't go through to the
 > frame below it.

Sounds good, but how comes that we apparently now we do not get the
ConfigureNotify we got before?  Basically, this new patch is
use_gdk_resize.diff with an initial child frame of 1000x1000 pixels
size.  Did you set 'x-resize-child-frame-special' to t?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-16 23:01                                                                                                                                           ` Dmitry Gutov
@ 2020-02-17 18:21                                                                                                                                             ` martin rudalics
  2020-02-21 14:18                                                                                                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-17 18:21 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > It seems like the optimization I described is sort of already there,
 > at least as far as fit-frame-to-buffer is concerned. So it's better
 > than explicitly cycling frame visibility like I tried before.

Which optimization?

 > When the frame does need to be resized, the flicker is there, of course.

So it doesn't flicker when the frame doesn't need a resize?  Maybe GTK
catches that.

 > But with the current implementation of company-posframe, at least, it might look better than the current behavior also with a GTK2 build. Like, with the new var set to nil (default), the frame is seemingly resized in two steps (*):
 >
 >   - Resize the frame.
 >     (redisplay, apparently, but show the previous contents of the buffer)
 >   - Update the contents of the frame.
 >     (redisplay again, apparently)

Have you tried the other way round?

 > The whole process is fast, but not fast enough for me to miss this transition.
 >
 > It's either a bug in company-posframe or in Emacs itself, but setting x-gtk-hide-child-frame-during-resize to t at least makes it happen in one move, at the cost of having the whole popup blink at the same time.

I doubt we could collapse the ConfigureNotify and MapNotify into one.
It would be worth a try though ...

 > (*) Tried to see the same problem with a Lucid build but couldn't. Maybe just because it resizes faster, IDK.

I doubt that.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-17 18:20                                                                                                                                             ` martin rudalics
@ 2020-02-21 11:03                                                                                                                                               ` Dmitry Gutov
  2020-02-21 11:13                                                                                                                                                 ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-21 11:03 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 17.02.2020 20:20, martin rudalics wrote:
>  > Indeed, it does *something*, but not the intended effect yet:
>  > apparently the window as seen by WM is extended by the Emacs child
>                                                 ^ but? ^
> 
>  > frame is not (similar to what we had using one of the intermediary
>  > patches).
> 
> Does shrinking work in the sense that the internal borders of the child
> frame are redrawn?
> 
>  > So it looks like the child frame is not enlarged, but e.g. clicks on
>  > the area that should have been added to it don't go through to the
>  > frame below it.
> 
> Sounds good, but how comes that we apparently now we do not get the
> ConfigureNotify we got before?  Basically, this new patch is
> use_gdk_resize.diff with an initial child frame of 1000x1000 pixels
> size.  Did you set 'x-resize-child-frame-special' to t?

I... no. I only changed the value of this variable (locally or globally) 
after the frame was created.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-21 11:03                                                                                                                                               ` Dmitry Gutov
@ 2020-02-21 11:13                                                                                                                                                 ` Dmitry Gutov
  2020-02-21 16:08                                                                                                                                                   ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-21 11:13 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 21.02.2020 13:03, Dmitry Gutov wrote:
> On 17.02.2020 20:20, martin rudalics wrote:
>>  > Indeed, it does *something*, but not the intended effect yet:
>>  > apparently the window as seen by WM is extended by the Emacs child
>>                                                 ^ but? ^
>>
>>  > frame is not (similar to what we had using one of the intermediary
>>  > patches).
>>
>> Does shrinking work in the sense that the internal borders of the child
>> frame are redrawn?
>>
>>  > So it looks like the child frame is not enlarged, but e.g. clicks on
>>  > the area that should have been added to it don't go through to the
>>  > frame below it.
>>
>> Sounds good, but how comes that we apparently now we do not get the
>> ConfigureNotify we got before?  Basically, this new patch is
>> use_gdk_resize.diff with an initial child frame of 1000x1000 pixels
>> size.  Did you set 'x-resize-child-frame-special' to t?
> 
> I... no. I only changed the value of this variable (locally or globally) 
> after the frame was created.

Sorry, the email got sent too fast.

Resizing indeed works if this variable is set to t before the frame is 
created. One problem is that the initial width and height are 2x the 
specified (probably scaling at fault).

Otherwise, it seems to work OK is the test scenario. Not so ideal in 
"production": it seems company-posframe still fails to change the width 
(!) when height is kept unchanged. And when that happens, the expected 
extra area (when we're enlarging the frame, but seemingly fail) is 
apparently where Emacs and the WM disagree (clicks don't do through).



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-17 18:21                                                                                                                                             ` martin rudalics
@ 2020-02-21 14:18                                                                                                                                               ` Dmitry Gutov
  2020-02-21 16:08                                                                                                                                                 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-21 14:18 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 17.02.2020 20:21, martin rudalics wrote:
>  > It seems like the optimization I described is sort of already there,
>  > at least as far as fit-frame-to-buffer is concerned. So it's better
>  > than explicitly cycling frame visibility like I tried before.
> 
> Which optimization?

Not resizing frame when set-frame-size doesn't need to (the new size is 
the same as the old one). Maybe modify-frame-parameters doesn't do the 
resize. Or the window manager avoids the flicker some other way.

>  > When the frame does need to be resized, the flicker is there, of course.
> 
> So it doesn't flicker when the frame doesn't need a resize?  Maybe GTK
> catches that.

Yup. Maybe.

>  > But with the current implementation of company-posframe, at least, it 
> might look better than the current behavior also with a GTK2 build. 
> Like, with the new var set to nil (default), the frame is seemingly 
> resized in two steps (*):
>  >
>  >   - Resize the frame.
>  >     (redisplay, apparently, but show the previous contents of the 
> buffer)
>  >   - Update the contents of the frame.
>  >     (redisplay again, apparently)
> 
> Have you tried the other way round?

posframe already does it the other way around:

        ;; Replace the posframe buffer contents
       (posframe--insert-string string no-properties)

       (posframe--set-frame-size
        posframe height min-height width min-width)

...but the visual effect is how I described above, for some reason.

>  > The whole process is fast, but not fast enough for me to miss this 
> transition.
>  >
>  > It's either a bug in company-posframe or in Emacs itself, but setting 
> x-gtk-hide-child-frame-during-resize to t at least makes it happen in 
> one move, at the cost of having the whole popup blink at the same time.
> 
> I doubt we could collapse the ConfigureNotify and MapNotify into one.
> It would be worth a try though ...
> 
>  > (*) Tried to see the same problem with a Lucid build but couldn't. 
> Maybe just because it resizes faster, IDK.
> 
> I doubt that.

The benchmarks that I posted earlier in this discussion did show that 
Lucid is very fast at resizing.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-21 11:13                                                                                                                                                 ` Dmitry Gutov
@ 2020-02-21 16:08                                                                                                                                                   ` martin rudalics
  2020-02-24  0:11                                                                                                                                                     ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-21 16:08 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1930 bytes --]

 >>> Did you set 'x-resize-child-frame-special' to t?
 >>
 >> I... no. I only changed the value of this variable (locally or globally) after the frame was created.
 >
 > Sorry, the email got sent too fast.
 >
 > Resizing indeed works if this variable is set to t before the frame is
 > created.

My bad.  I should have explained it better.

 > One problem is that the initial width and height are 2x the specified
 > (probably scaling at fault).

With the patch applied and 'x-resize-child-frame-special' non-nil
'x-create-frame' asks for an initial frame size of 1000x1000 pixels

   if (FRAME_PARENT_FRAME (f) && x_resize_child_frame_special)
     adjust_frame_size (f, 1000, 1000, 0, true, Qx_create_frame_2);

So what you see could be the 1000 (2000 scaled?) pixels from that call.
You could try with other values instead of 1000 so we can tell whether
that call has any visible impact.  It's possible that the WM rejects too
large values, for example, because they would exceed the initial size of
the parent frame (insanely large values can make Emacs even crash here).

And always keep in mind that all this is a crazy hack that tries to
second-guess what the WM (or GTK) might do.  I've nowhere in their code
seen the slightest evidence for such behavior.

 > Otherwise, it seems to work OK is the test scenario. Not so ideal in
 > "production": it seems company-posframe still fails to change the
 > width (!) when height is kept unchanged. And when that happens, the
 > expected extra area (when we're enlarging the frame, but seemingly
 > fail) is apparently where Emacs and the WM disagree (clicks don't do
 > through).

Did you use 'set-frame-width' to change it?  Does it also fail to shrink
the width or only to enlarge it?

In either case I attach a patch that now tries to make the second
adjust_frame_size call apply the initially requested sizes but I'm
afraid that it will not produce anything useful.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: x-resize-child-frame-special.diff --]
[-- Type: text/x-patch; name="x-resize-child-frame-special.diff", Size: 2862 bytes --]

diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..a77810141a 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -997,12 +997,13 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
     }
   else
     {
+      GdkWindow *gwin = gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (f));
+
       frame_size_history_add
 	(f, Qxg_frame_set_char_size_3, width, height,
 	 list2i (totalwidth, totalheight));

-      gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
-			 totalwidth, totalheight);
+      gdk_window_resize (gwin, (gint)totalwidth, (gint)totalheight);
       fullscreen = Qnil;
     }

diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..ea6c6902aa 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -4125,6 +4125,13 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
   x_wm_set_size_hint (f, window_prompting, false);
   unblock_input ();

+  if (FRAME_PARENT_FRAME (f) && x_resize_child_frame_special)
+    {
+      adjust_frame_size (f, 1000, 1000, 0, true, Qx_create_frame_2);
+      SET_FRAME_WIDTH (f, x_width);
+      SET_FRAME_HEIGHT (f, x_height);
+    }
+
   adjust_frame_size (f, FRAME_TEXT_WIDTH (f), FRAME_TEXT_HEIGHT (f),
 		     0, true, Qx_create_frame_2);

diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..84b154f8fc 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -8953,6 +8953,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
 #ifdef USE_CAIRO
 	  x_cr_update_surface_desired_size (f, configureEvent.xconfigure.width,
 					    configureEvent.xconfigure.height);
+#endif
+          f = 0;
+        }
+      else if (f && FRAME_PARENT_FRAME (f)
+	       && x_resize_child_frame_special
+	       && (configureEvent.xconfigure.width != FRAME_PIXEL_WIDTH (f)
+		   || configureEvent.xconfigure.height != FRAME_PIXEL_HEIGHT (f)))
+        {
+          block_input ();
+          if (FRAME_X_DOUBLE_BUFFERED_P (f))
+            font_drop_xrender_surfaces (f);
+          unblock_input ();
+          xg_frame_resized (f, configureEvent.xconfigure.width,
+                            configureEvent.xconfigure.height);
+#ifdef USE_CAIRO
+	  x_cr_update_surface_desired_size (f, configureEvent.xconfigure.width,
+					    configureEvent.xconfigure.height);
 #endif
           f = 0;
         }
@@ -13747,4 +13764,10 @@ syms_of_xterm (void)
 consuming frame position adjustments.  In newer versions of GTK, Emacs
 always uses gtk_window_move and ignores the value of this variable.  */);
   x_gtk_use_window_move = true;
+
+  DEFVAR_BOOL ("x-resize-child-frame-special", x_resize_child_frame_special,
+    doc: /* Non-nil means treat child frames specially during resizing.
+Set this if and only if your window manager refuses to resize child
+frames as expected.  */);
+  x_resize_child_frame_special = false;
 }

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-21 14:18                                                                                                                                               ` Dmitry Gutov
@ 2020-02-21 16:08                                                                                                                                                 ` martin rudalics
  2020-02-23  9:22                                                                                                                                                   ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-21 16:08 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 556 bytes --]

 >> So it doesn't flicker when the frame doesn't need a resize?  Maybe GTK
 >> catches that.
 >
 > Yup. Maybe.

In either case I'd have thought that the now attached patch is needed to
avoid a flicker when the frame does not need to be resized (and we still
would hide the frame and make it visible again) but apparently it's not
needed).

 > The benchmarks that I posted earlier in this discussion did show that Lucid is very fast at resizing.

Resizing only, I suppose.  We seemed to agree earlier that Lucid is slow
at repositioning + resizing.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: hide-child-frame-during-resize.diff --]
[-- Type: text/x-patch; name="hide-child-frame-during-resize.diff", Size: 2690 bytes --]

diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..713a46899c 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -940,9 +940,8 @@ xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight)
     }
 }

-/* Resize the outer window of frame F after changing the height.
-   COLUMNS/ROWS is the size the edit area shall have after the resize.  */
-
+/** Resize the outer window of frame F.  WIDTH and HEIGHT are the new
+    pixel sizes of F's text area.  */
 void
 xg_frame_set_char_size (struct frame *f, int width, int height)
 {
@@ -953,6 +952,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
   int totalheight
     = pixelheight + FRAME_TOOLBAR_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
   int totalwidth = pixelwidth + FRAME_TOOLBAR_WIDTH (f);
+  bool was_visible = false;

   if (FRAME_PIXEL_HEIGHT (f) == 0)
     return;
@@ -1001,8 +1001,26 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
 	(f, Qxg_frame_set_char_size_3, width, height,
 	 list2i (totalwidth, totalheight));

+      if (FRAME_PARENT_FRAME (f) && FRAME_VISIBLE_P (f)
+	  && x_gtk_hide_child_frame_during_resize
+	  && (totalwidth != gwidth || totalheight != gheight))
+	{
+	  was_visible = true;
+	  block_input ();
+	  gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
+	  unblock_input ();
+	}
+
       gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 			 totalwidth, totalheight);
+
+      if (was_visible)
+	{
+	  block_input ();
+	  gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
+	  unblock_input ();
+	}
+
       fullscreen = Qnil;
     }

@@ -1016,7 +1034,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
      size as fast as possible.
      For unmapped windows, we can set rows/cols.  When
      the frame is mapped again we will (hopefully) get the correct size.  */
-  if (FRAME_VISIBLE_P (f))
+  if (FRAME_VISIBLE_P (f) && !was_visible)
     {
       /* Must call this to flush out events */
       (void)gtk_events_pending ();
diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..95109baf46 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13747,4 +13747,9 @@ syms_of_xterm (void)
 consuming frame position adjustments.  In newer versions of GTK, Emacs
 always uses gtk_window_move and ignores the value of this variable.  */);
   x_gtk_use_window_move = true;
+
+  DEFVAR_BOOL ("x-gtk-hide-child-frame-during-resize", x_gtk_hide_child_frame_during_resize,
+    doc: /* Non-nil means hide child frame during resize.
+Set this only if your window manager refuses to resize child frames.  */);
+  x_gtk_hide_child_frame_during_resize = false;
 }

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-21 16:08                                                                                                                                                 ` martin rudalics
@ 2020-02-23  9:22                                                                                                                                                   ` Dmitry Gutov
  2020-02-26 17:30                                                                                                                                                     ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-23  9:22 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 21.02.2020 18:08, martin rudalics wrote:
> In either case I'd have thought that the now attached patch is needed to
> avoid a flicker when the frame does not need to be resized (and we still
> would hide the frame and make it visible again) but apparently it's not
> needed).

I've tried this patch and can't see any difference in behavior.

I could ask why not omit the call to gtk_window_resize when (totalwidth 
== gwidth && totalheight == gheight), but that would probably only 
affect performance.

> Resizing only, I suppose.  We seemed to agree earlier that 
> Lucid is slow
> at repositioning + resizing.

Yes. In my main "real" scenario, though, resizing is a more frequent 
operation than repositioning (though the latter also happens regularly).



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-21 16:08                                                                                                                                                   ` martin rudalics
@ 2020-02-24  0:11                                                                                                                                                     ` Dmitry Gutov
  2020-02-26 17:30                                                                                                                                                       ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-02-24  0:11 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 2949 bytes --]

On 21.02.2020 18:08, martin rudalics wrote:

> With the patch applied and 'x-resize-child-frame-special' non-nil
> 'x-create-frame' asks for an initial frame size of 1000x1000 pixels
> 
>    if (FRAME_PARENT_FRAME (f) && x_resize_child_frame_special)
>      adjust_frame_size (f, 1000, 1000, 0, true, Qx_create_frame_2);
> 
> So what you see could be the 1000 (2000 scaled?) pixels from that call.

Yes, (frame-geometry test-frame) includes (1048 . 1000) as outer-size.

But I would expect this initial size to be only assigned briefly and 
then changed (by Emacs, internally, without having been asked) to the 
dimensions originally specified by the caller. So that the workaround is 
applied, but the user doesn't really have to see it.

The child frame could even be made invisible while it's created with 
this huge size, before it's resized to the target size.

> You could try with other values instead of 1000 so we can tell whether
> that call has any visible impact.  It's possible that the WM rejects too
> large values, for example, because they would exceed the initial size of
> the parent frame (insanely large values can make Emacs even crash here).

Seems to be not the issue here.

> And always keep in mind that all this is a crazy hack that tries to
> second-guess what the WM (or GTK) might do.  I've nowhere in their code
> seen the slightest evidence for such behavior.
> 
>  > Otherwise, it seems to work OK is the test scenario. Not so ideal in
>  > "production": it seems company-posframe still fails to change the
>  > width (!) when height is kept unchanged. And when that happens, the
>  > expected extra area (when we're enlarging the frame, but seemingly
>  > fail) is apparently where Emacs and the WM disagree (clicks don't do
>  > through).
> 
> Did you use 'set-frame-width' to change it?

posframe--set-frame-size always delegates to fit-frame-to-buffer. Which 
calls modify-frame-parameters at the end.

 > Does it also fail to shrink
 > the width or only to enlarge it?

As I describe at the end of this email, the last patch is kinda broken.

I went to the previous version of x-resize-child-frame-special.diff and 
this time couldn't reproduce this effect (of width often staying 
unchanged). The problem of "first size changes, then contents" is still 
there. I also saw occasional graphical glitches and window update 
problems like the one in the attached screenshot (see the black area; 
the first line, in blue, should have not have been wrapped in two). 
Those were hard to reproduce reliably, however.

> In either case I attach a patch that now tries to make the second
> adjust_frame_size call apply the initially requested sizes but I'm
> afraid that it will not produce anything useful.

If you're saying it should do what I described above... it does not. :-(

Also, the test scenario (one that calls (set-frame-height frame 20)) 
made it 3 lines tall from the POW of Emacs (but not the WM).

[-- Attachment #2: Screenshot from 2020-02-24 02-05-36.png --]
[-- Type: image/png, Size: 299843 bytes --]

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-23  9:22                                                                                                                                                   ` Dmitry Gutov
@ 2020-02-26 17:30                                                                                                                                                     ` martin rudalics
  2020-03-06 23:32                                                                                                                                                       ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-26 17:30 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 867 bytes --]

 > I could ask why not omit the call to gtk_window_resize when (totalwidth == gwidth && totalheight == gheight), but that would probably only affect performance.

You mean like in the attached?  It hardly affects performance here.

I meanwhile did a full GNOME installation here, a somewhat nightmarish
experience trying to get a system menu and task bar, recovering all the
stolen key bindings, disabling the trackers ...  It strongly reminds me
of Windows 10 where I never managed to fix all relevant issues.

Anyway, AFAICT the hide during resizing approach seems to be the only
halfway working alternative at the moment.  It's also the only one that
can show a scroll bar on a child frame (not necessarily right away but
after one resize operation at least).  Which hints at some outer-window
vs edit-window snafu but so far I have no idea where to look.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: hide-child-frame-during-resize.diff --]
[-- Type: text/x-patch; name="hide-child-frame-during-resize.diff", Size: 3073 bytes --]

diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..fec6056bb0 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -940,9 +940,8 @@ xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight)
     }
 }

-/* Resize the outer window of frame F after changing the height.
-   COLUMNS/ROWS is the size the edit area shall have after the resize.  */
-
+/** Resize the outer window of frame F.  WIDTH and HEIGHT are the new
+    pixel sizes of F's text area.  */
 void
 xg_frame_set_char_size (struct frame *f, int width, int height)
 {
@@ -953,6 +952,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
   int totalheight
     = pixelheight + FRAME_TOOLBAR_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
   int totalwidth = pixelwidth + FRAME_TOOLBAR_WIDTH (f);
+  bool was_visible = false;

   if (FRAME_PIXEL_HEIGHT (f) == 0)
     return;
@@ -995,12 +995,35 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
       gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 			 totalwidth, gheight);
     }
+  else if (FRAME_PARENT_FRAME (f) && FRAME_VISIBLE_P (f)
+	   && x_gtk_hide_child_frame_during_resize)
+    {
+      was_visible = true;
+
+      if (totalwidth != gwidth || totalheight != gheight)
+	{
+	  frame_size_history_add
+	    (f, Qxg_frame_set_char_size_3, width, height,
+	     list2i (totalwidth, totalheight));
+	  block_input ();
+	  gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
+	  unblock_input ();
+
+	  gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+			     totalwidth, totalheight);
+
+	  block_input ();
+	  gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
+	  unblock_input ();
+
+	  fullscreen = Qnil;
+	}
+    }
   else
     {
       frame_size_history_add
 	(f, Qxg_frame_set_char_size_3, width, height,
 	 list2i (totalwidth, totalheight));
-
       gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 			 totalwidth, totalheight);
       fullscreen = Qnil;
@@ -1016,7 +1039,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
      size as fast as possible.
      For unmapped windows, we can set rows/cols.  When
      the frame is mapped again we will (hopefully) get the correct size.  */
-  if (FRAME_VISIBLE_P (f))
+  if (FRAME_VISIBLE_P (f) && !was_visible)
     {
       /* Must call this to flush out events */
       (void)gtk_events_pending ();
diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..95109baf46 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -13747,4 +13747,9 @@ syms_of_xterm (void)
 consuming frame position adjustments.  In newer versions of GTK, Emacs
 always uses gtk_window_move and ignores the value of this variable.  */);
   x_gtk_use_window_move = true;
+
+  DEFVAR_BOOL ("x-gtk-hide-child-frame-during-resize", x_gtk_hide_child_frame_during_resize,
+    doc: /* Non-nil means hide child frame during resize.
+Set this only if your window manager refuses to resize child frames.  */);
+  x_gtk_hide_child_frame_during_resize = false;
 }

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-24  0:11                                                                                                                                                     ` Dmitry Gutov
@ 2020-02-26 17:30                                                                                                                                                       ` martin rudalics
  2020-02-28 16:32                                                                                                                                                         ` martin rudalics
  2020-03-06 23:03                                                                                                                                                         ` Dmitry Gutov
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-02-26 17:30 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > But I would expect this initial size to be only assigned briefly and
 > then changed (by Emacs, internally, without having been asked) to the
 > dimensions originally specified by the caller. So that the workaround
 > is applied, but the user doesn't really have to see it.

I hoped so too.  But IIUC the child frame must be first mapped with the
large size and even then hiding it once invalidates the workaround: I
must show it again with the large size before I can re-resize it.

 > The child frame could even be made invisible while it's created with
 > this huge size, before it's resized to the target size.

Been there, done that.  I also tried to set the alpha of the child frame
to zero but apparently this won't work for child frames, regardless of
whether they are override-redirect or not.  Can you change transparency
of child frames (to make it 0 you have to set 'frame-alpha-lower-limit'
first)?

 >> (insanely large values can make Emacs even crash here).
 >
 > Seems to be not the issue here.

It should work with a 10000x10000 characters frame.

 > As I describe at the end of this email, the last patch is kinda broken.

Very much so, indeed.  I couldn't try it at that time.

 > I went to the previous version of x-resize-child-frame-special.diff
 > and this time couldn't reproduce this effect (of width often staying
 > unchanged). The problem of "first size changes, then contents" is
 > still there. I also saw occasional graphical glitches and window
 > update problems like the one in the attached screenshot (see the black
 > area; the first line, in blue, should have not have been wrapped in
 > two). Those were hard to reproduce reliably, however.

I see all sorts of glitches.  And I can't guess what goes on underneath.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-26 17:30                                                                                                                                                       ` martin rudalics
@ 2020-02-28 16:32                                                                                                                                                         ` martin rudalics
  2020-03-03 13:50                                                                                                                                                           ` Dmitry Gutov
  2020-03-06 23:03                                                                                                                                                         ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-02-28 16:32 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 163 bytes --]

 > And I can't guess what goes on underneath.

FWIW the attached patch seems to fix it.  It's based on a deprecated GTK
feature so there might be dragons.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gtk-container-set-resize-mode.diff --]
[-- Type: text/x-patch; name="gtk-container-set-resize-mode.diff", Size: 1000 bytes --]

diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..727b1fc059 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -861,6 +861,11 @@ x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu
 	(FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 	 p ? FRAME_X_WINDOW (p) : DefaultRootWindow (FRAME_X_DISPLAY (f)),
 	 f->left_pos, f->top_pos);
+#ifdef USE_GTK
+      gtk_container_set_resize_mode
+	(GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)),
+	 p ? GTK_RESIZE_IMMEDIATE : GTK_RESIZE_QUEUE);
+#endif
       unblock_input ();

       fset_parent_frame (f, new_value);
@@ -4084,6 +4089,10 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
       block_input ();
       XReparentWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 		       FRAME_X_WINDOW (p), f->left_pos, f->top_pos);
+#ifdef USE_GTK
+      gtk_container_set_resize_mode
+	(GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)), GTK_RESIZE_IMMEDIATE);
+#endif
       unblock_input ();
     }


^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-28 16:32                                                                                                                                                         ` martin rudalics
@ 2020-03-03 13:50                                                                                                                                                           ` Dmitry Gutov
  2020-03-03 14:40                                                                                                                                                             ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-03-03 13:50 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

Hi Martin,

On 28.02.2020 18:32, martin rudalics wrote:
> FWIW the attached patch seems to fix it.  It's based on a deprecated GTK
> feature so there might be dragons.

Please clarify: do I use this together with the previous patch, or on 
its own?



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-03 13:50                                                                                                                                                           ` Dmitry Gutov
@ 2020-03-03 14:40                                                                                                                                                             ` martin rudalics
  2020-03-03 18:27                                                                                                                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-03-03 14:40 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

> Please clarify: do I use this together with the previous patch, or on its own?

On its own.

martin





^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-03 14:40                                                                                                                                                             ` martin rudalics
@ 2020-03-03 18:27                                                                                                                                                               ` Dmitry Gutov
  2020-03-04 17:29                                                                                                                                                                 ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-03-03 18:27 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 823 bytes --]

On 03.03.2020 16:40, martin rudalics wrote:
>> Please clarify: do I use this together with the previous patch, or on 
>> its own?
> 
> On its own.

It looks like it pretty much works, with a couple caveats. Thank you.

Resizing and repositioning works. company-posframe functions with a GTK3 
build like it does with a GTK2 build.

Caveats:

- The thing with "resize then refresh" is also here. When a frame is 
resized, two distinct phases are also visible sometimes. But if it's the 
best we can do with GTK... *shrug*

- The original test case in this thread shows a glitch in the child 
frame in the place (to the right) where the scroll bar could be. See the 
attached screenshot. Resizing the frame (height or width) doesn't make 
it go away. posframe doesn't trigger this, probably because it disables 
scroll bars.

[-- Attachment #2: Screenshot from 2020-03-03 20-21-45.png --]
[-- Type: image/png, Size: 185701 bytes --]

^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-03 18:27                                                                                                                                                               ` Dmitry Gutov
@ 2020-03-04 17:29                                                                                                                                                                 ` martin rudalics
  2020-03-06 23:38                                                                                                                                                                   ` Dmitry Gutov
  2020-03-07  0:07                                                                                                                                                                   ` Dmitry Gutov
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-03-04 17:29 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1148 bytes --]

 > - The thing with "resize then refresh" is also here. When a frame is
 > resized, two distinct phases are also visible sometimes. But if it's
 > the best we can do with GTK... *shrug*

Have you ever tried setting 'x-wait-for-event-timeout' to zero?

 > - The original test case in this thread shows a glitch in the child
 > frame in the place (to the right) where the scroll bar could be. See
 > the attached screenshot. Resizing the frame (height or width) doesn't
 > make it go away. posframe doesn't trigger this, probably because it
 > disables scroll bars.

Right.  A similar thing happens with the toolbar I suppose.  You have to
turn off all of them.  The situation is slightly better with GTK2 builds
but there you can get strange resizing effects.  The only builds that
here work sufficiently well are Lucid builds after bypassing a brutal
hack that causes each single move to wait for half a second on platforms
that do not report the frame position as we want them (patch attached).

I have to fix Bug#38452 first before I can investigate the move/resize
issues further.  Don't expect further improvements for Emacs 27 though.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: gtk-resize-mode+no-sync-with-move+mouse+gtk-debug.diff --]
[-- Type: text/x-patch; name="gtk-resize-mode+no-sync-with-move+mouse+gtk-debug.diff", Size: 37894 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index e58a2e6da1..9a0e2b28e4 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -552,7 +552,7 @@ mouse-drag-mode-line
              (not (eq (window-frame minibuffer-window) frame))))
       ;; Drag frame when the window is on the bottom of its frame and
       ;; there is no minibuffer window below.
-      (mouse-drag-frame start-event 'move)))))
+      (mouse-drag-frame-move start-event)))))
 
 (defun mouse-drag-header-line (start-event)
   "Change the height of a window by dragging on its header line.
@@ -569,7 +569,7 @@ mouse-drag-header-line
         (mouse-drag-line start-event 'header)
       (let ((frame (window-frame window)))
         (when (frame-parameter frame 'drag-with-header-line)
-          (mouse-drag-frame start-event 'move))))))
+          (mouse-drag-frame-move start-event))))))
 
 (defun mouse-drag-vertical-line (start-event)
   "Change the width of a window by dragging on a vertical line.
@@ -577,46 +577,7 @@ mouse-drag-vertical-line
   (interactive "e")
   (mouse-drag-line start-event 'vertical))
 \f
-(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move)
-  "Helper function for `mouse-drag-frame'."
-  (let* ((frame-x-y (frame-position frame))
-         (frame-x (car frame-x-y))
-         (frame-y (cdr frame-x-y))
-         alist)
-    (if (> x-diff 0)
-        (when x-move
-          (setq x-diff (min x-diff frame-x))
-          (setq x-move (- frame-x x-diff)))
-      (let* ((min-width (frame-windows-min-size frame t nil t))
-             (min-diff (max 0 (- (frame-inner-width frame) min-width))))
-        (setq x-diff (max x-diff (- min-diff)))
-        (when x-move
-          (setq x-move (+ frame-x (- x-diff))))))
-
-    (if (> y-diff 0)
-        (when y-move
-          (setq y-diff (min y-diff frame-y))
-          (setq y-move (- frame-y y-diff)))
-      (let* ((min-height (frame-windows-min-size frame nil nil t))
-             (min-diff (max 0 (- (frame-inner-height frame) min-height))))
-        (setq y-diff (max y-diff (- min-diff)))
-        (when y-move
-          (setq y-move (+ frame-y (- y-diff))))))
-
-    (unless (zerop x-diff)
-      (when x-move
-        (push `(left . ,x-move) alist))
-      (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff)))
-            alist))
-    (unless (zerop y-diff)
-      (when y-move
-        (push `(top . ,y-move) alist))
-      (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff)))
-            alist))
-    (when alist
-      (modify-frame-parameters frame alist))))
-
-(defun mouse-drag-frame (start-event part)
+(defun mouse-drag-frame-resize (start-event part)
   "Drag a frame or one of its edges with the mouse.
 START-EVENT is the starting mouse event of the drag action.  Its
 position window denotes the frame that will be dragged.
@@ -635,9 +596,168 @@ mouse-drag-frame
          (frame (if (window-live-p window)
                     (window-frame window)
                   window))
-         (width (frame-native-width frame))
-         (height (frame-native-height frame))
-         ;; PARENT is the parent frame of FRAME or, if FRAME is a
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+         (x-left first-left)
+         (first-top (cdr first-pos))
+         (x-top first-top)
+	 (first-width (frame-text-width frame))
+         (x-width first-width)
+	 (first-height (frame-text-height frame))
+         (x-height first-height)
+	 ;; Don't let FRAME become less large than the size needed to
+	 ;; fit all of its windows.
+	 (min-text-width
+	  (+ (frame-windows-min-size frame t nil t)
+	     (- (frame-inner-width frame) first-width)))
+	 (min-text-height
+	  (+ (frame-windows-min-size frame nil nil t)
+	     (- (frame-inner-height frame) first-height)))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
+         ;; top-level frame, FRAME's workarea.
+         (parent (frame-parent frame))
+         (parent-edges
+          (if parent
+              (frame-edges parent)
+            (let* ((attributes
+                    (car (display-monitor-attributes-list)))
+                   (workarea (assq 'workarea attributes)))
+              (and workarea
+                   `(,(nth 1 workarea) ,(nth 2 workarea)
+                     ,(+ (nth 1 workarea) (nth 3 workarea))
+                     ,(+ (nth 2 workarea) (nth 4 workarea)))))))
+         (parent-left (and parent-edges (nth 0 parent-edges)))
+         (parent-top (and parent-edges (nth 1 parent-edges)))
+         (parent-right (and parent-edges (nth 2 parent-edges)))
+         (parent-bottom (and parent-edges (nth 3 parent-edges)))
+	 ;; Drag types.  drag-left/drag-right and drag-top/drag-bottom
+	 ;; are mutually exclusive.
+	 (drag-left (memq part '(bottom-left left top-left)))
+	 (drag-top (memq part '(top-left top top-right)))
+	 (drag-right (memq part '(top-right right bottom-right)))
+	 (drag-bottom (memq part '(bottom-right bottom bottom-left)))
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         (exitfun nil)
+         (move
+          (lambda (event)
+            (interactive "e")
+            (when (consp event)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+		     alist)
+                ;; We never want to warp the mouse position here.  When
+                ;; moving the mouse leftward or upward, then with a wide
+                ;; border the calculated left or top position of the
+                ;; frame could drop to a value less than zero depending
+                ;; on where precisely the mouse within the border.  We
+                ;; guard against this by never allowing the frame to
+                ;; move to a position less than zero here.  No such
+                ;; precautions are used for the right and bottom borders
+                ;; so with a large internal border parts of that border
+                ;; may disappear.
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (progn
+                      (when (and drag-left (>= last-x parent-left)
+                                 (>= (- first-width left) min-text-width))
+		        (setq x-left (max (+ first-left left) 0))
+		        (setq x-width (- first-width left)))
+	              (when (and drag-top (>= last-y parent-top)
+                                 (>= (- first-height top) min-text-height))
+		        (setq x-top (max 0 (+ first-top top)))
+		        (setq x-height (- first-height top)))
+	              (when (and drag-right (<= last-x parent-right)
+                                 (>= (+ first-width left) min-text-width))
+		        (setq x-width (+ first-width left)))
+	              (when (and drag-bottom (<= last-y parent-bottom)
+                                 (>= (+ first-height top) min-text-height))
+		        (setq x-height (+ first-height top)))
+                      (x-set-frame-size-and-position
+                       frame x-width x-height x-left x-top))
+                  (when (and drag-left (>= last-x parent-left)
+                             (>= (- first-width left) min-text-width))
+		    (push `(left . ,(max (+ first-left left) 0)) alist)
+		    (push `(width . (text-pixels . ,(- first-width left)))
+                          alist))
+	          (when (and drag-top (>= last-y parent-top)
+                             (>= (- first-height top) min-text-height))
+		    (push `(top . ,(max 0 (+ first-top top))) alist)
+		    (push `(height . (text-pixels . ,(- first-height top)))
+                          alist))
+	          (when (and drag-right (<= last-x parent-right)
+                             (>= (+ first-width left) min-text-width))
+		    (push `(width . (text-pixels . ,(+ first-width left)))
+                          alist))
+	          (when (and drag-bottom (<= last-y parent-bottom)
+                             (>= (+ first-height top) min-text-height))
+		    (push `(height . (text-pixels . ,(+ first-height top)))
+                          alist))
+	          (modify-frame-parameters frame alist))))))
+         (old-track-mouse track-mouse))
+    ;; Start tracking.  The special value 'dragging' signals the
+    ;; display engine to freeze the mouse pointer shape for as long
+    ;; as we drag.
+    (setq track-mouse 'dragging)
+    ;; Loop reading events and sampling the position of the mouse.
+    (setq exitfun
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [scroll-bar-movement] #'ignore)
+             (define-key map [mouse-movement] move)
+             ;; Swallow drag-mouse-1 events to avoid selecting some other window.
+             (define-key map [drag-mouse-1]
+               (lambda () (interactive) (funcall exitfun)))
+             ;; Some of the events will of course end up looked up
+             ;; with a mode-line, header-line or vertical-line prefix ...
+             (define-key map [mode-line] map)
+             (define-key map [header-line] map)
+             (define-key map [vertical-line] map)
+             ;; ... and some maybe even with a right- or bottom-divider
+             ;; prefix.
+             (define-key map [right-divider] map)
+             (define-key map [bottom-divider] map)
+             map)
+           t (lambda () (setq track-mouse old-track-mouse))))))
+
+(defun mouse-drag-frame-move (start-event)
+  "Drag a frame or one of its edges with the mouse.
+START-EVENT is the starting mouse event of the drag action.  Its
+position window denotes the frame that will be dragged.
+
+PART specifies the part that has been dragged and must be one of
+the symbols `left', `top', `right', `bottom', `top-left',
+`top-right', `bottom-left', `bottom-right' to drag an internal
+border or edge.  If PART equals `move', this means to move the
+frame with the mouse."
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
+  (let* ((echo-keystrokes 0)
+	 (start (event-start start-event))
+         (window (posn-window start))
+         ;; FRAME is the frame to drag.
+         (frame (if (window-live-p window)
+                    (window-frame window)
+                  window))
+         (native-width (frame-native-width frame))
+         (native-height (frame-native-height frame))
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+	 (first-top (cdr first-pos))
+	 (first-width (frame-text-width frame))
+	 (first-height (frame-text-height frame))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
          ;; top-level frame, FRAME's workarea.
          (parent (frame-parent frame))
          (parent-edges
@@ -654,19 +774,16 @@ mouse-drag-frame
          (parent-top (and parent-edges (nth 1 parent-edges)))
          (parent-right (and parent-edges (nth 2 parent-edges)))
          (parent-bottom (and parent-edges (nth 3 parent-edges)))
-         ;; `pos-x' and `pos-y' record the x- and y-coordinates of the
-	 ;; last sampled mouse position.  Note that we sample absolute
-	 ;; mouse positions to avoid that moving the mouse from one
-	 ;; frame into another gets into our way.  `last-x' and `last-y'
-	 ;; records the x- and y-coordinates of the previously sampled
-	 ;; position.  The differences between `last-x' and `pos-x' as
-	 ;; well as `last-y' and `pos-y' determine the amount the mouse
-	 ;; has been dragged between the last two samples.
-         pos-x-y pos-x pos-y
-         (last-x-y (mouse-absolute-pixel-position))
-         (last-x (car last-x-y))
-         (last-y (cdr last-x-y))
-         ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         ;; `snap-width' (maybe also a yet to be provided `snap-height')
+         ;; could become floats to handle proportionality wrt PARENT.
+         ;; We don't do any checks on this parameter so far.
+         (snap-width (frame-parameter frame 'snap-width))
+	 ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
          ;; mouse position when FRAME snapped.  As soon as the
          ;; difference between `pos-x' and `snap-x' (or `pos-y' and
          ;; `snap-y') exceeds the value of FRAME's `snap-width'
@@ -678,176 +795,144 @@ mouse-drag-frame
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (setq pos-x-y (mouse-absolute-pixel-position))
-              (setq pos-x (car pos-x-y))
-              (setq pos-y (cdr pos-x-y))
-              (cond
-               ((eq part 'left)
-                (mouse-resize-frame frame (- last-x pos-x) 0 t))
-               ((eq part 'top)
-                (mouse-resize-frame frame 0 (- last-y pos-y) nil t))
-               ((eq part 'right)
-                (mouse-resize-frame frame (- pos-x last-x) 0))
-               ((eq part 'bottom)
-                (mouse-resize-frame frame 0 (- pos-y last-y)))
-               ((eq part 'top-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- last-y pos-y) t t))
-               ((eq part 'top-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- last-y pos-y) nil t))
-               ((eq part 'bottom-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- pos-y last-y) t))
-               ((eq part 'bottom-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- pos-y last-y)))
-               ((eq part 'move)
-                (let* ((old-position (frame-position frame))
-                       (old-left (car old-position))
-                       (old-top (cdr old-position))
-                       (left (+ old-left (- pos-x last-x)))
-                       (top (+ old-top (- pos-y last-y)))
-                       right bottom
-                       ;; `snap-width' (maybe also a yet to be provided
-                       ;; `snap-height') could become floats to handle
-                       ;; proportionality wrt PARENT.  We don't do any
-                       ;; checks on this parameter so far.
-                       (snap-width (frame-parameter frame 'snap-width)))
-                  ;; Docking and constraining.
-                  (when (and (numberp snap-width) parent-edges)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+                     right bottom)
+		(setq left (+ first-left left))
+		(setq top (+ first-top top))
+                ;; Docking and constraining.
+                (when (and (numberp snap-width) parent-edges)
+                  (cond
+                   ;; Docking at the left parent edge.
+                   ((< last-x first-x)
                     (cond
-                     ;; Docking at the left parent edge.
-                     ((< pos-x last-x)
-                      (cond
-                       ((and (> left parent-left)
-                             (<= (- left parent-left) snap-width))
-                        ;; Snap when the mouse moved leftward and
-                        ;; FRAME's left edge would end up within
-                        ;; `snap-width' pixels from PARENT's left edge.
-                        (setq snap-x pos-x)
-                        (setq left parent-left))
-                       ((and (<= left parent-left)
-                             (<= (- parent-left left) snap-width)
-                             snap-x (<= (- snap-x pos-x) snap-width))
-                        ;; Stay snapped when the mouse moved leftward
-                        ;; but not more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq left parent-left))
-                       (t
-                        ;; Unsnap when the mouse moved more than
-                        ;; `snap-width' pixels leftward from the time
-                        ;; FRAME snapped.
-                        (setq snap-x nil))))
-                     ((> pos-x last-x)
-                      (setq right (+ left width))
-                      (cond
-                       ((and (< right parent-right)
-                             (<= (- parent-right right) snap-width))
-                        ;; Snap when the mouse moved rightward and
-                        ;; FRAME's right edge would end up within
-                        ;; `snap-width' pixels from PARENT's right edge.
-                        (setq snap-x pos-x)
-                        (setq left (- parent-right width)))
-                       ((and (>= right parent-right)
-                             (<= (- right parent-right) snap-width)
-                             snap-x (<= (- pos-x snap-x) snap-width))
-                        ;; Stay snapped when the mouse moved rightward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq left (- parent-right width)))
-                       (t
-                        ;; Unsnap when the mouse moved rightward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-x nil)))))
-
+                     ((and (> left parent-left)
+                           (<= (- left parent-left) snap-width))
+                      ;; Snap when the mouse moved leftward and FRAME's
+                      ;; left edge would end up within `snap-width'
+                      ;; pixels from PARENT's left edge.
+                      (setq snap-x last-x)
+                      (setq left parent-left))
+                     ((and (<= left parent-left)
+                           (<= (- parent-left left) snap-width)
+                           snap-x (<= (- snap-x last-x) snap-width))
+                      ;; Stay snapped when the mouse moved leftward but
+                      ;; not more than `snap-width' pixels from the time
+                      ;; FRAME snapped.
+                      (setq left parent-left))
+                     (t
+                      ;; Unsnap when the mouse moved more than
+                      ;; `snap-width' pixels leftward from the time
+                      ;; FRAME snapped.
+                      (setq snap-x nil))))
+                   ((> last-x first-x)
+                    (setq right (+ left native-width))
                     (cond
-                     ((< pos-y last-y)
-                      (cond
-                       ((and (> top parent-top)
-                             (<= (- top parent-top) snap-width))
-                        ;; Snap when the mouse moved upward and FRAME's
-                        ;; top edge would end up within `snap-width'
-                        ;; pixels from PARENT's top edge.
-                        (setq snap-y pos-y)
-                        (setq top parent-top))
-                       ((and (<= top parent-top)
-                             (<= (- parent-top top) snap-width)
-                             snap-y (<= (- snap-y pos-y) snap-width))
-                        ;; Stay snapped when the mouse moved upward but
-                        ;; not more more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq top parent-top))
-                       (t
-                        ;; Unsnap when the mouse moved upward more than
-                        ;; `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))
-                     ((> pos-y last-y)
-                      (setq bottom (+ top height))
-                      (cond
-                       ((and (< bottom parent-bottom)
-                             (<= (- parent-bottom bottom) snap-width))
-                        ;; Snap when the mouse moved downward and
-                        ;; FRAME's bottom edge would end up within
-                        ;; `snap-width' pixels from PARENT's bottom
-                        ;; edge.
-                        (setq snap-y pos-y)
-                        (setq top (- parent-bottom height)))
-                       ((and (>= bottom parent-bottom)
-                             (<= (- bottom parent-bottom) snap-width)
-                             snap-y (<= (- pos-y snap-y) snap-width))
-                        ;; Stay snapped when the mouse moved downward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq top (- parent-bottom height)))
-                       (t
-                        ;; Unsnap when the mouse moved downward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))))
-
-                  ;; If requested, constrain FRAME's draggable areas to
-                  ;; PARENT's edges.  The `top-visible' parameter should
-                  ;; be set when FRAME has a draggable header-line.  If
-                  ;; set to a number, it ascertains that the top of
-                  ;; FRAME is always constrained to the top of PARENT
-                  ;; and that at least as many pixels of FRAME as
-                  ;; specified by that number are visible on each of the
-                  ;; three remaining sides of PARENT.
-                  ;;
-                  ;; The `bottom-visible' parameter should be set when
-                  ;; FRAME has a draggable mode-line.  If set to a
-                  ;; number, it ascertains that the bottom of FRAME is
-                  ;; always constrained to the bottom of PARENT and that
-                  ;; at least as many pixels of FRAME as specified by
-                  ;; that number are visible on each of the three
-                  ;; remaining sides of PARENT.
-                  (let ((par (frame-parameter frame 'top-visible))
-                        bottom-visible)
-                    (unless par
-                      (setq par (frame-parameter frame 'bottom-visible))
-                      (setq bottom-visible t))
-                    (when (and (numberp par) parent-edges)
-                      (setq left
-                            (max (min (- parent-right par) left)
-                                 (+ (- parent-left width) par)))
-                      (setq top
-                            (if bottom-visible
-                                (min (max top (- parent-top (- height par)))
-                                     (- parent-bottom height))
-                              (min (max top parent-top)
-                                   (- parent-bottom par))))))
-
-                  ;; Use `modify-frame-parameters' since `left' and
-                  ;; `top' may want to move FRAME out of its PARENT.
-                  (modify-frame-parameters
-                   frame
-                   `((left . (+ ,left)) (top . (+ ,top)))))))
-              (setq last-x pos-x)
-              (setq last-y pos-y))))
-         (old-track-mouse track-mouse))
+                     ((and (< right parent-right)
+                           (<= (- parent-right right) snap-width))
+                      ;; Snap when the mouse moved rightward and FRAME's
+                      ;; right edge would end up within `snap-width'
+                      ;; pixels from PARENT's right edge.
+                      (setq snap-x last-x)
+                      (setq left (- parent-right native-width)))
+                     ((and (>= right parent-right)
+                           (<= (- right parent-right) snap-width)
+                           snap-x (<= (- last-x snap-x) snap-width))
+                      ;; Stay snapped when the mouse moved rightward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq left (- parent-right native-width)))
+                     (t
+                      ;; Unsnap when the mouse moved rightward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-x nil)))))
+                  (cond
+                   ((< last-y first-y)
+                    (cond
+                     ((and (> top parent-top)
+                           (<= (- top parent-top) snap-width))
+                      ;; Snap when the mouse moved upward and FRAME's
+                      ;; top edge would end up within `snap-width'
+                      ;; pixels from PARENT's top edge.
+                      (setq snap-y last-y)
+                      (setq top parent-top))
+                     ((and (<= top parent-top)
+                           (<= (- parent-top top) snap-width)
+                           snap-y (<= (- snap-y last-y) snap-width))
+                      ;; Stay snapped when the mouse moved upward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top parent-top))
+                     (t
+                      ;; Unsnap when the mouse moved upward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))
+                   ((> last-y first-y)
+                    (setq bottom (+ top native-height))
+                    (cond
+                     ((and (< bottom parent-bottom)
+                           (<= (- parent-bottom bottom) snap-width))
+                      ;; Snap when the mouse moved downward and FRAME's
+                      ;; bottom edge would end up within `snap-width'
+                      ;; pixels from PARENT's bottom edge.
+                      (setq snap-y last-y)
+                      (setq top (- parent-bottom native-height)))
+                     ((and (>= bottom parent-bottom)
+                           (<= (- bottom parent-bottom) snap-width)
+                           snap-y (<= (- last-y snap-y) snap-width))
+                      ;; Stay snapped when the mouse moved downward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top (- parent-bottom native-height)))
+                     (t
+                      ;; Unsnap when the mouse moved downward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))))
+
+                ;; If requested, constrain FRAME's draggable areas to
+                ;; PARENT's edges.  The `top-visible' parameter should
+                ;; be set when FRAME has a draggable header-line.  If
+                ;; set to a number, it ascertains that the top of FRAME
+                ;; is always constrained to the top of PARENT and that
+                ;; at least as many pixels of FRAME as specified by that
+                ;; number are visible on each of the three remaining
+                ;; sides of PARENT.
+                ;;
+                ;; The `bottom-visible' parameter should be set when
+                ;; FRAME has a draggable mode-line.  If set to a number,
+                ;; it ascertains that the bottom of FRAME is always
+                ;; constrained to the bottom of PARENT and that at least
+                ;; as many pixels of FRAME as specified by that number
+                ;; are visible on each of the three remaining sides of
+                ;; PARENT.
+                (let ((par (frame-parameter frame 'top-visible))
+                      bottom-visible)
+                  (unless par
+                    (setq par (frame-parameter frame 'bottom-visible))
+                    (setq bottom-visible t))
+                  (when (and (numberp par) parent-edges)
+                    (setq left
+                          (max (min (- parent-right par) left)
+                               (+ (- parent-left native-width) par)))
+                    (setq top
+                          (if bottom-visible
+                              (min (max top (- parent-top (- native-height par)))
+                                   (- parent-bottom native-height))
+                            (min (max top parent-top)
+                                 (- parent-bottom par))))))
+                (if (fboundp 'x-set-frame-size-and-position)
+                    (x-set-frame-size-and-position
+                     frame first-width first-height left top)
+                  ;; Use `modify-frame-parameters' since `left' and `top'
+                  ;; may want to move FRAME out of its PARENT.
+                  (modify-frame-parameters frame `((left . (+ ,left)) (top . (+ ,top)))))))))
+	 (old-track-mouse track-mouse))
     ;; Start tracking.  The special value 'dragging' signals the
     ;; display engine to freeze the mouse pointer shape for as long
     ;; as we drag.
@@ -879,49 +964,49 @@ mouse-drag-left-edge
   "Drag left edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'left))
+  (mouse-drag-frame-resize start-event 'left))
 
 (defun mouse-drag-top-left-corner (start-event)
   "Drag top left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-left))
+  (mouse-drag-frame-resize start-event 'top-left))
 
 (defun mouse-drag-top-edge (start-event)
   "Drag top edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top))
+  (mouse-drag-frame-resize start-event 'top))
 
 (defun mouse-drag-top-right-corner (start-event)
   "Drag top right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-right))
+  (mouse-drag-frame-resize start-event 'top-right))
 
 (defun mouse-drag-right-edge (start-event)
   "Drag right edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'right))
+  (mouse-drag-frame-resize start-event 'right))
 
 (defun mouse-drag-bottom-right-corner (start-event)
   "Drag bottom right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-right))
+  (mouse-drag-frame-resize start-event 'bottom-right))
 
 (defun mouse-drag-bottom-edge (start-event)
   "Drag bottom edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom))
+  (mouse-drag-frame-resize start-event 'bottom))
 
 (defun mouse-drag-bottom-left-corner (start-event)
   "Drag bottom left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-left))
+  (mouse-drag-frame-resize start-event 'bottom-left))
 
 (defcustom mouse-select-region-move-to-beginning nil
   "Effect of selecting a region extending backward from double click.
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..cc2c7d9cec 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1003,6 +1003,9 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
 
       gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 			 totalwidth, totalheight);
+
+/**       if (FRAME_PARENT_FRAME (f)) **/
+/** 	gtk_container_check_resize (GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f))); **/
       fullscreen = Qnil;
     }
 
diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..97574a173b 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -861,6 +861,11 @@ x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu
 	(FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 	 p ? FRAME_X_WINDOW (p) : DefaultRootWindow (FRAME_X_DISPLAY (f)),
 	 f->left_pos, f->top_pos);
+#ifdef USE_GTK
+      gtk_container_set_resize_mode
+	(GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)),
+	 p ? GTK_RESIZE_IMMEDIATE : GTK_RESIZE_QUEUE);
+#endif
       unblock_input ();
 
       fset_parent_frame (f, new_value);
@@ -4084,6 +4089,10 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
       block_input ();
       XReparentWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 		       FRAME_X_WINDOW (p), f->left_pos, f->top_pos);
+#ifdef USE_GTK
+      gtk_container_set_resize_mode
+	(GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)), GTK_RESIZE_IMMEDIATE);
+#endif
       unblock_input ();
     }
 
@@ -7742,6 +7751,22 @@ frames (each of which corresponds to one page).  Each frame should be
 #endif	/* USE_GTK */
 #endif	/* USE_CAIRO */
 
+#ifdef USE_GTK
+#ifdef HAVE_GTK3
+DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0,
+       doc: /* Toggle interactive GTK debugging.   */)
+  (Lisp_Object enable)
+{
+  gboolean enable_debug = !NILP (enable);
+
+  block_input ();
+  gtk_window_set_interactive_debugging (enable_debug);
+  unblock_input ();
+
+  return NILP (enable) ? Qnil : Qt;
+}
+#endif /* HAVE_GTK3 */
+#endif	/* USE_GTK */
 \f
 /***********************************************************************
 			    Initialization
@@ -8101,4 +8126,9 @@ syms_of_xfns (void)
   defsubr (&Sx_print_frames_dialog);
 #endif
 #endif
+#ifdef USE_GTK
+#ifdef HAVE_GTK3
+  defsubr (&Sx_gtk_debug);
+#endif
+#endif
 }
diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..971f374764 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10612,26 +10612,29 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_
 	       modified_left, modified_top);
 #endif
 
-  x_sync_with_move (f, f->left_pos, f->top_pos,
-                    FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
-
-  /* change_gravity is non-zero when this function is called from Lisp to
-     programmatically move a frame.  In that case, we call
-     x_check_expected_move to discover if we have a "Type A" or "Type B"
-     window manager, and, for a "Type A" window manager, adjust the position
-     of the frame.
-
-     We call x_check_expected_move if a programmatic move occurred, and
-     either the window manager type (A/B) is unknown or it is Type A but we
-     need to compute the top/left offset adjustment for this frame.  */
-
-  if (change_gravity != 0
-      && !FRAME_PARENT_FRAME (f)
-      && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
-	  || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
-	      && (FRAME_X_OUTPUT (f)->move_offset_left == 0
-		  && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
-    x_check_expected_move (f, modified_left, modified_top);
+  /* 'x_sync_with_move' is too costly for dragging child frames.  */
+  if (!FRAME_PARENT_FRAME (f))
+    {
+      x_sync_with_move (f, f->left_pos, f->top_pos,
+			FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
+
+      /* change_gravity is non-zero when this function is called from Lisp to
+	 programmatically move a frame.  In that case, we call
+	 x_check_expected_move to discover if we have a "Type A" or "Type B"
+	 window manager, and, for a "Type A" window manager, adjust the position
+	 of the frame.
+
+	 We call x_check_expected_move if a programmatic move occurred, and
+	 either the window manager type (A/B) is unknown or it is Type A but we
+	 need to compute the top/left offset adjustment for this frame.  */
+
+      if (change_gravity != 0
+	  && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
+	      || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
+		  && (FRAME_X_OUTPUT (f)->move_offset_left == 0
+		      && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
+	x_check_expected_move (f, modified_left, modified_top);
+    }
 
   unblock_input ();
 }

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-26 17:30                                                                                                                                                       ` martin rudalics
  2020-02-28 16:32                                                                                                                                                         ` martin rudalics
@ 2020-03-06 23:03                                                                                                                                                         ` Dmitry Gutov
  1 sibling, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-03-06 23:03 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 26.02.2020 19:30, martin rudalics wrote:
> Been there, done that.  I also tried to set the alpha of the child frame
> to zero but apparently this won't work for child frames, regardless of
> whether they are override-redirect or not.  Can you change transparency
> of child frames (to make it 0 you have to set 'frame-alpha-lower-limit'
> first)?

I can't set it to be semi-transparent at all (changing the 'alpha' 
paramter seems to have no effect). Oh well.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-02-26 17:30                                                                                                                                                     ` martin rudalics
@ 2020-03-06 23:32                                                                                                                                                       ` Dmitry Gutov
  2020-03-09  9:03                                                                                                                                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-03-06 23:32 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 26.02.2020 19:30, martin rudalics wrote:
>  > I could ask why not omit the call to gtk_window_resize when 
> (totalwidth == gwidth && totalheight == gheight), but that would 
> probably only affect performance.
> 
> You mean like in the attached?  It hardly affects performance here.

That's what I meant, yes. After testing it, I'm also not sure if there's 
a real performance improvement there. But maybe this change wouldn't 
hurt either.

> I meanwhile did a full GNOME installation here, a somewhat nightmarish
> experience trying to get a system menu and task bar, recovering all the
> stolen key bindings, disabling the trackers ...  It strongly reminds me
> of Windows 10 where I never managed to fix all relevant issues.

Personally, I don't use the system menu, or a task bar. Only a dock on 
the left. But then again, I'm using the Unite extension that makes it 
behave like Ubuntu's Unity.

> Anyway, AFAICT the hide during resizing approach seems to be the only
> halfway working alternative at the moment.

That, or the patch using the obsolete gtk_container_set_resize_mode. I'm 
not 100% sure which is the best choice (you seem to be favoring the 
hiding approach, judging by the next paragraph), but the other one seems 
to provide a better experience in the use case I'm looking at. 
Especially when combined with (setq x-wait-for-event-timeout 0.0).

> It's also the only one that
> can show a scroll bar on a child frame (not necessarily right away but
> after one resize operation at least).  Which hints at some outer-window
> vs edit-window snafu but so far I have no idea where to look.

FWIW, I'm pretty sure 99.9% of users of child frames out there aren't 
going to enable scroll bars.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-04 17:29                                                                                                                                                                 ` martin rudalics
@ 2020-03-06 23:38                                                                                                                                                                   ` Dmitry Gutov
  2020-03-07  0:07                                                                                                                                                                   ` Dmitry Gutov
  1 sibling, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-03-06 23:38 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 04.03.2020 19:29, martin rudalics wrote:
>  > - The thing with "resize then refresh" is also here. When a frame is
>  > resized, two distinct phases are also visible sometimes. But if it's
>  > the best we can do with GTK... *shrug*
> 
> Have you ever tried setting 'x-wait-for-event-timeout' to zero?

I thought I tried this before, but now I tried it again, and yes, 
setting it to zero makes that weird effect go away (and setting it to 
0.1 makes the said effect come back).

So I don't see real downsides to that last patch you posted. Aside from 
using an obsolete interface, I suppose. And scrollbars, which nobody 
will use.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-04 17:29                                                                                                                                                                 ` martin rudalics
  2020-03-06 23:38                                                                                                                                                                   ` Dmitry Gutov
@ 2020-03-07  0:07                                                                                                                                                                   ` Dmitry Gutov
  1 sibling, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-03-07  0:07 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 04.03.2020 19:29, martin rudalics wrote:
> Right.  A similar thing happens with the toolbar I suppose.  You have to
> turn off all of them.  The situation is slightly better with GTK2 builds
> but there you can get strange resizing effects.  The only builds that
> here work sufficiently well are Lucid builds after bypassing a brutal
> hack that causes each single move to wait for half a second on platforms
> that do not report the frame position as we want them (patch attached).

I tried the "combined" patch in your attachment, and it seemed in good 
shape: no resizing issues with GTK3, no repositioning slowness with 
Lucid (and mouse dragging works too).

If we could get it into Emacs 27, that would be great.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-06 23:32                                                                                                                                                       ` Dmitry Gutov
@ 2020-03-09  9:03                                                                                                                                                         ` martin rudalics
  2020-03-12  0:22                                                                                                                                                           ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-03-09  9:03 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> Anyway, AFAICT the hide during resizing approach seems to be the only
 >> halfway working alternative at the moment.
 >
 > That, or the patch using the obsolete
 > gtk_container_set_resize_mode. I'm not 100% sure which is the best
 > choice (you seem to be favoring the hiding approach, judging by the
 > next paragraph), but the other one seems to provide a better
 > experience in the use case I'm looking at. Especially when combined
 > with (setq x-wait-for-event-timeout 0.0).

The problem is that the gtk_container_set_resize_mode patch might break
with the next update of mutter or GTK.  It also freezes Emacs on
desktops like kwin and xfwm and therefore must be made optional anyway.
I meanwhile tested some ten window managers and so far only the GNOME
and Budgie (both mutter based) desktops exhibit the resize problem.

So I intend to add an option, say 'x-gtk-resize-child-frames', that
would be nil by default and have the optional values say 'hide and
'resize-mode which would either use the hiding or the container based
approach to deal with the problem.

 >> It's also the only one that
 >> can show a scroll bar on a child frame (not necessarily right away but
 >> after one resize operation at least).  Which hints at some outer-window
 >> vs edit-window snafu but so far I have no idea where to look.
 >
 > FWIW, I'm pretty sure 99.9% of users of child frames out there aren't going to enable scroll bars.

Maybe.  The fact that it doesn't work with mutter still hints at a more
serious underlying problem.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-09  9:03                                                                                                                                                         ` martin rudalics
@ 2020-03-12  0:22                                                                                                                                                           ` Dmitry Gutov
  2020-03-12  8:23                                                                                                                                                             ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-03-12  0:22 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 09.03.2020 11:03, martin rudalics wrote:

>  > That, or the patch using the obsolete
>  > gtk_container_set_resize_mode. I'm not 100% sure which is the best
>  > choice (you seem to be favoring the hiding approach, judging by the
>  > next paragraph), but the other one seems to provide a better
>  > experience in the use case I'm looking at. Especially when combined
>  > with (setq x-wait-for-event-timeout 0.0).
> 
> The problem is that the gtk_container_set_resize_mode patch might break
> with the next update of mutter or GTK.

I wondered about that. But we'll probably release a new version of Emacs 
before then?

It might also send a stronger message to GTK/Mutter developers, who are 
not so fast to answer a bug report from a fellow GNU project.

> It also freezes Emacs on
> desktops like kwin and xfwm and therefore must be made optional anyway.

That's unfortunate. If there was a way to detect Mutter 
programmatically, maybe we should use that. Even if just to set the 
default value of the new variable you've described below.

> I meanwhile tested some ten window managers and so far only the GNOME
> and Budgie (both mutter based) desktops exhibit the resize problem.

Makes sense.

> So I intend to add an option, say 'x-gtk-resize-child-frames', that
> would be nil by default and have the optional values say 'hide and
> 'resize-mode which would either use the hiding or the container based
> approach to deal with the problem.

I think 'resize-mode' should be the main mode of operation for it. But 
if 'hide' wouldn't complicate the code too much, I can't really argue 
against it.

>  >> It's also the only one that
>  >> can show a scroll bar on a child frame (not necessarily right away but
>  >> after one resize operation at least).  Which hints at some outer-window
>  >> vs edit-window snafu but so far I have no idea where to look.
>  >
>  > FWIW, I'm pretty sure 99.9% of users of child frames out there aren't 
> going to enable scroll bars.
> 
> Maybe.  The fact that it doesn't work with mutter still hints at a more
> serious underlying problem.

A more serious problem in Mutter, seems like. But it's not a given, of 
course.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-12  0:22                                                                                                                                                           ` Dmitry Gutov
@ 2020-03-12  8:23                                                                                                                                                             ` martin rudalics
  2020-03-13 16:57                                                                                                                                                               ` Dmitry Gutov
  2020-04-06 22:51                                                                                                                                                               ` Dmitry Gutov
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-03-12  8:23 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 >> The problem is that the gtk_container_set_resize_mode patch might break
 >> with the next update of mutter or GTK.
 >
 > I wondered about that. But we'll probably release a new version of Emacs before then?

In either case it shouldn't bother us.  If it works, people may use it
and use the hiding approach if it doesn't.

 > It might also send a stronger message to GTK/Mutter developers, who
 > are not so fast to answer a bug report from a fellow GNU project.

We've fallen between two stools here: It's not precisely a mutter
problem - Lucid and Motif work there.  And it's not precisely a GTK3
problem because it works with all other window managers I know of.

 >> It also freezes Emacs on
 >> desktops like kwin and xfwm and therefore must be made optional anyway.
 >
 > That's unfortunate. If there was a way to detect Mutter programmatically, maybe we should use that. Even if just to set the default value of the new variable you've described below.

I've been trying to do that but it's unreliable (BTW mutter here
identifies itself as GNOME shell): We would have to test such an
automatism on all possible desktops people use.  So better leave that to
Emacs 28.

 > I think 'resize-mode' should be the main mode of operation for it. But if 'hide' wouldn't complicate the code too much, I can't really argue against it.

So far we have no proof that 'resize-mode' works for a sufficient number
of people.  Or did you have any feedback?

 > A more serious problem in Mutter, seems like. But it's not a given, of course.

mutter might not be bad ('focus-follows-mouse' nowhere works as well as
there) but I have no idea what goes on under its hood.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-12  8:23                                                                                                                                                             ` martin rudalics
@ 2020-03-13 16:57                                                                                                                                                               ` Dmitry Gutov
  2020-03-13 17:46                                                                                                                                                                 ` martin rudalics
  2020-04-06 22:51                                                                                                                                                               ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-03-13 16:57 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 12.03.2020 10:23, martin rudalics wrote:
>  >> The problem is that the gtk_container_set_resize_mode patch might break
>  >> with the next update of mutter or GTK.
>  >
>  > I wondered about that. But we'll probably release a new version of 
> Emacs before then?
> 
> In either case it shouldn't bother us.  If it works, people may use it
> and use the hiding approach if it doesn't.

With a custom var, you mean. OK.

>  > It might also send a stronger message to GTK/Mutter developers, who
>  > are not so fast to answer a bug report from a fellow GNU project.
> 
> We've fallen between two stools here: It's not precisely a mutter
> problem - Lucid and Motif work there.  And it's not precisely a GTK3
> problem because it works with all other window managers I know of.

IIUC though, the majority of the GTK developers work on GNOME and Mutter 
as well. If that's the case, asking for Mutter's developers' help makes 
sense anyway.

>  >> It also freezes Emacs on
>  >> desktops like kwin and xfwm and therefore must be made optional anyway.
>  >
>  > That's unfortunate. If there was a way to detect Mutter 
> programmatically, maybe we should use that. Even if just to set the 
> default value of the new variable you've described below.
> 
> I've been trying to do that but it's unreliable (BTW mutter here
> identifies itself as GNOME shell): We would have to test such an
> automatism on all possible desktops people use.  So better leave that to
> Emacs 28.

OK.

>  > I think 'resize-mode' should be the main mode of operation for it. 
> But if 'hide' wouldn't complicate the code too much, I can't really 
> argue against it.
> 
> So far we have no proof that 'resize-mode' works for a sufficient number
> of people.  Or did you have any feedback?

I asked that question today. Got one +1 so far: 
https://github.com/tumashu/company-posframe/issues/2#issuecomment-598809266



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-13 16:57                                                                                                                                                               ` Dmitry Gutov
@ 2020-03-13 17:46                                                                                                                                                                 ` martin rudalics
  2020-03-16 19:51                                                                                                                                                                   ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-03-13 17:46 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 1560 bytes --]

 > With a custom var, you mean. OK.

I attach the latest diff I made for Emacs 27.  The variable is called
'x-gtk-resize-child-frames' and may assume the values 'hide' and
'resize-mode' in addition to the default nil.  It should work for Emacs
28 as well but it would be important to test it on Emacs 27 for obvious
reasons.

Clearly, people might want to to set 'x-wait-for-event-timeout' to zero
as well and we should tell them so.  But here I can't observe that doing
so has any impact.

 > IIUC though, the majority of the GTK developers work on GNOME and
 > Mutter as well. If that's the case, asking for Mutter's developers'
 > help makes sense anyway.

It would make sense but if they don't respond ...

 > I asked that question today. Got one +1 so far: https://github.com/tumashu/company-posframe/issues/2#issuecomment-598809266

Not much so far.  In either case, whenever people report a "it changes
size somewhat half a second later" then this usually means that a frame
move occurred on a platform (like GNOME shell) that does not report a
frame position as Emacs expects it (Bug#38452), does not send a suitable
event in due time and is thereafter penalized by xterm.c's

   /* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
      will then return up-to-date position info. */

   wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0);

This should be bypassed by my patch but for non-child frames the delay
persists.  Users then might want to drop a couple of zeros from that
insane nanosecond argument.

martin

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: x-gtk-resize-child-frames.diff --]
[-- Type: text/x-patch; name="x-gtk-resize-child-frames.diff", Size: 40850 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index e58a2e6da1..9703d957d5 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -552,7 +552,7 @@ mouse-drag-mode-line
              (not (eq (window-frame minibuffer-window) frame))))
       ;; Drag frame when the window is on the bottom of its frame and
       ;; there is no minibuffer window below.
-      (mouse-drag-frame start-event 'move)))))
+      (mouse-drag-frame-move start-event)))))
 
 (defun mouse-drag-header-line (start-event)
   "Change the height of a window by dragging on its header line.
@@ -569,7 +569,7 @@ mouse-drag-header-line
         (mouse-drag-line start-event 'header)
       (let ((frame (window-frame window)))
         (when (frame-parameter frame 'drag-with-header-line)
-          (mouse-drag-frame start-event 'move))))))
+          (mouse-drag-frame-move start-event))))))
 
 (defun mouse-drag-vertical-line (start-event)
   "Change the width of a window by dragging on a vertical line.
@@ -577,46 +577,7 @@ mouse-drag-vertical-line
   (interactive "e")
   (mouse-drag-line start-event 'vertical))
 \f
-(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move)
-  "Helper function for `mouse-drag-frame'."
-  (let* ((frame-x-y (frame-position frame))
-         (frame-x (car frame-x-y))
-         (frame-y (cdr frame-x-y))
-         alist)
-    (if (> x-diff 0)
-        (when x-move
-          (setq x-diff (min x-diff frame-x))
-          (setq x-move (- frame-x x-diff)))
-      (let* ((min-width (frame-windows-min-size frame t nil t))
-             (min-diff (max 0 (- (frame-inner-width frame) min-width))))
-        (setq x-diff (max x-diff (- min-diff)))
-        (when x-move
-          (setq x-move (+ frame-x (- x-diff))))))
-
-    (if (> y-diff 0)
-        (when y-move
-          (setq y-diff (min y-diff frame-y))
-          (setq y-move (- frame-y y-diff)))
-      (let* ((min-height (frame-windows-min-size frame nil nil t))
-             (min-diff (max 0 (- (frame-inner-height frame) min-height))))
-        (setq y-diff (max y-diff (- min-diff)))
-        (when y-move
-          (setq y-move (+ frame-y (- y-diff))))))
-
-    (unless (zerop x-diff)
-      (when x-move
-        (push `(left . ,x-move) alist))
-      (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff)))
-            alist))
-    (unless (zerop y-diff)
-      (when y-move
-        (push `(top . ,y-move) alist))
-      (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff)))
-            alist))
-    (when alist
-      (modify-frame-parameters frame alist))))
-
-(defun mouse-drag-frame (start-event part)
+(defun mouse-drag-frame-resize (start-event part)
   "Drag a frame or one of its edges with the mouse.
 START-EVENT is the starting mouse event of the drag action.  Its
 position window denotes the frame that will be dragged.
@@ -635,9 +596,144 @@ mouse-drag-frame
          (frame (if (window-live-p window)
                     (window-frame window)
                   window))
-         (width (frame-native-width frame))
-         (height (frame-native-height frame))
-         ;; PARENT is the parent frame of FRAME or, if FRAME is a
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+         (first-top (cdr first-pos))
+	 (first-width (frame-text-width frame))
+	 (first-height (frame-text-height frame))
+	 ;; Don't let FRAME become less large than the size needed to
+	 ;; fit all of its windows.
+	 (min-text-width
+	  (+ (frame-windows-min-size frame t nil t)
+	     (- (frame-inner-width frame) first-width)))
+	 (min-text-height
+	  (+ (frame-windows-min-size frame nil nil t)
+	     (- (frame-inner-height frame) first-height)))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
+         ;; top-level frame, FRAME's workarea.
+         (parent (frame-parent frame))
+         (parent-edges
+          (if parent
+              (frame-edges parent)
+            (let* ((attributes
+                    (car (display-monitor-attributes-list)))
+                   (workarea (assq 'workarea attributes)))
+              (and workarea
+                   `(,(nth 1 workarea) ,(nth 2 workarea)
+                     ,(+ (nth 1 workarea) (nth 3 workarea))
+                     ,(+ (nth 2 workarea) (nth 4 workarea)))))))
+         (parent-left (and parent-edges (nth 0 parent-edges)))
+         (parent-top (and parent-edges (nth 1 parent-edges)))
+         (parent-right (and parent-edges (nth 2 parent-edges)))
+         (parent-bottom (and parent-edges (nth 3 parent-edges)))
+	 ;; Drag types.  drag-left/drag-right and drag-top/drag-bottom
+	 ;; are mutually exclusive.
+	 (drag-left (memq part '(bottom-left left top-left)))
+	 (drag-top (memq part '(top-left top top-right)))
+	 (drag-right (memq part '(top-right right bottom-right)))
+	 (drag-bottom (memq part '(bottom-right bottom bottom-left)))
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         (exitfun nil)
+         (move
+          (lambda (event)
+            (interactive "e")
+            (when (consp event)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+		     alist)
+                ;; We never want to warp the mouse position here.  When
+                ;; moving the mouse leftward or upward, then with a wide
+                ;; border the calculated left or top position of the
+                ;; frame could drop to a value less than zero depending
+                ;; on where precisely the mouse within the border.  We
+                ;; guard against this by never allowing the frame to
+                ;; move to a position less than zero here.  No such
+                ;; precautions are used for the right and bottom borders
+                ;; so with a large internal border parts of that border
+                ;; may disappear.
+                  (when (and drag-left (>= last-x parent-left)
+                             (>= (- first-width left) min-text-width))
+		    (push `(left . ,(max (+ first-left left) 0)) alist)
+		    (push `(width . (text-pixels . ,(- first-width left)))
+                          alist))
+	          (when (and drag-top (>= last-y parent-top)
+                             (>= (- first-height top) min-text-height))
+		    (push `(top . ,(max 0 (+ first-top top))) alist)
+		    (push `(height . (text-pixels . ,(- first-height top)))
+                          alist))
+	          (when (and drag-right (<= last-x parent-right)
+                             (>= (+ first-width left) min-text-width))
+		    (push `(width . (text-pixels . ,(+ first-width left)))
+                          alist))
+	          (when (and drag-bottom (<= last-y parent-bottom)
+                             (>= (+ first-height top) min-text-height))
+		    (push `(height . (text-pixels . ,(+ first-height top)))
+                          alist))
+	          (modify-frame-parameters frame alist)))))
+         (old-track-mouse track-mouse))
+    ;; Start tracking.  The special value 'dragging' signals the
+    ;; display engine to freeze the mouse pointer shape for as long
+    ;; as we drag.
+    (setq track-mouse 'dragging)
+    ;; Loop reading events and sampling the position of the mouse.
+    (setq exitfun
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [scroll-bar-movement] #'ignore)
+             (define-key map [mouse-movement] move)
+             ;; Swallow drag-mouse-1 events to avoid selecting some other window.
+             (define-key map [drag-mouse-1]
+               (lambda () (interactive) (funcall exitfun)))
+             ;; Some of the events will of course end up looked up
+             ;; with a mode-line, header-line or vertical-line prefix ...
+             (define-key map [mode-line] map)
+             (define-key map [header-line] map)
+             (define-key map [vertical-line] map)
+             ;; ... and some maybe even with a right- or bottom-divider
+             ;; prefix.
+             (define-key map [right-divider] map)
+             (define-key map [bottom-divider] map)
+             map)
+           t (lambda () (setq track-mouse old-track-mouse))))))
+
+(defun mouse-drag-frame-move (start-event)
+  "Drag a frame or one of its edges with the mouse.
+START-EVENT is the starting mouse event of the drag action.  Its
+position window denotes the frame that will be dragged.
+
+PART specifies the part that has been dragged and must be one of
+the symbols `left', `top', `right', `bottom', `top-left',
+`top-right', `bottom-left', `bottom-right' to drag an internal
+border or edge.  If PART equals `move', this means to move the
+frame with the mouse."
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
+  (let* ((echo-keystrokes 0)
+	 (start (event-start start-event))
+         (window (posn-window start))
+         ;; FRAME is the frame to drag.
+         (frame (if (window-live-p window)
+                    (window-frame window)
+                  window))
+         (native-width (frame-native-width frame))
+         (native-height (frame-native-height frame))
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+	 (first-top (cdr first-pos))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
          ;; top-level frame, FRAME's workarea.
          (parent (frame-parent frame))
          (parent-edges
@@ -654,19 +750,16 @@ mouse-drag-frame
          (parent-top (and parent-edges (nth 1 parent-edges)))
          (parent-right (and parent-edges (nth 2 parent-edges)))
          (parent-bottom (and parent-edges (nth 3 parent-edges)))
-         ;; `pos-x' and `pos-y' record the x- and y-coordinates of the
-	 ;; last sampled mouse position.  Note that we sample absolute
-	 ;; mouse positions to avoid that moving the mouse from one
-	 ;; frame into another gets into our way.  `last-x' and `last-y'
-	 ;; records the x- and y-coordinates of the previously sampled
-	 ;; position.  The differences between `last-x' and `pos-x' as
-	 ;; well as `last-y' and `pos-y' determine the amount the mouse
-	 ;; has been dragged between the last two samples.
-         pos-x-y pos-x pos-y
-         (last-x-y (mouse-absolute-pixel-position))
-         (last-x (car last-x-y))
-         (last-y (cdr last-x-y))
-         ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         ;; `snap-width' (maybe also a yet to be provided `snap-height')
+         ;; could become floats to handle proportionality wrt PARENT.
+         ;; We don't do any checks on this parameter so far.
+         (snap-width (frame-parameter frame 'snap-width))
+	 ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
          ;; mouse position when FRAME snapped.  As soon as the
          ;; difference between `pos-x' and `snap-x' (or `pos-y' and
          ;; `snap-y') exceeds the value of FRAME's `snap-width'
@@ -678,176 +771,141 @@ mouse-drag-frame
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (setq pos-x-y (mouse-absolute-pixel-position))
-              (setq pos-x (car pos-x-y))
-              (setq pos-y (cdr pos-x-y))
-              (cond
-               ((eq part 'left)
-                (mouse-resize-frame frame (- last-x pos-x) 0 t))
-               ((eq part 'top)
-                (mouse-resize-frame frame 0 (- last-y pos-y) nil t))
-               ((eq part 'right)
-                (mouse-resize-frame frame (- pos-x last-x) 0))
-               ((eq part 'bottom)
-                (mouse-resize-frame frame 0 (- pos-y last-y)))
-               ((eq part 'top-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- last-y pos-y) t t))
-               ((eq part 'top-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- last-y pos-y) nil t))
-               ((eq part 'bottom-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- pos-y last-y) t))
-               ((eq part 'bottom-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- pos-y last-y)))
-               ((eq part 'move)
-                (let* ((old-position (frame-position frame))
-                       (old-left (car old-position))
-                       (old-top (cdr old-position))
-                       (left (+ old-left (- pos-x last-x)))
-                       (top (+ old-top (- pos-y last-y)))
-                       right bottom
-                       ;; `snap-width' (maybe also a yet to be provided
-                       ;; `snap-height') could become floats to handle
-                       ;; proportionality wrt PARENT.  We don't do any
-                       ;; checks on this parameter so far.
-                       (snap-width (frame-parameter frame 'snap-width)))
-                  ;; Docking and constraining.
-                  (when (and (numberp snap-width) parent-edges)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+                     right bottom)
+		(setq left (+ first-left left))
+		(setq top (+ first-top top))
+                ;; Docking and constraining.
+                (when (and (numberp snap-width) parent-edges)
+                  (cond
+                   ;; Docking at the left parent edge.
+                   ((< last-x first-x)
                     (cond
-                     ;; Docking at the left parent edge.
-                     ((< pos-x last-x)
-                      (cond
-                       ((and (> left parent-left)
-                             (<= (- left parent-left) snap-width))
-                        ;; Snap when the mouse moved leftward and
-                        ;; FRAME's left edge would end up within
-                        ;; `snap-width' pixels from PARENT's left edge.
-                        (setq snap-x pos-x)
-                        (setq left parent-left))
-                       ((and (<= left parent-left)
-                             (<= (- parent-left left) snap-width)
-                             snap-x (<= (- snap-x pos-x) snap-width))
-                        ;; Stay snapped when the mouse moved leftward
-                        ;; but not more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq left parent-left))
-                       (t
-                        ;; Unsnap when the mouse moved more than
-                        ;; `snap-width' pixels leftward from the time
-                        ;; FRAME snapped.
-                        (setq snap-x nil))))
-                     ((> pos-x last-x)
-                      (setq right (+ left width))
-                      (cond
-                       ((and (< right parent-right)
-                             (<= (- parent-right right) snap-width))
-                        ;; Snap when the mouse moved rightward and
-                        ;; FRAME's right edge would end up within
-                        ;; `snap-width' pixels from PARENT's right edge.
-                        (setq snap-x pos-x)
-                        (setq left (- parent-right width)))
-                       ((and (>= right parent-right)
-                             (<= (- right parent-right) snap-width)
-                             snap-x (<= (- pos-x snap-x) snap-width))
-                        ;; Stay snapped when the mouse moved rightward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq left (- parent-right width)))
-                       (t
-                        ;; Unsnap when the mouse moved rightward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-x nil)))))
-
+                     ((and (> left parent-left)
+                           (<= (- left parent-left) snap-width))
+                      ;; Snap when the mouse moved leftward and FRAME's
+                      ;; left edge would end up within `snap-width'
+                      ;; pixels from PARENT's left edge.
+                      (setq snap-x last-x)
+                      (setq left parent-left))
+                     ((and (<= left parent-left)
+                           (<= (- parent-left left) snap-width)
+                           snap-x (<= (- snap-x last-x) snap-width))
+                      ;; Stay snapped when the mouse moved leftward but
+                      ;; not more than `snap-width' pixels from the time
+                      ;; FRAME snapped.
+                      (setq left parent-left))
+                     (t
+                      ;; Unsnap when the mouse moved more than
+                      ;; `snap-width' pixels leftward from the time
+                      ;; FRAME snapped.
+                      (setq snap-x nil))))
+                   ((> last-x first-x)
+                    (setq right (+ left native-width))
                     (cond
-                     ((< pos-y last-y)
-                      (cond
-                       ((and (> top parent-top)
-                             (<= (- top parent-top) snap-width))
-                        ;; Snap when the mouse moved upward and FRAME's
-                        ;; top edge would end up within `snap-width'
-                        ;; pixels from PARENT's top edge.
-                        (setq snap-y pos-y)
-                        (setq top parent-top))
-                       ((and (<= top parent-top)
-                             (<= (- parent-top top) snap-width)
-                             snap-y (<= (- snap-y pos-y) snap-width))
-                        ;; Stay snapped when the mouse moved upward but
-                        ;; not more more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq top parent-top))
-                       (t
-                        ;; Unsnap when the mouse moved upward more than
-                        ;; `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))
-                     ((> pos-y last-y)
-                      (setq bottom (+ top height))
-                      (cond
-                       ((and (< bottom parent-bottom)
-                             (<= (- parent-bottom bottom) snap-width))
-                        ;; Snap when the mouse moved downward and
-                        ;; FRAME's bottom edge would end up within
-                        ;; `snap-width' pixels from PARENT's bottom
-                        ;; edge.
-                        (setq snap-y pos-y)
-                        (setq top (- parent-bottom height)))
-                       ((and (>= bottom parent-bottom)
-                             (<= (- bottom parent-bottom) snap-width)
-                             snap-y (<= (- pos-y snap-y) snap-width))
-                        ;; Stay snapped when the mouse moved downward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq top (- parent-bottom height)))
-                       (t
-                        ;; Unsnap when the mouse moved downward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))))
-
-                  ;; If requested, constrain FRAME's draggable areas to
-                  ;; PARENT's edges.  The `top-visible' parameter should
-                  ;; be set when FRAME has a draggable header-line.  If
-                  ;; set to a number, it ascertains that the top of
-                  ;; FRAME is always constrained to the top of PARENT
-                  ;; and that at least as many pixels of FRAME as
-                  ;; specified by that number are visible on each of the
-                  ;; three remaining sides of PARENT.
-                  ;;
-                  ;; The `bottom-visible' parameter should be set when
-                  ;; FRAME has a draggable mode-line.  If set to a
-                  ;; number, it ascertains that the bottom of FRAME is
-                  ;; always constrained to the bottom of PARENT and that
-                  ;; at least as many pixels of FRAME as specified by
-                  ;; that number are visible on each of the three
-                  ;; remaining sides of PARENT.
-                  (let ((par (frame-parameter frame 'top-visible))
-                        bottom-visible)
-                    (unless par
-                      (setq par (frame-parameter frame 'bottom-visible))
-                      (setq bottom-visible t))
-                    (when (and (numberp par) parent-edges)
-                      (setq left
-                            (max (min (- parent-right par) left)
-                                 (+ (- parent-left width) par)))
-                      (setq top
-                            (if bottom-visible
-                                (min (max top (- parent-top (- height par)))
-                                     (- parent-bottom height))
-                              (min (max top parent-top)
-                                   (- parent-bottom par))))))
-
-                  ;; Use `modify-frame-parameters' since `left' and
-                  ;; `top' may want to move FRAME out of its PARENT.
-                  (modify-frame-parameters
-                   frame
-                   `((left . (+ ,left)) (top . (+ ,top)))))))
-              (setq last-x pos-x)
-              (setq last-y pos-y))))
-         (old-track-mouse track-mouse))
+                     ((and (< right parent-right)
+                           (<= (- parent-right right) snap-width))
+                      ;; Snap when the mouse moved rightward and FRAME's
+                      ;; right edge would end up within `snap-width'
+                      ;; pixels from PARENT's right edge.
+                      (setq snap-x last-x)
+                      (setq left (- parent-right native-width)))
+                     ((and (>= right parent-right)
+                           (<= (- right parent-right) snap-width)
+                           snap-x (<= (- last-x snap-x) snap-width))
+                      ;; Stay snapped when the mouse moved rightward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq left (- parent-right native-width)))
+                     (t
+                      ;; Unsnap when the mouse moved rightward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-x nil)))))
+                  (cond
+                   ((< last-y first-y)
+                    (cond
+                     ((and (> top parent-top)
+                           (<= (- top parent-top) snap-width))
+                      ;; Snap when the mouse moved upward and FRAME's
+                      ;; top edge would end up within `snap-width'
+                      ;; pixels from PARENT's top edge.
+                      (setq snap-y last-y)
+                      (setq top parent-top))
+                     ((and (<= top parent-top)
+                           (<= (- parent-top top) snap-width)
+                           snap-y (<= (- snap-y last-y) snap-width))
+                      ;; Stay snapped when the mouse moved upward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top parent-top))
+                     (t
+                      ;; Unsnap when the mouse moved upward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))
+                   ((> last-y first-y)
+                    (setq bottom (+ top native-height))
+                    (cond
+                     ((and (< bottom parent-bottom)
+                           (<= (- parent-bottom bottom) snap-width))
+                      ;; Snap when the mouse moved downward and FRAME's
+                      ;; bottom edge would end up within `snap-width'
+                      ;; pixels from PARENT's bottom edge.
+                      (setq snap-y last-y)
+                      (setq top (- parent-bottom native-height)))
+                     ((and (>= bottom parent-bottom)
+                           (<= (- bottom parent-bottom) snap-width)
+                           snap-y (<= (- last-y snap-y) snap-width))
+                      ;; Stay snapped when the mouse moved downward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top (- parent-bottom native-height)))
+                     (t
+                      ;; Unsnap when the mouse moved downward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))))
+
+                ;; If requested, constrain FRAME's draggable areas to
+                ;; PARENT's edges.  The `top-visible' parameter should
+                ;; be set when FRAME has a draggable header-line.  If
+                ;; set to a number, it ascertains that the top of FRAME
+                ;; is always constrained to the top of PARENT and that
+                ;; at least as many pixels of FRAME as specified by that
+                ;; number are visible on each of the three remaining
+                ;; sides of PARENT.
+                ;;
+                ;; The `bottom-visible' parameter should be set when
+                ;; FRAME has a draggable mode-line.  If set to a number,
+                ;; it ascertains that the bottom of FRAME is always
+                ;; constrained to the bottom of PARENT and that at least
+                ;; as many pixels of FRAME as specified by that number
+                ;; are visible on each of the three remaining sides of
+                ;; PARENT.
+                (let ((par (frame-parameter frame 'top-visible))
+                      bottom-visible)
+                  (unless par
+                    (setq par (frame-parameter frame 'bottom-visible))
+                    (setq bottom-visible t))
+                  (when (and (numberp par) parent-edges)
+                    (setq left
+                          (max (min (- parent-right par) left)
+                               (+ (- parent-left native-width) par)))
+                    (setq top
+                          (if bottom-visible
+                              (min (max top (- parent-top (- native-height par)))
+                                   (- parent-bottom native-height))
+                            (min (max top parent-top)
+                                 (- parent-bottom par))))))
+                ;; Use `modify-frame-parameters' since `left' and `top'
+                ;; may want to move FRAME out of its PARENT.
+                (modify-frame-parameters frame `((left . (+ ,left)) (top . (+ ,top))))))))
+	 (old-track-mouse track-mouse))
     ;; Start tracking.  The special value 'dragging' signals the
     ;; display engine to freeze the mouse pointer shape for as long
     ;; as we drag.
@@ -879,49 +937,49 @@ mouse-drag-left-edge
   "Drag left edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'left))
+  (mouse-drag-frame-resize start-event 'left))
 
 (defun mouse-drag-top-left-corner (start-event)
   "Drag top left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-left))
+  (mouse-drag-frame-resize start-event 'top-left))
 
 (defun mouse-drag-top-edge (start-event)
   "Drag top edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top))
+  (mouse-drag-frame-resize start-event 'top))
 
 (defun mouse-drag-top-right-corner (start-event)
   "Drag top right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-right))
+  (mouse-drag-frame-resize start-event 'top-right))
 
 (defun mouse-drag-right-edge (start-event)
   "Drag right edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'right))
+  (mouse-drag-frame-resize start-event 'right))
 
 (defun mouse-drag-bottom-right-corner (start-event)
   "Drag bottom right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-right))
+  (mouse-drag-frame-resize start-event 'bottom-right))
 
 (defun mouse-drag-bottom-edge (start-event)
   "Drag bottom edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom))
+  (mouse-drag-frame-resize start-event 'bottom))
 
 (defun mouse-drag-bottom-left-corner (start-event)
   "Drag bottom left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-left))
+  (mouse-drag-frame-resize start-event 'bottom-left))
 
 (defcustom mouse-select-region-move-to-beginning nil
   "Effect of selecting a region extending backward from double click.
diff --git a/src/frame.c b/src/frame.c
index 88d6f22fc0..9ec5c24b22 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -5941,6 +5941,7 @@ syms_of_frame (void)
   DEFSYM (Qxg_frame_set_char_size_1, "xg-frame-set-char-size-1");
   DEFSYM (Qxg_frame_set_char_size_2, "xg-frame-set-char-size-2");
   DEFSYM (Qxg_frame_set_char_size_3, "xg-frame-set-char-size-3");
+  DEFSYM (Qxg_frame_set_char_size_4, "xg-frame-set-char-size-4");
   DEFSYM (Qx_set_window_size_1, "x-set-window-size-1");
   DEFSYM (Qx_set_window_size_2, "x-set-window-size-2");
   DEFSYM (Qx_set_window_size_3, "x-set-window-size-3");
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..4cab8a5706 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -940,9 +940,8 @@ xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight)
     }
 }
 
-/* Resize the outer window of frame F after changing the height.
-   COLUMNS/ROWS is the size the edit area shall have after the resize.  */
-
+/** Resize the outer window of frame F.  WIDTH and HEIGHT are the new
+    pixel sizes of F's text area.  */
 void
 xg_frame_set_char_size (struct frame *f, int width, int height)
 {
@@ -953,6 +952,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
   int totalheight
     = pixelheight + FRAME_TOOLBAR_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
   int totalwidth = pixelwidth + FRAME_TOOLBAR_WIDTH (f);
+  bool was_visible = false;
 
   if (FRAME_PIXEL_HEIGHT (f) == 0)
     return;
@@ -995,12 +995,35 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
       gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 			 totalwidth, gheight);
     }
+  else if (FRAME_PARENT_FRAME (f) && FRAME_VISIBLE_P (f)
+	   && EQ (x_gtk_resize_child_frames, Qhide))
+    {
+      was_visible = true;
+
+      if (totalwidth != gwidth || totalheight != gheight)
+	{
+	  frame_size_history_add
+	    (f, Qxg_frame_set_char_size_4, width, height,
+	     list2i (totalwidth, totalheight));
+	  block_input ();
+	  gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
+	  unblock_input ();
+
+	  gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+			     totalwidth, totalheight);
+
+	  block_input ();
+	  gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
+	  unblock_input ();
+
+	  fullscreen = Qnil;
+	}
+    }
   else
     {
       frame_size_history_add
 	(f, Qxg_frame_set_char_size_3, width, height,
 	 list2i (totalwidth, totalheight));
-
       gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 			 totalwidth, totalheight);
       fullscreen = Qnil;
@@ -1016,7 +1039,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
      size as fast as possible.
      For unmapped windows, we can set rows/cols.  When
      the frame is mapped again we will (hopefully) get the correct size.  */
-  if (FRAME_VISIBLE_P (f))
+  if (FRAME_VISIBLE_P (f) && !was_visible)
     {
       /* Must call this to flush out events */
       (void)gtk_events_pending ();
diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..f32056ff03 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -861,6 +861,12 @@ x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu
 	(FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 	 p ? FRAME_X_WINDOW (p) : DefaultRootWindow (FRAME_X_DISPLAY (f)),
 	 f->left_pos, f->top_pos);
+#ifdef USE_GTK
+      if (EQ (x_gtk_resize_child_frames, Qresize_mode))
+	gtk_container_set_resize_mode
+	  (GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)),
+	   p ? GTK_RESIZE_IMMEDIATE : GTK_RESIZE_QUEUE);
+#endif
       unblock_input ();
 
       fset_parent_frame (f, new_value);
@@ -4084,6 +4090,11 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
       block_input ();
       XReparentWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 		       FRAME_X_WINDOW (p), f->left_pos, f->top_pos);
+#ifdef USE_GTK
+      if (EQ (x_gtk_resize_child_frames, Qresize_mode))
+	gtk_container_set_resize_mode
+	  (GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)), GTK_RESIZE_IMMEDIATE);
+#endif
       unblock_input ();
     }
 
@@ -7742,6 +7753,22 @@ frames (each of which corresponds to one page).  Each frame should be
 #endif	/* USE_GTK */
 #endif	/* USE_CAIRO */
 
+#ifdef USE_GTK
+#ifdef HAVE_GTK3
+DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0,
+       doc: /* Toggle interactive GTK debugging.   */)
+  (Lisp_Object enable)
+{
+  gboolean enable_debug = !NILP (enable);
+
+  block_input ();
+  gtk_window_set_interactive_debugging (enable_debug);
+  unblock_input ();
+
+  return NILP (enable) ? Qnil : Qt;
+}
+#endif /* HAVE_GTK3 */
+#endif	/* USE_GTK */
 \f
 /***********************************************************************
 			    Initialization
@@ -7810,6 +7837,8 @@ syms_of_xfns (void)
   DEFSYM (Qfont_parameter, "font-parameter");
   DEFSYM (Qmono, "mono");
   DEFSYM (Qassq_delete_all, "assq-delete-all");
+  DEFSYM (Qhide, "hide");
+  DEFSYM (Qresize_mode, "resize-mode");
 
 #ifdef USE_CAIRO
   DEFSYM (Qpdf, "pdf");
@@ -7986,6 +8015,28 @@ syms_of_xfns (void)
 When using Gtk+ tooltips, the tooltip face is not used.  */);
   x_gtk_use_system_tooltips = true;
 
+  DEFVAR_LISP ("x-gtk-resize-child-frames", x_gtk_resize_child_frames,
+    doc: /* If non-nil, resize child frames specially with GTK builds.
+If this is nil, resize child frames like any other frames.  This is the
+default and usually works with most desktops.  Some desktop environments
+(GNOME shell in particular when using the mutter window manager),
+however, may refuse to resize a child frame when Emacs is built with
+GTK3.  For those environments, the two settings below are provided.
+
+If this equals the symbol 'hide', Emacs temporarily hides the child
+frame during resizing.  This approach seems to work reliably, may
+however induce some flicker when the frame is made visible again.
+
+If this equals the symbol 'resize-mode', Emacs uses GTK's resize mode to
+always trigger an immediate resize of the child frame.  This method is
+deprecated by GTK and may not work in future versions of that toolkit.
+It also may freeze Emacs when used with other desktop environments.  It
+avoids, however, the unpleasent flicker induced by the hiding approach.
+
+This variable is considered a temporary workaround and will be hopefully
+eliminated in future versions of Emacs.  */);
+  x_gtk_resize_child_frames = Qnil;
+
   /* Tell Emacs about this window system.  */
   Fprovide (Qx, Qnil);
 
@@ -8101,4 +8152,9 @@ syms_of_xfns (void)
   defsubr (&Sx_print_frames_dialog);
 #endif
 #endif
+#ifdef USE_GTK
+#ifdef HAVE_GTK3
+  defsubr (&Sx_gtk_debug);
+#endif
+#endif
 }
diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..971f374764 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10612,26 +10612,29 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_
 	       modified_left, modified_top);
 #endif
 
-  x_sync_with_move (f, f->left_pos, f->top_pos,
-                    FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
-
-  /* change_gravity is non-zero when this function is called from Lisp to
-     programmatically move a frame.  In that case, we call
-     x_check_expected_move to discover if we have a "Type A" or "Type B"
-     window manager, and, for a "Type A" window manager, adjust the position
-     of the frame.
-
-     We call x_check_expected_move if a programmatic move occurred, and
-     either the window manager type (A/B) is unknown or it is Type A but we
-     need to compute the top/left offset adjustment for this frame.  */
-
-  if (change_gravity != 0
-      && !FRAME_PARENT_FRAME (f)
-      && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
-	  || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
-	      && (FRAME_X_OUTPUT (f)->move_offset_left == 0
-		  && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
-    x_check_expected_move (f, modified_left, modified_top);
+  /* 'x_sync_with_move' is too costly for dragging child frames.  */
+  if (!FRAME_PARENT_FRAME (f))
+    {
+      x_sync_with_move (f, f->left_pos, f->top_pos,
+			FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
+
+      /* change_gravity is non-zero when this function is called from Lisp to
+	 programmatically move a frame.  In that case, we call
+	 x_check_expected_move to discover if we have a "Type A" or "Type B"
+	 window manager, and, for a "Type A" window manager, adjust the position
+	 of the frame.
+
+	 We call x_check_expected_move if a programmatic move occurred, and
+	 either the window manager type (A/B) is unknown or it is Type A but we
+	 need to compute the top/left offset adjustment for this frame.  */
+
+      if (change_gravity != 0
+	  && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
+	      || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
+		  && (FRAME_X_OUTPUT (f)->move_offset_left == 0
+		      && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
+	x_check_expected_move (f, modified_left, modified_top);
+    }
 
   unblock_input ();
 }

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-13 17:46                                                                                                                                                                 ` martin rudalics
@ 2020-03-16 19:51                                                                                                                                                                   ` Dmitry Gutov
  2020-03-17  9:38                                                                                                                                                                     ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-03-16 19:51 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 13.03.2020 19:46, martin rudalics wrote:
>  > With a custom var, you mean. OK.
> 
> I attach the latest diff I made for Emacs 27.  The variable is called
> 'x-gtk-resize-child-frames' and may assume the values 'hide' and
> 'resize-mode' in addition to the default nil.  It should work for Emacs
> 28 as well but it would be important to test it on Emacs 27 for obvious
> reasons.

I've tried the patch, and the behavior is as expected: the value 'hide' 
makes it blink, and 'resize-mode' makes it work correctly.

One unfortunate aspect of making it a custom var is it only works if set 
before the child frame was created. And posframe caches created frames, 
either because child frame creation is expensive, or was such previously.

So if the user sees the problem, searches for a solution, then applies 
it in the current session, they won't see the change. We'll have to say 
"and restart Emacs" in the doc, and hope they won't miss that.

> Clearly, people might want to to set 'x-wait-for-event-timeout' to zero
> as well and we should tell them so.  But here I can't observe that doing
> so has any impact.

It does have impact on my machine.

>  > IIUC though, the majority of the GTK developers work on GNOME and
>  > Mutter as well. If that's the case, asking for Mutter's developers'
>  > help makes sense anyway.
> 
> It would make sense but if they don't respond ...
> 
>  > I asked that question today. Got one +1 so far: 
> https://github.com/tumashu/company-posframe/issues/2#issuecomment-598809266
> 
> Not much so far.

Since then we have another +1 in the issue comments above, as well as an 
additional solid thumbs up on the patch from the first reporter.

> In either case, whenever people report a "it changes
> size somewhat half a second later" then this usually means that a frame
> move occurred on a platform (like GNOME shell) that does not report a
> frame position as Emacs expects it (Bug#38452), does not send a suitable
> event in due time and is thereafter penalized by xterm.c's
> 
>    /* As a last resort, just wait 0.5 seconds and hope that XGetGeometry
>       will then return up-to-date position info. */
> 
>    wait_reading_process_output (0, 500000000, 0, false, Qnil, NULL, 0);
> 
> This should be bypassed by my patch but for non-child frames the delay
> persists.  Users then might want to drop a couple of zeros from that
> insane nanosecond argument.

I've never seen a "half a second" later problem myself, and the person 
who complained says he doesn't see that anymore [for some reason]. So 
maybe we can leave that alone for now.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-16 19:51                                                                                                                                                                   ` Dmitry Gutov
@ 2020-03-17  9:38                                                                                                                                                                     ` martin rudalics
  2020-03-17 11:22                                                                                                                                                                       ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-03-17  9:38 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > One unfortunate aspect of making it a custom var is it only works if
 > set before the child frame was created. And posframe caches created
 > frames, either because child frame creation is expensive, or was such
 > previously.
 >
 > So if the user sees the problem, searches for a solution, then applies
 > it in the current session, they won't see the change. We'll have to
 > say "and restart Emacs" in the doc, and hope they won't miss that.

The hiding approach should work out of the box unless I'm missing
something.  The resize-mode approach OTOH is sufficiently dangerous for
non-GNOME-shell users in order to warrant a restart after having read
the doc carefully.

 > I've never seen a "half a second" later problem myself, and the person
 > who complained says he doesn't see that anymore [for some reason]. So
 > maybe we can leave that alone for now.

You certainly have at the time you complained about the persisting
slowness of dragging Lucid child frames.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-17  9:38                                                                                                                                                                     ` martin rudalics
@ 2020-03-17 11:22                                                                                                                                                                       ` Dmitry Gutov
  2020-03-31 17:04                                                                                                                                                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-03-17 11:22 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 17.03.2020 11:38, martin rudalics wrote:
> The hiding approach should work out of the box unless I'm missing
> something.

Yes, true.

> The resize-mode approach OTOH is sufficiently dangerous for
> non-GNOME-shell users in order to warrant a restart after having read
> the doc carefully. 

Fair enough.

> You certainly have at the time you complained about 
> the persisting
> slowness of dragging Lucid child frames.

With Lucid ones, yes. But that build has been very snappy with the 
recent patches.

And Andrey complained about something like that with the GTK3 build 
(IIUC), which I can't reproduce, and it seems neither can he anymore.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-17 11:22                                                                                                                                                                       ` Dmitry Gutov
@ 2020-03-31 17:04                                                                                                                                                                         ` martin rudalics
  2020-04-03 11:09                                                                                                                                                                           ` Eli Zaretskii
  2020-04-12  6:44                                                                                                                                                                           ` Andreas Schwab
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-03-31 17:04 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

[-- Attachment #1: Type: text/plain, Size: 2791 bytes --]

OK.  Eli, I would like to install the attached patch for Emacs 27.  All
changes affect the resizing and moving of child frames only, normal
frames are not affected.  The Change Log below tries to explain why they
are needed.  One change (the addition of Fx_gtk_debug) is not needed but
might be useful in order to debug GTK issues from inside Emacs if and
when we receive more bug reports in this area.

martin


Fix problems with moving and resizing child frames

(1) Re-implement 'mouse-drag-frame' via two new functions
'mouse-drag-frame-resize' and 'mouse-drag-frame-move'.  This is
needed because with some toolkits the notifications for frame
movement and resizing arrive asynchronously, breaking any
calculations using intermediate frame sizes and positions.
(2) Provide new option 'x-gtk-resize-child-frames' which allows
to either hide a child frame during resizing or asks GTK to
resize it "immediately".  This is needed because desktops like
GNOME shell otherwise won't allow resizing child frames at all.
(3) Do not try to synchronize the position of a child frame
after moving it.  Needed because the present implementation
introduces a 0.5 secs delay which makes dragging child frames
virtually impossible with Lucid and Motif toolkits on desktops
like GNOME shell that use invisible outer frame borders.

For further information see the thread starting with
https://lists.gnu.org/archive/html/emacs-devel/2020-01/msg00343.html

* lisp/mouse.el (mouse-drag-mode-line, mouse-drag-left-edge)
(mouse-drag-top-left-corner, mouse-drag-top-edge)
(mouse-drag-top-right-corner, mouse-drag-right-edge)
(mouse-drag-bottom-right-corner, mouse-drag-bottom-edge)
(mouse-drag-bottom-left-corner): Call 'mouse-drag-frame-resize'
instead of 'mouse-drag-frame'.
(mouse-drag-frame): Split into two new functions -
'mouse-drag-frame-move' and 'mouse-drag-frame-resize'.
(mouse-drag-frame-resize, mouse-drag-frame-move): New functions
to implement functionality of the removed 'mouse-drag-frame'.
* src/frame.c (syms_of_frame): New symbol Qxg_frame_set_char_size_4
* src/gtkutil.c (xg_frame_set_char_size): Hide frame
during resizing when 'x-gtk-resize-child-frames' equals 'hide'.
* src/xfns.c (x_set_parent_frame, Fx_create_frame): Set
gtk_container_resize_mode to GTK_RESIZE_IMMEDIATE
when'x-gtk-resize-child-frames' equals 'resize-mode'.
(Fx_gtk_debug): New function to toggle interactive GTK debugging
from within Emacs.
(syms_of_xfns): New symbols Qhide and Qresize_mode.
(x-gtk-resize-child-frames): New option that allows to resize
child frames on desktops like GNOME shell (with the mutter WM)
that generally refuse to resize them.
* src/xterm.c (x_set_offset): Don't x_sync_with_move for child
frames, it makes moving child frames virtually impossible with
the Lucid and Motif toolkits.

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: x-gtk-resize-child-frames.diff --]
[-- Type: text/x-patch; name="x-gtk-resize-child-frames.diff", Size: 40850 bytes --]

diff --git a/lisp/mouse.el b/lisp/mouse.el
index e58a2e6da1..9703d957d5 100644
--- a/lisp/mouse.el
+++ b/lisp/mouse.el
@@ -552,7 +552,7 @@ mouse-drag-mode-line
              (not (eq (window-frame minibuffer-window) frame))))
       ;; Drag frame when the window is on the bottom of its frame and
       ;; there is no minibuffer window below.
-      (mouse-drag-frame start-event 'move)))))
+      (mouse-drag-frame-move start-event)))))
 
 (defun mouse-drag-header-line (start-event)
   "Change the height of a window by dragging on its header line.
@@ -569,7 +569,7 @@ mouse-drag-header-line
         (mouse-drag-line start-event 'header)
       (let ((frame (window-frame window)))
         (when (frame-parameter frame 'drag-with-header-line)
-          (mouse-drag-frame start-event 'move))))))
+          (mouse-drag-frame-move start-event))))))
 
 (defun mouse-drag-vertical-line (start-event)
   "Change the width of a window by dragging on a vertical line.
@@ -577,46 +577,7 @@ mouse-drag-vertical-line
   (interactive "e")
   (mouse-drag-line start-event 'vertical))
 \f
-(defun mouse-resize-frame (frame x-diff y-diff &optional x-move y-move)
-  "Helper function for `mouse-drag-frame'."
-  (let* ((frame-x-y (frame-position frame))
-         (frame-x (car frame-x-y))
-         (frame-y (cdr frame-x-y))
-         alist)
-    (if (> x-diff 0)
-        (when x-move
-          (setq x-diff (min x-diff frame-x))
-          (setq x-move (- frame-x x-diff)))
-      (let* ((min-width (frame-windows-min-size frame t nil t))
-             (min-diff (max 0 (- (frame-inner-width frame) min-width))))
-        (setq x-diff (max x-diff (- min-diff)))
-        (when x-move
-          (setq x-move (+ frame-x (- x-diff))))))
-
-    (if (> y-diff 0)
-        (when y-move
-          (setq y-diff (min y-diff frame-y))
-          (setq y-move (- frame-y y-diff)))
-      (let* ((min-height (frame-windows-min-size frame nil nil t))
-             (min-diff (max 0 (- (frame-inner-height frame) min-height))))
-        (setq y-diff (max y-diff (- min-diff)))
-        (when y-move
-          (setq y-move (+ frame-y (- y-diff))))))
-
-    (unless (zerop x-diff)
-      (when x-move
-        (push `(left . ,x-move) alist))
-      (push `(width . (text-pixels . ,(+ (frame-text-width frame) x-diff)))
-            alist))
-    (unless (zerop y-diff)
-      (when y-move
-        (push `(top . ,y-move) alist))
-      (push `(height . (text-pixels . ,(+ (frame-text-height frame) y-diff)))
-            alist))
-    (when alist
-      (modify-frame-parameters frame alist))))
-
-(defun mouse-drag-frame (start-event part)
+(defun mouse-drag-frame-resize (start-event part)
   "Drag a frame or one of its edges with the mouse.
 START-EVENT is the starting mouse event of the drag action.  Its
 position window denotes the frame that will be dragged.
@@ -635,9 +596,144 @@ mouse-drag-frame
          (frame (if (window-live-p window)
                     (window-frame window)
                   window))
-         (width (frame-native-width frame))
-         (height (frame-native-height frame))
-         ;; PARENT is the parent frame of FRAME or, if FRAME is a
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+         (first-top (cdr first-pos))
+	 (first-width (frame-text-width frame))
+	 (first-height (frame-text-height frame))
+	 ;; Don't let FRAME become less large than the size needed to
+	 ;; fit all of its windows.
+	 (min-text-width
+	  (+ (frame-windows-min-size frame t nil t)
+	     (- (frame-inner-width frame) first-width)))
+	 (min-text-height
+	  (+ (frame-windows-min-size frame nil nil t)
+	     (- (frame-inner-height frame) first-height)))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
+         ;; top-level frame, FRAME's workarea.
+         (parent (frame-parent frame))
+         (parent-edges
+          (if parent
+              (frame-edges parent)
+            (let* ((attributes
+                    (car (display-monitor-attributes-list)))
+                   (workarea (assq 'workarea attributes)))
+              (and workarea
+                   `(,(nth 1 workarea) ,(nth 2 workarea)
+                     ,(+ (nth 1 workarea) (nth 3 workarea))
+                     ,(+ (nth 2 workarea) (nth 4 workarea)))))))
+         (parent-left (and parent-edges (nth 0 parent-edges)))
+         (parent-top (and parent-edges (nth 1 parent-edges)))
+         (parent-right (and parent-edges (nth 2 parent-edges)))
+         (parent-bottom (and parent-edges (nth 3 parent-edges)))
+	 ;; Drag types.  drag-left/drag-right and drag-top/drag-bottom
+	 ;; are mutually exclusive.
+	 (drag-left (memq part '(bottom-left left top-left)))
+	 (drag-top (memq part '(top-left top top-right)))
+	 (drag-right (memq part '(top-right right bottom-right)))
+	 (drag-bottom (memq part '(bottom-right bottom bottom-left)))
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         (exitfun nil)
+         (move
+          (lambda (event)
+            (interactive "e")
+            (when (consp event)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+		     alist)
+                ;; We never want to warp the mouse position here.  When
+                ;; moving the mouse leftward or upward, then with a wide
+                ;; border the calculated left or top position of the
+                ;; frame could drop to a value less than zero depending
+                ;; on where precisely the mouse within the border.  We
+                ;; guard against this by never allowing the frame to
+                ;; move to a position less than zero here.  No such
+                ;; precautions are used for the right and bottom borders
+                ;; so with a large internal border parts of that border
+                ;; may disappear.
+                  (when (and drag-left (>= last-x parent-left)
+                             (>= (- first-width left) min-text-width))
+		    (push `(left . ,(max (+ first-left left) 0)) alist)
+		    (push `(width . (text-pixels . ,(- first-width left)))
+                          alist))
+	          (when (and drag-top (>= last-y parent-top)
+                             (>= (- first-height top) min-text-height))
+		    (push `(top . ,(max 0 (+ first-top top))) alist)
+		    (push `(height . (text-pixels . ,(- first-height top)))
+                          alist))
+	          (when (and drag-right (<= last-x parent-right)
+                             (>= (+ first-width left) min-text-width))
+		    (push `(width . (text-pixels . ,(+ first-width left)))
+                          alist))
+	          (when (and drag-bottom (<= last-y parent-bottom)
+                             (>= (+ first-height top) min-text-height))
+		    (push `(height . (text-pixels . ,(+ first-height top)))
+                          alist))
+	          (modify-frame-parameters frame alist)))))
+         (old-track-mouse track-mouse))
+    ;; Start tracking.  The special value 'dragging' signals the
+    ;; display engine to freeze the mouse pointer shape for as long
+    ;; as we drag.
+    (setq track-mouse 'dragging)
+    ;; Loop reading events and sampling the position of the mouse.
+    (setq exitfun
+          (set-transient-map
+           (let ((map (make-sparse-keymap)))
+             (define-key map [switch-frame] #'ignore)
+             (define-key map [select-window] #'ignore)
+             (define-key map [scroll-bar-movement] #'ignore)
+             (define-key map [mouse-movement] move)
+             ;; Swallow drag-mouse-1 events to avoid selecting some other window.
+             (define-key map [drag-mouse-1]
+               (lambda () (interactive) (funcall exitfun)))
+             ;; Some of the events will of course end up looked up
+             ;; with a mode-line, header-line or vertical-line prefix ...
+             (define-key map [mode-line] map)
+             (define-key map [header-line] map)
+             (define-key map [vertical-line] map)
+             ;; ... and some maybe even with a right- or bottom-divider
+             ;; prefix.
+             (define-key map [right-divider] map)
+             (define-key map [bottom-divider] map)
+             map)
+           t (lambda () (setq track-mouse old-track-mouse))))))
+
+(defun mouse-drag-frame-move (start-event)
+  "Drag a frame or one of its edges with the mouse.
+START-EVENT is the starting mouse event of the drag action.  Its
+position window denotes the frame that will be dragged.
+
+PART specifies the part that has been dragged and must be one of
+the symbols `left', `top', `right', `bottom', `top-left',
+`top-right', `bottom-left', `bottom-right' to drag an internal
+border or edge.  If PART equals `move', this means to move the
+frame with the mouse."
+  ;; Give temporary modes such as isearch a chance to turn off.
+  (run-hooks 'mouse-leave-buffer-hook)
+  (let* ((echo-keystrokes 0)
+	 (start (event-start start-event))
+         (window (posn-window start))
+         ;; FRAME is the frame to drag.
+         (frame (if (window-live-p window)
+                    (window-frame window)
+                  window))
+         (native-width (frame-native-width frame))
+         (native-height (frame-native-height frame))
+	 ;; Initial "first" frame position and size.  While dragging we
+	 ;; base all calculations against that size and position.
+	 (first-pos (frame-position frame))
+	 (first-left (car first-pos))
+	 (first-top (cdr first-pos))
+	 ;; PARENT is the parent frame of FRAME or, if FRAME is a
          ;; top-level frame, FRAME's workarea.
          (parent (frame-parent frame))
          (parent-edges
@@ -654,19 +750,16 @@ mouse-drag-frame
          (parent-top (and parent-edges (nth 1 parent-edges)))
          (parent-right (and parent-edges (nth 2 parent-edges)))
          (parent-bottom (and parent-edges (nth 3 parent-edges)))
-         ;; `pos-x' and `pos-y' record the x- and y-coordinates of the
-	 ;; last sampled mouse position.  Note that we sample absolute
-	 ;; mouse positions to avoid that moving the mouse from one
-	 ;; frame into another gets into our way.  `last-x' and `last-y'
-	 ;; records the x- and y-coordinates of the previously sampled
-	 ;; position.  The differences between `last-x' and `pos-x' as
-	 ;; well as `last-y' and `pos-y' determine the amount the mouse
-	 ;; has been dragged between the last two samples.
-         pos-x-y pos-x pos-y
-         (last-x-y (mouse-absolute-pixel-position))
-         (last-x (car last-x-y))
-         (last-y (cdr last-x-y))
-         ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
+	 ;; Initial "first" mouse position.  While dragging we base all
+	 ;; calculations against that position.
+	 (first-x-y (mouse-absolute-pixel-position))
+         (first-x (car first-x-y))
+         (first-y (cdr first-x-y))
+         ;; `snap-width' (maybe also a yet to be provided `snap-height')
+         ;; could become floats to handle proportionality wrt PARENT.
+         ;; We don't do any checks on this parameter so far.
+         (snap-width (frame-parameter frame 'snap-width))
+	 ;; `snap-x' and `snap-y' record the x- and y-coordinates of the
          ;; mouse position when FRAME snapped.  As soon as the
          ;; difference between `pos-x' and `snap-x' (or `pos-y' and
          ;; `snap-y') exceeds the value of FRAME's `snap-width'
@@ -678,176 +771,141 @@ mouse-drag-frame
           (lambda (event)
             (interactive "e")
             (when (consp event)
-              (setq pos-x-y (mouse-absolute-pixel-position))
-              (setq pos-x (car pos-x-y))
-              (setq pos-y (cdr pos-x-y))
-              (cond
-               ((eq part 'left)
-                (mouse-resize-frame frame (- last-x pos-x) 0 t))
-               ((eq part 'top)
-                (mouse-resize-frame frame 0 (- last-y pos-y) nil t))
-               ((eq part 'right)
-                (mouse-resize-frame frame (- pos-x last-x) 0))
-               ((eq part 'bottom)
-                (mouse-resize-frame frame 0 (- pos-y last-y)))
-               ((eq part 'top-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- last-y pos-y) t t))
-               ((eq part 'top-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- last-y pos-y) nil t))
-               ((eq part 'bottom-left)
-                (mouse-resize-frame
-                 frame (- last-x pos-x) (- pos-y last-y) t))
-               ((eq part 'bottom-right)
-                (mouse-resize-frame
-                 frame (- pos-x last-x) (- pos-y last-y)))
-               ((eq part 'move)
-                (let* ((old-position (frame-position frame))
-                       (old-left (car old-position))
-                       (old-top (cdr old-position))
-                       (left (+ old-left (- pos-x last-x)))
-                       (top (+ old-top (- pos-y last-y)))
-                       right bottom
-                       ;; `snap-width' (maybe also a yet to be provided
-                       ;; `snap-height') could become floats to handle
-                       ;; proportionality wrt PARENT.  We don't do any
-                       ;; checks on this parameter so far.
-                       (snap-width (frame-parameter frame 'snap-width)))
-                  ;; Docking and constraining.
-                  (when (and (numberp snap-width) parent-edges)
+              (let* ((last-x-y (mouse-absolute-pixel-position))
+		     (last-x (car last-x-y))
+		     (last-y (cdr last-x-y))
+		     (left (- last-x first-x))
+		     (top (- last-y first-y))
+                     right bottom)
+		(setq left (+ first-left left))
+		(setq top (+ first-top top))
+                ;; Docking and constraining.
+                (when (and (numberp snap-width) parent-edges)
+                  (cond
+                   ;; Docking at the left parent edge.
+                   ((< last-x first-x)
                     (cond
-                     ;; Docking at the left parent edge.
-                     ((< pos-x last-x)
-                      (cond
-                       ((and (> left parent-left)
-                             (<= (- left parent-left) snap-width))
-                        ;; Snap when the mouse moved leftward and
-                        ;; FRAME's left edge would end up within
-                        ;; `snap-width' pixels from PARENT's left edge.
-                        (setq snap-x pos-x)
-                        (setq left parent-left))
-                       ((and (<= left parent-left)
-                             (<= (- parent-left left) snap-width)
-                             snap-x (<= (- snap-x pos-x) snap-width))
-                        ;; Stay snapped when the mouse moved leftward
-                        ;; but not more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq left parent-left))
-                       (t
-                        ;; Unsnap when the mouse moved more than
-                        ;; `snap-width' pixels leftward from the time
-                        ;; FRAME snapped.
-                        (setq snap-x nil))))
-                     ((> pos-x last-x)
-                      (setq right (+ left width))
-                      (cond
-                       ((and (< right parent-right)
-                             (<= (- parent-right right) snap-width))
-                        ;; Snap when the mouse moved rightward and
-                        ;; FRAME's right edge would end up within
-                        ;; `snap-width' pixels from PARENT's right edge.
-                        (setq snap-x pos-x)
-                        (setq left (- parent-right width)))
-                       ((and (>= right parent-right)
-                             (<= (- right parent-right) snap-width)
-                             snap-x (<= (- pos-x snap-x) snap-width))
-                        ;; Stay snapped when the mouse moved rightward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq left (- parent-right width)))
-                       (t
-                        ;; Unsnap when the mouse moved rightward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-x nil)))))
-
+                     ((and (> left parent-left)
+                           (<= (- left parent-left) snap-width))
+                      ;; Snap when the mouse moved leftward and FRAME's
+                      ;; left edge would end up within `snap-width'
+                      ;; pixels from PARENT's left edge.
+                      (setq snap-x last-x)
+                      (setq left parent-left))
+                     ((and (<= left parent-left)
+                           (<= (- parent-left left) snap-width)
+                           snap-x (<= (- snap-x last-x) snap-width))
+                      ;; Stay snapped when the mouse moved leftward but
+                      ;; not more than `snap-width' pixels from the time
+                      ;; FRAME snapped.
+                      (setq left parent-left))
+                     (t
+                      ;; Unsnap when the mouse moved more than
+                      ;; `snap-width' pixels leftward from the time
+                      ;; FRAME snapped.
+                      (setq snap-x nil))))
+                   ((> last-x first-x)
+                    (setq right (+ left native-width))
                     (cond
-                     ((< pos-y last-y)
-                      (cond
-                       ((and (> top parent-top)
-                             (<= (- top parent-top) snap-width))
-                        ;; Snap when the mouse moved upward and FRAME's
-                        ;; top edge would end up within `snap-width'
-                        ;; pixels from PARENT's top edge.
-                        (setq snap-y pos-y)
-                        (setq top parent-top))
-                       ((and (<= top parent-top)
-                             (<= (- parent-top top) snap-width)
-                             snap-y (<= (- snap-y pos-y) snap-width))
-                        ;; Stay snapped when the mouse moved upward but
-                        ;; not more more than `snap-width' pixels from
-                        ;; the time FRAME snapped.
-                        (setq top parent-top))
-                       (t
-                        ;; Unsnap when the mouse moved upward more than
-                        ;; `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))
-                     ((> pos-y last-y)
-                      (setq bottom (+ top height))
-                      (cond
-                       ((and (< bottom parent-bottom)
-                             (<= (- parent-bottom bottom) snap-width))
-                        ;; Snap when the mouse moved downward and
-                        ;; FRAME's bottom edge would end up within
-                        ;; `snap-width' pixels from PARENT's bottom
-                        ;; edge.
-                        (setq snap-y pos-y)
-                        (setq top (- parent-bottom height)))
-                       ((and (>= bottom parent-bottom)
-                             (<= (- bottom parent-bottom) snap-width)
-                             snap-y (<= (- pos-y snap-y) snap-width))
-                        ;; Stay snapped when the mouse moved downward
-                        ;; but not more more than `snap-width' pixels
-                        ;; from the time FRAME snapped.
-                        (setq top (- parent-bottom height)))
-                       (t
-                        ;; Unsnap when the mouse moved downward more
-                        ;; than `snap-width' pixels from the time FRAME
-                        ;; snapped.
-                        (setq snap-y nil))))))
-
-                  ;; If requested, constrain FRAME's draggable areas to
-                  ;; PARENT's edges.  The `top-visible' parameter should
-                  ;; be set when FRAME has a draggable header-line.  If
-                  ;; set to a number, it ascertains that the top of
-                  ;; FRAME is always constrained to the top of PARENT
-                  ;; and that at least as many pixels of FRAME as
-                  ;; specified by that number are visible on each of the
-                  ;; three remaining sides of PARENT.
-                  ;;
-                  ;; The `bottom-visible' parameter should be set when
-                  ;; FRAME has a draggable mode-line.  If set to a
-                  ;; number, it ascertains that the bottom of FRAME is
-                  ;; always constrained to the bottom of PARENT and that
-                  ;; at least as many pixels of FRAME as specified by
-                  ;; that number are visible on each of the three
-                  ;; remaining sides of PARENT.
-                  (let ((par (frame-parameter frame 'top-visible))
-                        bottom-visible)
-                    (unless par
-                      (setq par (frame-parameter frame 'bottom-visible))
-                      (setq bottom-visible t))
-                    (when (and (numberp par) parent-edges)
-                      (setq left
-                            (max (min (- parent-right par) left)
-                                 (+ (- parent-left width) par)))
-                      (setq top
-                            (if bottom-visible
-                                (min (max top (- parent-top (- height par)))
-                                     (- parent-bottom height))
-                              (min (max top parent-top)
-                                   (- parent-bottom par))))))
-
-                  ;; Use `modify-frame-parameters' since `left' and
-                  ;; `top' may want to move FRAME out of its PARENT.
-                  (modify-frame-parameters
-                   frame
-                   `((left . (+ ,left)) (top . (+ ,top)))))))
-              (setq last-x pos-x)
-              (setq last-y pos-y))))
-         (old-track-mouse track-mouse))
+                     ((and (< right parent-right)
+                           (<= (- parent-right right) snap-width))
+                      ;; Snap when the mouse moved rightward and FRAME's
+                      ;; right edge would end up within `snap-width'
+                      ;; pixels from PARENT's right edge.
+                      (setq snap-x last-x)
+                      (setq left (- parent-right native-width)))
+                     ((and (>= right parent-right)
+                           (<= (- right parent-right) snap-width)
+                           snap-x (<= (- last-x snap-x) snap-width))
+                      ;; Stay snapped when the mouse moved rightward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq left (- parent-right native-width)))
+                     (t
+                      ;; Unsnap when the mouse moved rightward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-x nil)))))
+                  (cond
+                   ((< last-y first-y)
+                    (cond
+                     ((and (> top parent-top)
+                           (<= (- top parent-top) snap-width))
+                      ;; Snap when the mouse moved upward and FRAME's
+                      ;; top edge would end up within `snap-width'
+                      ;; pixels from PARENT's top edge.
+                      (setq snap-y last-y)
+                      (setq top parent-top))
+                     ((and (<= top parent-top)
+                           (<= (- parent-top top) snap-width)
+                           snap-y (<= (- snap-y last-y) snap-width))
+                      ;; Stay snapped when the mouse moved upward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top parent-top))
+                     (t
+                      ;; Unsnap when the mouse moved upward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))
+                   ((> last-y first-y)
+                    (setq bottom (+ top native-height))
+                    (cond
+                     ((and (< bottom parent-bottom)
+                           (<= (- parent-bottom bottom) snap-width))
+                      ;; Snap when the mouse moved downward and FRAME's
+                      ;; bottom edge would end up within `snap-width'
+                      ;; pixels from PARENT's bottom edge.
+                      (setq snap-y last-y)
+                      (setq top (- parent-bottom native-height)))
+                     ((and (>= bottom parent-bottom)
+                           (<= (- bottom parent-bottom) snap-width)
+                           snap-y (<= (- last-y snap-y) snap-width))
+                      ;; Stay snapped when the mouse moved downward but
+                      ;; not more more than `snap-width' pixels from the
+                      ;; time FRAME snapped.
+                      (setq top (- parent-bottom native-height)))
+                     (t
+                      ;; Unsnap when the mouse moved downward more than
+                      ;; `snap-width' pixels from the time FRAME
+                      ;; snapped.
+                      (setq snap-y nil))))))
+
+                ;; If requested, constrain FRAME's draggable areas to
+                ;; PARENT's edges.  The `top-visible' parameter should
+                ;; be set when FRAME has a draggable header-line.  If
+                ;; set to a number, it ascertains that the top of FRAME
+                ;; is always constrained to the top of PARENT and that
+                ;; at least as many pixels of FRAME as specified by that
+                ;; number are visible on each of the three remaining
+                ;; sides of PARENT.
+                ;;
+                ;; The `bottom-visible' parameter should be set when
+                ;; FRAME has a draggable mode-line.  If set to a number,
+                ;; it ascertains that the bottom of FRAME is always
+                ;; constrained to the bottom of PARENT and that at least
+                ;; as many pixels of FRAME as specified by that number
+                ;; are visible on each of the three remaining sides of
+                ;; PARENT.
+                (let ((par (frame-parameter frame 'top-visible))
+                      bottom-visible)
+                  (unless par
+                    (setq par (frame-parameter frame 'bottom-visible))
+                    (setq bottom-visible t))
+                  (when (and (numberp par) parent-edges)
+                    (setq left
+                          (max (min (- parent-right par) left)
+                               (+ (- parent-left native-width) par)))
+                    (setq top
+                          (if bottom-visible
+                              (min (max top (- parent-top (- native-height par)))
+                                   (- parent-bottom native-height))
+                            (min (max top parent-top)
+                                 (- parent-bottom par))))))
+                ;; Use `modify-frame-parameters' since `left' and `top'
+                ;; may want to move FRAME out of its PARENT.
+                (modify-frame-parameters frame `((left . (+ ,left)) (top . (+ ,top))))))))
+	 (old-track-mouse track-mouse))
     ;; Start tracking.  The special value 'dragging' signals the
     ;; display engine to freeze the mouse pointer shape for as long
     ;; as we drag.
@@ -879,49 +937,49 @@ mouse-drag-left-edge
   "Drag left edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'left))
+  (mouse-drag-frame-resize start-event 'left))
 
 (defun mouse-drag-top-left-corner (start-event)
   "Drag top left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-left))
+  (mouse-drag-frame-resize start-event 'top-left))
 
 (defun mouse-drag-top-edge (start-event)
   "Drag top edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top))
+  (mouse-drag-frame-resize start-event 'top))
 
 (defun mouse-drag-top-right-corner (start-event)
   "Drag top right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'top-right))
+  (mouse-drag-frame-resize start-event 'top-right))
 
 (defun mouse-drag-right-edge (start-event)
   "Drag right edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'right))
+  (mouse-drag-frame-resize start-event 'right))
 
 (defun mouse-drag-bottom-right-corner (start-event)
   "Drag bottom right corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-right))
+  (mouse-drag-frame-resize start-event 'bottom-right))
 
 (defun mouse-drag-bottom-edge (start-event)
   "Drag bottom edge of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom))
+  (mouse-drag-frame-resize start-event 'bottom))
 
 (defun mouse-drag-bottom-left-corner (start-event)
   "Drag bottom left corner of a frame with the mouse.
 START-EVENT is the starting mouse event of the drag action."
   (interactive "e")
-  (mouse-drag-frame start-event 'bottom-left))
+  (mouse-drag-frame-resize start-event 'bottom-left))
 
 (defcustom mouse-select-region-move-to-beginning nil
   "Effect of selecting a region extending backward from double click.
diff --git a/src/frame.c b/src/frame.c
index 88d6f22fc0..9ec5c24b22 100644
--- a/src/frame.c
+++ b/src/frame.c
@@ -5941,6 +5941,7 @@ syms_of_frame (void)
   DEFSYM (Qxg_frame_set_char_size_1, "xg-frame-set-char-size-1");
   DEFSYM (Qxg_frame_set_char_size_2, "xg-frame-set-char-size-2");
   DEFSYM (Qxg_frame_set_char_size_3, "xg-frame-set-char-size-3");
+  DEFSYM (Qxg_frame_set_char_size_4, "xg-frame-set-char-size-4");
   DEFSYM (Qx_set_window_size_1, "x-set-window-size-1");
   DEFSYM (Qx_set_window_size_2, "x-set-window-size-2");
   DEFSYM (Qx_set_window_size_3, "x-set-window-size-3");
diff --git a/src/gtkutil.c b/src/gtkutil.c
index 6308c38f16..4cab8a5706 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -940,9 +940,8 @@ xg_frame_resized (struct frame *f, int pixelwidth, int pixelheight)
     }
 }
 
-/* Resize the outer window of frame F after changing the height.
-   COLUMNS/ROWS is the size the edit area shall have after the resize.  */
-
+/** Resize the outer window of frame F.  WIDTH and HEIGHT are the new
+    pixel sizes of F's text area.  */
 void
 xg_frame_set_char_size (struct frame *f, int width, int height)
 {
@@ -953,6 +952,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
   int totalheight
     = pixelheight + FRAME_TOOLBAR_HEIGHT (f) + FRAME_MENUBAR_HEIGHT (f);
   int totalwidth = pixelwidth + FRAME_TOOLBAR_WIDTH (f);
+  bool was_visible = false;
 
   if (FRAME_PIXEL_HEIGHT (f) == 0)
     return;
@@ -995,12 +995,35 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
       gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 			 totalwidth, gheight);
     }
+  else if (FRAME_PARENT_FRAME (f) && FRAME_VISIBLE_P (f)
+	   && EQ (x_gtk_resize_child_frames, Qhide))
+    {
+      was_visible = true;
+
+      if (totalwidth != gwidth || totalheight != gheight)
+	{
+	  frame_size_history_add
+	    (f, Qxg_frame_set_char_size_4, width, height,
+	     list2i (totalwidth, totalheight));
+	  block_input ();
+	  gtk_widget_hide (FRAME_GTK_OUTER_WIDGET (f));
+	  unblock_input ();
+
+	  gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
+			     totalwidth, totalheight);
+
+	  block_input ();
+	  gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
+	  unblock_input ();
+
+	  fullscreen = Qnil;
+	}
+    }
   else
     {
       frame_size_history_add
 	(f, Qxg_frame_set_char_size_3, width, height,
 	 list2i (totalwidth, totalheight));
-
       gtk_window_resize (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
 			 totalwidth, totalheight);
       fullscreen = Qnil;
@@ -1016,7 +1039,7 @@ xg_frame_set_char_size (struct frame *f, int width, int height)
      size as fast as possible.
      For unmapped windows, we can set rows/cols.  When
      the frame is mapped again we will (hopefully) get the correct size.  */
-  if (FRAME_VISIBLE_P (f))
+  if (FRAME_VISIBLE_P (f) && !was_visible)
     {
       /* Must call this to flush out events */
       (void)gtk_events_pending ();
diff --git a/src/xfns.c b/src/xfns.c
index 276ea1c393..f32056ff03 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -861,6 +861,12 @@ x_set_parent_frame (struct frame *f, Lisp_Object new_value, Lisp_Object old_valu
 	(FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 	 p ? FRAME_X_WINDOW (p) : DefaultRootWindow (FRAME_X_DISPLAY (f)),
 	 f->left_pos, f->top_pos);
+#ifdef USE_GTK
+      if (EQ (x_gtk_resize_child_frames, Qresize_mode))
+	gtk_container_set_resize_mode
+	  (GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)),
+	   p ? GTK_RESIZE_IMMEDIATE : GTK_RESIZE_QUEUE);
+#endif
       unblock_input ();
 
       fset_parent_frame (f, new_value);
@@ -4084,6 +4090,11 @@ DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
       block_input ();
       XReparentWindow (FRAME_X_DISPLAY (f), FRAME_OUTER_WINDOW (f),
 		       FRAME_X_WINDOW (p), f->left_pos, f->top_pos);
+#ifdef USE_GTK
+      if (EQ (x_gtk_resize_child_frames, Qresize_mode))
+	gtk_container_set_resize_mode
+	  (GTK_CONTAINER (FRAME_GTK_OUTER_WIDGET (f)), GTK_RESIZE_IMMEDIATE);
+#endif
       unblock_input ();
     }
 
@@ -7742,6 +7753,22 @@ frames (each of which corresponds to one page).  Each frame should be
 #endif	/* USE_GTK */
 #endif	/* USE_CAIRO */
 
+#ifdef USE_GTK
+#ifdef HAVE_GTK3
+DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0,
+       doc: /* Toggle interactive GTK debugging.   */)
+  (Lisp_Object enable)
+{
+  gboolean enable_debug = !NILP (enable);
+
+  block_input ();
+  gtk_window_set_interactive_debugging (enable_debug);
+  unblock_input ();
+
+  return NILP (enable) ? Qnil : Qt;
+}
+#endif /* HAVE_GTK3 */
+#endif	/* USE_GTK */
 \f
 /***********************************************************************
 			    Initialization
@@ -7810,6 +7837,8 @@ syms_of_xfns (void)
   DEFSYM (Qfont_parameter, "font-parameter");
   DEFSYM (Qmono, "mono");
   DEFSYM (Qassq_delete_all, "assq-delete-all");
+  DEFSYM (Qhide, "hide");
+  DEFSYM (Qresize_mode, "resize-mode");
 
 #ifdef USE_CAIRO
   DEFSYM (Qpdf, "pdf");
@@ -7986,6 +8015,28 @@ syms_of_xfns (void)
 When using Gtk+ tooltips, the tooltip face is not used.  */);
   x_gtk_use_system_tooltips = true;
 
+  DEFVAR_LISP ("x-gtk-resize-child-frames", x_gtk_resize_child_frames,
+    doc: /* If non-nil, resize child frames specially with GTK builds.
+If this is nil, resize child frames like any other frames.  This is the
+default and usually works with most desktops.  Some desktop environments
+(GNOME shell in particular when using the mutter window manager),
+however, may refuse to resize a child frame when Emacs is built with
+GTK3.  For those environments, the two settings below are provided.
+
+If this equals the symbol 'hide', Emacs temporarily hides the child
+frame during resizing.  This approach seems to work reliably, may
+however induce some flicker when the frame is made visible again.
+
+If this equals the symbol 'resize-mode', Emacs uses GTK's resize mode to
+always trigger an immediate resize of the child frame.  This method is
+deprecated by GTK and may not work in future versions of that toolkit.
+It also may freeze Emacs when used with other desktop environments.  It
+avoids, however, the unpleasent flicker induced by the hiding approach.
+
+This variable is considered a temporary workaround and will be hopefully
+eliminated in future versions of Emacs.  */);
+  x_gtk_resize_child_frames = Qnil;
+
   /* Tell Emacs about this window system.  */
   Fprovide (Qx, Qnil);
 
@@ -8101,4 +8152,9 @@ syms_of_xfns (void)
   defsubr (&Sx_print_frames_dialog);
 #endif
 #endif
+#ifdef USE_GTK
+#ifdef HAVE_GTK3
+  defsubr (&Sx_gtk_debug);
+#endif
+#endif
 }
diff --git a/src/xterm.c b/src/xterm.c
index 21d99f0c7b..971f374764 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10612,26 +10612,29 @@ x_set_offset (struct frame *f, register int xoff, register int yoff, int change_
 	       modified_left, modified_top);
 #endif
 
-  x_sync_with_move (f, f->left_pos, f->top_pos,
-                    FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
-
-  /* change_gravity is non-zero when this function is called from Lisp to
-     programmatically move a frame.  In that case, we call
-     x_check_expected_move to discover if we have a "Type A" or "Type B"
-     window manager, and, for a "Type A" window manager, adjust the position
-     of the frame.
-
-     We call x_check_expected_move if a programmatic move occurred, and
-     either the window manager type (A/B) is unknown or it is Type A but we
-     need to compute the top/left offset adjustment for this frame.  */
-
-  if (change_gravity != 0
-      && !FRAME_PARENT_FRAME (f)
-      && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
-	  || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
-	      && (FRAME_X_OUTPUT (f)->move_offset_left == 0
-		  && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
-    x_check_expected_move (f, modified_left, modified_top);
+  /* 'x_sync_with_move' is too costly for dragging child frames.  */
+  if (!FRAME_PARENT_FRAME (f))
+    {
+      x_sync_with_move (f, f->left_pos, f->top_pos,
+			FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN);
+
+      /* change_gravity is non-zero when this function is called from Lisp to
+	 programmatically move a frame.  In that case, we call
+	 x_check_expected_move to discover if we have a "Type A" or "Type B"
+	 window manager, and, for a "Type A" window manager, adjust the position
+	 of the frame.
+
+	 We call x_check_expected_move if a programmatic move occurred, and
+	 either the window manager type (A/B) is unknown or it is Type A but we
+	 need to compute the top/left offset adjustment for this frame.  */
+
+      if (change_gravity != 0
+	  && (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_UNKNOWN
+	      || (FRAME_DISPLAY_INFO (f)->wm_type == X_WMTYPE_A
+		  && (FRAME_X_OUTPUT (f)->move_offset_left == 0
+		      && FRAME_X_OUTPUT (f)->move_offset_top == 0))))
+	x_check_expected_move (f, modified_left, modified_top);
+    }
 
   unblock_input ();
 }

^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-31 17:04                                                                                                                                                                         ` martin rudalics
@ 2020-04-03 11:09                                                                                                                                                                           ` Eli Zaretskii
  2020-04-03 15:08                                                                                                                                                                             ` martin rudalics
  2020-04-12  6:44                                                                                                                                                                           ` Andreas Schwab
  1 sibling, 1 reply; 196+ messages in thread
From: Eli Zaretskii @ 2020-04-03 11:09 UTC (permalink / raw)
  To: martin rudalics; +Cc: tumashu, emacs-devel, dgutov

> From: martin rudalics <rudalics@gmx.at>
> Date: Tue, 31 Mar 2020 19:04:11 +0200
> Cc: "emacs-devel@gnu.org" <emacs-devel@gnu.org>
> 
> OK.  Eli, I would like to install the attached patch for Emacs 27.

I'm sorry, I'm really at a loss regarding this jumbo changeset.  Why
exactly does it have to be in Emacs 27?  Child frames were introduced
in Emacs 26, not Emacs 27.

> All changes affect the resizing and moving of child frames only,
> normal frames are not affected.

You say that, and I believe you actually meant that, but the code
changes many functions that do affect normal frames, AFAICT.  I don't
see how can we be sure normal frames are not affected.  If you have a
way of showing that convincingly, I'm all ears.

Thanks.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-03 11:09                                                                                                                                                                           ` Eli Zaretskii
@ 2020-04-03 15:08                                                                                                                                                                             ` martin rudalics
  2020-04-03 16:08                                                                                                                                                                               ` martin rudalics
                                                                                                                                                                                                 ` (2 more replies)
  0 siblings, 3 replies; 196+ messages in thread
From: martin rudalics @ 2020-04-03 15:08 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tumashu, dgutov, emacs-devel

 >> OK.  Eli, I would like to install the attached patch for Emacs 27.
 >
 > I'm sorry, I'm really at a loss regarding this jumbo changeset.  Why
 > exactly does it have to be in Emacs 27?  Child frames were introduced
 > in Emacs 26, not Emacs 27.

Apparently, child frames are in wider use only since last year.

 >> All changes affect the resizing and moving of child frames only,
 >> normal frames are not affected.
 >
 > You say that, and I believe you actually meant that, but the code
 > changes many functions that do affect normal frames, AFAICT.  I don't
 > see how can we be sure normal frames are not affected.  If you have a
 > way of showing that convincingly, I'm all ears.

First of all let me note that none of the problems this patch tries to
solve cannot be observed on Windows.  The Windows API wrt child windows
is to my knowledge correctly implemented by the underlying routines.  As
a matter of fact, most problems my patch tries to fix have been observed
with GTK3 builds of Emacs running on the GNOME shell desktop under the
mutter window manager only.

Now about the individual parts of the patch:

(1) The behavior I try to fix in mouse.el has AFAICT been observed by me
only.  While the patch is not restricted to child frames the
functionality it fixes is not useful for non-child frames: All window
mangers I am aware of allow to move a non-child frame by dragging its
title area with the mouse and allow to resize a non-child frame by
dragging its external borders.  Windows provides the same functionality
for child frames.

However, practically all X windows managers I'm aware of neither allow
to put a title bar on a child frame nor do they draw a border on them.
Hence, in order to provide the same functionality for child frames they
are automatically given by Windows, I had to implement that
functionality on GNU/Linux manually.  And while I did that, I made the
incorrect assumption that move and resize events would be reported in
the order they were issued.  That assumption was unfortunately wrong
and caused, for example, a child frame's right edge to move too when
dragging its left edge in order to shrink or enlarge that frame
horizontally.  All changes in mouse.el are there to fix that behavior.

(2) The change in gtkutil.c's xg_frame_set_char_size is clearly for
child frames only due to the guard

   else if (FRAME_PARENT_FRAME (f) && FRAME_VISIBLE_P (f)
	   && EQ (x_gtk_resize_child_frames, Qhide))

and the fact that was_visible can be set only within the ensuing clause.

(3) The change in xfns.c's x_set_parent_frame is clearly for child
frames only.  The change in Fx_create_frame is separately guarded by a
(!NILP (parent_frame)).

(4) Adding x_gtk_resize_child_frames to xterm.c cannot affect
non-child-frames.  Its use is restricted to (2) and both instances of
(3).

(5) The change in x_set_offset of xterm.c does affect child frames only
in the sense that some part of x_set_offset is not run for child frames
via

   if (!FRAME_PARENT_FRAME (f))

The changes (2)-(4) are an attempt to fix the resizing of child frames
for GTK3 builds on mutter.  Users are supposed to put them into effect
there and only there by setting 'x-gtk-resize-child-frames' to non-nil.
Users of child frames on other systems should not notice them.

(5) affects all child frames under X and is needed in order to omit the
(IMHO useless) step that tries to reposition a frame when Emacs believes
that it detected that the frame was incorrectly positioned.  One reason
for this is that some newer window managers make the external border of
a frame invisible, position the visible part of the frame as Emacs
requested but report the new position of the frame as the one where the
invisible border starts.  For example, when the visible part of the
frame starts at (0, 0) the reported position has negative values
(Bug#38452).  IIRC Windows 10 does something similar.  Unfortunately, in
its X code, Emacs induces a 0.5 secs wait whenever it believes to have
detected such incorrect positioning which makes dragging a child frame
with the mouse unacceptably slow.

So the only thing that really affects non-child frames as well is the
earlier mentioned addition of 'x-gtk-debug'.  In fact, that addition
does not fix anything but might be useful when advising a user how to
debug a problem with GTK3.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-03 15:08                                                                                                                                                                             ` martin rudalics
@ 2020-04-03 16:08                                                                                                                                                                               ` martin rudalics
  2020-04-03 19:07                                                                                                                                                                               ` Dmitry Gutov
  2020-04-04  8:51                                                                                                                                                                               ` Eli Zaretskii
  2 siblings, 0 replies; 196+ messages in thread
From: martin rudalics @ 2020-04-03 16:08 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tumashu, emacs-devel, dgutov

 > First of all let me note that none of the problems this patch tries to
 > solve cannot be observed on Windows.
         ^can^

Sorry, martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-03 15:08                                                                                                                                                                             ` martin rudalics
  2020-04-03 16:08                                                                                                                                                                               ` martin rudalics
@ 2020-04-03 19:07                                                                                                                                                                               ` Dmitry Gutov
  2020-04-04  8:51                                                                                                                                                                               ` Eli Zaretskii
  2 siblings, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-04-03 19:07 UTC (permalink / raw)
  To: martin rudalics, Eli Zaretskii; +Cc: tumashu, emacs-devel

On 03.04.2020 18:08, martin rudalics wrote:
>  >> OK.  Eli, I would like to install the attached patch for Emacs 27.
>  >
>  > I'm sorry, I'm really at a loss regarding this jumbo changeset.  Why
>  > exactly does it have to be in Emacs 27?  Child frames were introduced
>  > in Emacs 26, not Emacs 27.
> 
> Apparently, child frames are in wider use only since last year.

Two years ago, to be more accurate.

Here's a bug report that's almost as old: 
https://github.com/tumashu/company-posframe/issues/2

In any case, they've really started to be used/tested/etc after Emacs 26 
was released.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-03 15:08                                                                                                                                                                             ` martin rudalics
  2020-04-03 16:08                                                                                                                                                                               ` martin rudalics
  2020-04-03 19:07                                                                                                                                                                               ` Dmitry Gutov
@ 2020-04-04  8:51                                                                                                                                                                               ` Eli Zaretskii
  2020-04-04  9:02                                                                                                                                                                                 ` martin rudalics
  2 siblings, 1 reply; 196+ messages in thread
From: Eli Zaretskii @ 2020-04-04  8:51 UTC (permalink / raw)
  To: martin rudalics; +Cc: tumashu, dgutov, emacs-devel

> Cc: tumashu@163.com, emacs-devel@gnu.org, dgutov@yandex.ru
> From: martin rudalics <rudalics@gmx.at>
> Date: Fri, 3 Apr 2020 17:08:31 +0200
> 
>  >> OK.  Eli, I would like to install the attached patch for Emacs 27.
>  >
>  > I'm sorry, I'm really at a loss regarding this jumbo changeset.  Why
>  > exactly does it have to be in Emacs 27?  Child frames were introduced
>  > in Emacs 26, not Emacs 27.
> 
> Apparently, child frames are in wider use only since last year.

OK, but that is only a convincing argument if the current emacs-27
behavior of child frames is horribly broken.  Is it? if so, can you
describe some examples of the breakage?

> Now about the individual parts of the patch:
> 
> (1) The behavior I try to fix in mouse.el has AFAICT been observed by me
> only.  While the patch is not restricted to child frames the
> functionality it fixes is not useful for non-child frames: All window
> mangers I am aware of allow to move a non-child frame by dragging its
> title area with the mouse and allow to resize a non-child frame by
> dragging its external borders.  Windows provides the same functionality
> for child frames.
> 
> However, practically all X windows managers I'm aware of neither allow
> to put a title bar on a child frame nor do they draw a border on them.
> Hence, in order to provide the same functionality for child frames they
> are automatically given by Windows, I had to implement that
> functionality on GNU/Linux manually.  And while I did that, I made the
> incorrect assumption that move and resize events would be reported in
> the order they were issued.  That assumption was unfortunately wrong
> and caused, for example, a child frame's right edge to move too when
> dragging its left edge in order to shrink or enlarge that frame
> horizontally.  All changes in mouse.el are there to fix that behavior.

The changes in mouse.el are the most troublesome from my POV, as long
as we are talking about the release branch.  They affect
mouse-resize-frame and mouse-drag-frame, two very important functions
used for all kinds of frames.  How can we be reasonably sure nothing
was broken in those two functions by these changes for frames that are
not child frames?  AFAICT, the above description doesn't attempt to
address this concern, which for me is the main one.  Can you help me
become less worried about that?

Thanks.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-04  8:51                                                                                                                                                                               ` Eli Zaretskii
@ 2020-04-04  9:02                                                                                                                                                                                 ` martin rudalics
  2020-04-04  9:30                                                                                                                                                                                   ` Eli Zaretskii
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-04-04  9:02 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tumashu, dgutov, emacs-devel

 >> Apparently, child frames are in wider use only since last year.
 >
 > OK, but that is only a convincing argument if the current emacs-27
 > behavior of child frames is horribly broken.  Is it? if so, can you
 > describe some examples of the breakage?

Resizing a child frame on mutter is impossible.  I think that's horrible
enough for the packages that want to do that.

 > The changes in mouse.el are the most troublesome from my POV, as long
 > as we are talking about the release branch.  They affect
 > mouse-resize-frame and mouse-drag-frame, two very important functions
 > used for all kinds of frames.  How can we be reasonably sure nothing
 > was broken in those two functions by these changes for frames that are
 > not child frames?  AFAICT, the above description doesn't attempt to
 > address this concern, which for me is the main one.  Can you help me
 > become less worried about that?

Yes.  I can apply these changes to master only because the only person
who ever noticed that something is wrong there was me.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-04  9:02                                                                                                                                                                                 ` martin rudalics
@ 2020-04-04  9:30                                                                                                                                                                                   ` Eli Zaretskii
  2020-04-06  9:03                                                                                                                                                                                     ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Eli Zaretskii @ 2020-04-04  9:30 UTC (permalink / raw)
  To: martin rudalics; +Cc: tumashu, dgutov, emacs-devel

> Cc: tumashu@163.com, emacs-devel@gnu.org, dgutov@yandex.ru
> From: martin rudalics <rudalics@gmx.at>
> Date: Sat, 4 Apr 2020 11:02:25 +0200
> 
>  >> Apparently, child frames are in wider use only since last year.
>  >
>  > OK, but that is only a convincing argument if the current emacs-27
>  > behavior of child frames is horribly broken.  Is it? if so, can you
>  > describe some examples of the breakage?
> 
> Resizing a child frame on mutter is impossible.  I think that's horrible
> enough for the packages that want to do that.

What is "mutter"?

>  > The changes in mouse.el are the most troublesome from my POV, as long
>  > as we are talking about the release branch.  They affect
>  > mouse-resize-frame and mouse-drag-frame, two very important functions
>  > used for all kinds of frames.  How can we be reasonably sure nothing
>  > was broken in those two functions by these changes for frames that are
>  > not child frames?  AFAICT, the above description doesn't attempt to
>  > address this concern, which for me is the main one.  Can you help me
>  > become less worried about that?
> 
> Yes.  I can apply these changes to master only because the only person
> who ever noticed that something is wrong there was me.

Pushing only the non-Lisp changes to the release branch is fine by me,
thanks.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-04  9:30                                                                                                                                                                                   ` Eli Zaretskii
@ 2020-04-06  9:03                                                                                                                                                                                     ` martin rudalics
  2020-04-06 13:26                                                                                                                                                                                       ` Eli Zaretskii
  2020-04-06 18:36                                                                                                                                                                                       ` Dmitry Gutov
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-04-06  9:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tumashu, emacs-devel, dgutov

 >> Resizing a child frame on mutter is impossible.  I think that's horrible
 >> enough for the packages that want to do that.
 >
 > What is "mutter"?

The standard window manager for GNOME shell.

 > Pushing only the non-Lisp changes to the release branch is fine by me,
 > thanks.

I pushed the non-Lisp changes to the release branch and the mouse.el
changes to master.

I think we should "advertise" the GTK related changes in PROBLEMS.
Sooner or later the GTK child frame resizing problem has to be fixed
outside Emacs although I currently see no chance that we can convince
people to look into it.  Like

*** Emacs run under the mutter WM cannot resize child frames

When running Emacs on GNOME shell under the mutter window manager, it
cannot resize child frames.  Emacs provides a workaround by setting the
option 'x-gtk-resize-child-frames' to either 'hide' or 'resize-mode'.
This option is considered a temporary workaround with restricted
functionality (child frames still cannot display scroll bars in that
environment) and will be hopefully removed as soon as a stable solution
to the problem has been found.

WDYT?

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-06  9:03                                                                                                                                                                                     ` martin rudalics
@ 2020-04-06 13:26                                                                                                                                                                                       ` Eli Zaretskii
  2020-04-07  8:32                                                                                                                                                                                         ` martin rudalics
  2020-04-06 18:36                                                                                                                                                                                       ` Dmitry Gutov
  1 sibling, 1 reply; 196+ messages in thread
From: Eli Zaretskii @ 2020-04-06 13:26 UTC (permalink / raw)
  To: martin rudalics; +Cc: tumashu, emacs-devel, dgutov

> Cc: tumashu@163.com, dgutov@yandex.ru, emacs-devel@gnu.org
> From: martin rudalics <rudalics@gmx.at>
> Date: Mon, 6 Apr 2020 11:03:33 +0200
> 
> I pushed the non-Lisp changes to the release branch and the mouse.el
> changes to master.

Thanks.

> *** Emacs run under the mutter WM cannot resize child frames
> 
> When running Emacs on GNOME shell under the mutter window manager, it
> cannot resize child frames.  Emacs provides a workaround by setting the
> option 'x-gtk-resize-child-frames' to either 'hide' or 'resize-mode'.
> This option is considered a temporary workaround with restricted
> functionality (child frames still cannot display scroll bars in that
> environment) and will be hopefully removed as soon as a stable solution
> to the problem has been found.
> 
> WDYT?

SGTM, but please mention the Emacs version in the text, since this
problem will be gone in future releases.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-06  9:03                                                                                                                                                                                     ` martin rudalics
  2020-04-06 13:26                                                                                                                                                                                       ` Eli Zaretskii
@ 2020-04-06 18:36                                                                                                                                                                                       ` Dmitry Gutov
  2020-04-07  8:33                                                                                                                                                                                         ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-04-06 18:36 UTC (permalink / raw)
  To: martin rudalics, Eli Zaretskii; +Cc: tumashu, emacs-devel

On 06.04.2020 12:03, martin rudalics wrote:
> I pushed the non-Lisp changes to the release branch and the mouse.el
> changes to master.

Thanks, Martin! That should improve the experience of many users of 
childframe based popups.

Do you want to write a "here's what we ended up doing" comment for the 
GNOME bug tracker?

If the fact that we had to use a legacy function doesn't spur anybody to 
action, I don't know what could.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-12  8:23                                                                                                                                                             ` martin rudalics
  2020-03-13 16:57                                                                                                                                                               ` Dmitry Gutov
@ 2020-04-06 22:51                                                                                                                                                               ` Dmitry Gutov
  2020-04-07  8:33                                                                                                                                                                 ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-04-06 22:51 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

Hi Martin,

On 12.03.2020 10:23, martin rudalics wrote:
>  >> It also freezes Emacs on
>  >> desktops like kwin and xfwm and therefore must be made optional anyway.
>  >
>  > That's unfortunate. If there was a way to detect Mutter 
> programmatically, maybe we should use that. Even if just to set the 
> default value of the new variable you've described below.
> 
> I've been trying to do that but it's unreliable (BTW mutter here
> identifies itself as GNOME shell): We would have to test such an
> automatism on all possible desktops people use.  So better leave that to
> Emacs 28.

By the way, any chance we can have a variable or an accessor function 
that would return what the current WM identifies as?

Emacs might not want to alter its behavior based on that for now, but 
third-party packages (such as posframe) can experiment with that in the 
meantime.

And also, what's the best way to detect which toolkit was Emacs compiled 
with? Only look for 'gtk3' substring in system-configuration-options?



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-06 13:26                                                                                                                                                                                       ` Eli Zaretskii
@ 2020-04-07  8:32                                                                                                                                                                                         ` martin rudalics
  2020-04-07 14:04                                                                                                                                                                                           ` Eli Zaretskii
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-04-07  8:32 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: tumashu, dgutov, emacs-devel

 >> *** Emacs run under the mutter WM cannot resize child frames
 >>
 >> When running Emacs on GNOME shell under the mutter window manager, it
 >> cannot resize child frames.  Emacs provides a workaround by setting the
 >> option 'x-gtk-resize-child-frames' to either 'hide' or 'resize-mode'.
 >> This option is considered a temporary workaround with restricted
 >> functionality (child frames still cannot display scroll bars in that
 >> environment) and will be hopefully removed as soon as a stable solution
 >> to the problem has been found.
 >>
 >> WDYT?
 >
 > SGTM, but please mention the Emacs version in the text, since this
 > problem will be gone in future releases.

Sorry, I apparently was not able to make my point.  This problem is not
related to the mouse.el changes which I applied to master.  The problem
described here is more persistent and can be solved only when the mutter
people decide to fix it.  Till then, the workaround I applied to the
release branch can be used but is only imperfect in the way described by
the entry above.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-06 18:36                                                                                                                                                                                       ` Dmitry Gutov
@ 2020-04-07  8:33                                                                                                                                                                                         ` martin rudalics
  2020-04-07 13:19                                                                                                                                                                                           ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-04-07  8:33 UTC (permalink / raw)
  To: Dmitry Gutov, Eli Zaretskii; +Cc: tumashu, emacs-devel

 > Do you want to write a "here's what we ended up doing" comment for the GNOME bug tracker?

I can try to do that.  Here GNOME shell meanwhile has decided to ignore
all my earlier customizations and all it allows me to do is to start
applications via my keyboard shortcuts.  GNOME shell really doesn't like
me and I'm afraid that it will get even more insulted if I told its bug
tracker about what I did to its child frame handling.

 > If the fact that we had to use a legacy function doesn't spur anybody
 > to action, I don't know what could.

I strongly doubt that.  IIUC we do that all the time, at least with
GTK-3.  One day all this will break down on us.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-06 22:51                                                                                                                                                               ` Dmitry Gutov
@ 2020-04-07  8:33                                                                                                                                                                 ` martin rudalics
  2020-04-07 14:25                                                                                                                                                                   ` Dmitry Gutov
  2020-04-08  8:31                                                                                                                                                                   ` Support
  0 siblings, 2 replies; 196+ messages in thread
From: martin rudalics @ 2020-04-07  8:33 UTC (permalink / raw)
  To: Dmitry Gutov, tumashu; +Cc: emacs-devel@gnu.org

 > By the way, any chance we can have a variable or an accessor function
 > that would return what the current WM identifies as?

I started to look into this but with meager results so far.  From what I
read on the Web there's no standardized approach to find that out.

 > Emacs might not want to alter its behavior based on that for now, but
 > third-party packages (such as posframe) can experiment with that in
 > the meantime.

I'd urgently need it for Bug#38452.

 > And also, what's the best way to detect which toolkit was Emacs
 > compiled with? Only look for 'gtk3' substring in
 > system-configuration-options?

It might not be there when the default is used.  It's hidden somewhere
behind C-h C-a.

martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-07  8:33                                                                                                                                                                                         ` martin rudalics
@ 2020-04-07 13:19                                                                                                                                                                                           ` Dmitry Gutov
  0 siblings, 0 replies; 196+ messages in thread
From: Dmitry Gutov @ 2020-04-07 13:19 UTC (permalink / raw)
  To: martin rudalics, Eli Zaretskii; +Cc: tumashu, emacs-devel

On 07.04.2020 11:33, martin rudalics wrote:
>  > Do you want to write a "here's what we ended up doing" comment for 
> the GNOME bug tracker?
> 
> I can try to do that.  Here GNOME shell meanwhile has decided to ignore
> all my earlier customizations and all it allows me to do is to start
> applications via my keyboard shortcuts.

Not sure what to tell you. I've been a fairly satisfied GNOME user for 
the past year, and a user of Unity before that. The upcoming LTS release 
of Ubuntu (and GNOME release that comes with it) should be especially 
good/snappy/probably-even-stable.

But you likely have some particular requirements that I don't.

 > GNOME shell really doesn't like me and I'm afraid that it will
 > get even more insulted if I told its bug
 > tracker about what I did to its child frame handling.

Maybe that will earn its respect instead.

>  > If the fact that we had to use a legacy function doesn't spur anybody
>  > to action, I don't know what could.
> 
> I strongly doubt that.  IIUC we do that all the time, at least with
> GTK-3.  One day all this will break down on us.

But we're never too vocal about it. :-)



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-07  8:32                                                                                                                                                                                         ` martin rudalics
@ 2020-04-07 14:04                                                                                                                                                                                           ` Eli Zaretskii
  0 siblings, 0 replies; 196+ messages in thread
From: Eli Zaretskii @ 2020-04-07 14:04 UTC (permalink / raw)
  To: martin rudalics; +Cc: tumashu, dgutov, emacs-devel

> Cc: tumashu@163.com, emacs-devel@gnu.org, dgutov@yandex.ru
> From: martin rudalics <rudalics@gmx.at>
> Date: Tue, 7 Apr 2020 10:32:29 +0200
> 
>  > SGTM, but please mention the Emacs version in the text, since this
>  > problem will be gone in future releases.
> 
> Sorry, I apparently was not able to make my point.  This problem is not
> related to the mouse.el changes which I applied to master.  The problem
> described here is more persistent and can be solved only when the mutter
> people decide to fix it.

Ah, okay, then please disregard my comment.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-07  8:33                                                                                                                                                                 ` martin rudalics
@ 2020-04-07 14:25                                                                                                                                                                   ` Dmitry Gutov
  2020-04-07 14:39                                                                                                                                                                     ` Robert Pluim
  2020-04-08  8:31                                                                                                                                                                   ` Support
  1 sibling, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-04-07 14:25 UTC (permalink / raw)
  To: martin rudalics, tumashu; +Cc: emacs-devel@gnu.org

On 07.04.2020 11:33, martin rudalics wrote:
>  > By the way, any chance we can have a variable or an accessor function
>  > that would return what the current WM identifies as?
> 
> I started to look into this but with meager results so far.  From what I
> read on the Web there's no standardized approach to find that out.

So far the best option I've found is the XDG_CURRENT_DESKTOP env var. 
But indeed it only says "GNOME" (or "ubuntu:GNOME" on my machine), never 
mentioning Mutter.

But if Mate sets it to something different, at least, that could work 
well enough for the purposes of posframe.

The other, more nuanced option, is:

   grep -sl mutter /proc/*/maps

https://unix.stackexchange.com/a/512207/166215

>  > And also, what's the best way to detect which toolkit was Emacs
>  > compiled with? Only look for 'gtk3' substring in
>  > system-configuration-options?
> 
> It might not be there when the default is used.  It's hidden somewhere
> behind C-h C-a.

(string-match-p "GTK3" system-configuration-features) seems to do the trick.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-07 14:25                                                                                                                                                                   ` Dmitry Gutov
@ 2020-04-07 14:39                                                                                                                                                                     ` Robert Pluim
  2020-04-07 14:50                                                                                                                                                                       ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: Robert Pluim @ 2020-04-07 14:39 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: martin rudalics, emacs-devel@gnu.org, tumashu

>>>>> On Tue, 7 Apr 2020 17:25:16 +0300, Dmitry Gutov <dgutov@yandex.ru> said:

    Dmitry> (string-match-p "GTK3" system-configuration-features) seems to do the trick.

C-h v system-configuration-features says:
    This is mainly intended for diagnostic purposes in bug reports.
    Don't rely on it for testing whether a feature you want to use is available.

If this kind of stuff is really needed (and I hope it isnʼt) then we
should come up with a lisp variable with a guaranteed set of values
for toolkit type.

Robert



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-07 14:39                                                                                                                                                                     ` Robert Pluim
@ 2020-04-07 14:50                                                                                                                                                                       ` Dmitry Gutov
  2020-04-07 15:37                                                                                                                                                                         ` Robert Pluim
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-04-07 14:50 UTC (permalink / raw)
  To: Robert Pluim; +Cc: martin rudalics, emacs-devel@gnu.org, tumashu

On 07.04.2020 17:39, Robert Pluim wrote:
>      Dmitry> (string-match-p "GTK3" system-configuration-features) seems to do the trick.
> 
> C-h v system-configuration-features says:
>      This is mainly intended for diagnostic purposes in bug reports.
>      Don't rely on it for testing whether a feature you want to use is available.
> 
> If this kind of stuff is really needed (and I hope it isnʼt) then we
> should come up with a lisp variable with a guaranteed set of values
> for toolkit type.

Is it really unreliable or just subject to change?

Since we still hope that Emacs 28 won't need this particular check, and 
the variable has been present in all recent releases, maybe it's good 
enough.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-07 14:50                                                                                                                                                                       ` Dmitry Gutov
@ 2020-04-07 15:37                                                                                                                                                                         ` Robert Pluim
  2020-04-07 19:25                                                                                                                                                                           ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: Robert Pluim @ 2020-04-07 15:37 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: martin rudalics, emacs-devel@gnu.org, tumashu

>>>>> On Tue, 7 Apr 2020 17:50:57 +0300, Dmitry Gutov <dgutov@yandex.ru> said:

    Dmitry> On 07.04.2020 17:39, Robert Pluim wrote:
    Dmitry> (string-match-p "GTK3" system-configuration-features) seems to do the trick.
    >> C-h v system-configuration-features says:
    >> This is mainly intended for diagnostic purposes in bug reports.
    >> Don't rely on it for testing whether a feature you want to use is available.
    >> If this kind of stuff is really needed (and I hope it isnʼt) then we
    >> should come up with a lisp variable with a guaranteed set of values
    >> for toolkit type.

    Dmitry> Is it really unreliable or just subject to change?

Itʼs subject to change. Imagine the future, when we have GTK4, and
your string-match-p now fails.

    Dmitry> Since we still hope that Emacs 28 won't need this particular check,
    Dmitry> and the variable has been present in all recent releases, maybe it's
    Dmitry> good enough.

Iʼd like to think that the Gnome guys will jump on this and fix the
issue with mutter quickly, but then again, maybe they'll just say
"youʼre mixing X and GTK, stop doing that and we'll talk".

Robert



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-07 15:37                                                                                                                                                                         ` Robert Pluim
@ 2020-04-07 19:25                                                                                                                                                                           ` Dmitry Gutov
  2020-04-08  7:59                                                                                                                                                                             ` Robert Pluim
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-04-07 19:25 UTC (permalink / raw)
  To: Robert Pluim; +Cc: martin rudalics, emacs-devel@gnu.org, tumashu

On 07.04.2020 18:37, Robert Pluim wrote:
> Itʼs subject to change. Imagine the future, when we have GTK4, and
> your string-match-p now fails.

I don't know if GTK4 will need the same workaround. Maybe it won't or 
it'll need something different.

So in all likelihood the caller code would need to be updated. But 
that's not hard: we'll do that, release new version of posframe and call 
it a day.

That's the advantage of shipping features out-of-band with releases.

> Iʼd like to think that the Gnome guys will jump on this and fix the
> issue with mutter quickly, but then again, maybe they'll just say
> "youʼre mixing X and GTK, stop doing that and we'll talk".

Yes, well. So far we're still waiting for at least *some* response.



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-07 19:25                                                                                                                                                                           ` Dmitry Gutov
@ 2020-04-08  7:59                                                                                                                                                                             ` Robert Pluim
  2020-04-08 10:37                                                                                                                                                                               ` Dmitry Gutov
  0 siblings, 1 reply; 196+ messages in thread
From: Robert Pluim @ 2020-04-08  7:59 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: martin rudalics, tumashu, emacs-devel@gnu.org

>>>>> On Tue, 7 Apr 2020 22:25:17 +0300, Dmitry Gutov <dgutov@yandex.ru> said:

    >> Iʼd like to think that the Gnome guys will jump on this and fix the
    >> issue with mutter quickly, but then again, maybe they'll just say
    >> "youʼre mixing X and GTK, stop doing that and we'll talk".

    Dmitry> Yes, well. So far we're still waiting for at least *some* response.

Did someone open a bug on the Gnome tracker? I canʼt see anything
relevant in the 'mutter' issues list.

Robert



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-07  8:33                                                                                                                                                                 ` martin rudalics
  2020-04-07 14:25                                                                                                                                                                   ` Dmitry Gutov
@ 2020-04-08  8:31                                                                                                                                                                   ` Support
  2020-04-08  8:45                                                                                                                                                                     ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Support @ 2020-04-08  8:31 UTC (permalink / raw)
  To: martin rudalics; +Cc: Dmitry Gutov, tumashu, emacs-devel@gnu.org

On 7. Apr 2020, at 10:33, martin rudalics <rudalics@gmx.at> wrote:
> 
> > By the way, any chance we can have a variable or an accessor function
> > that would return what the current WM identifies as?
> 
> I started to look into this but with meager results so far.  From what I
> read on the Web there's no standardized approach to find that out.

Have you tried the _NET_SUPPORTING_WM_CHECK window’s _NET_WM_NAME?

https://specifications.freedesktop.org/wm-spec/1.5/ar01s03.html#idm46094431920896:

~~~
_NET_SUPPORTING_WM_CHECK

_NET_SUPPORTING_WM_CHECK, WINDOW/32

The Window Manager MUST set this property on the root window to be the ID of a child window created by himself, to indicate that a compliant window manager is active. The child window MUST also have the _NET_SUPPORTING_WM_CHECK property set to the ID of the child window. The child window MUST also have the _NET_WM_NAME property set to the name of the Window Manager.

[…]
~~~

Best regards,
Adrián.


^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-08  8:31                                                                                                                                                                   ` Support
@ 2020-04-08  8:45                                                                                                                                                                     ` martin rudalics
  2020-04-08  9:03                                                                                                                                                                       ` Adrián Medraño Calvo
  0 siblings, 1 reply; 196+ messages in thread
From: martin rudalics @ 2020-04-08  8:45 UTC (permalink / raw)
  To: Support; +Cc: tumashu, emacs-devel@gnu.org, Dmitry Gutov

 > Have you tried the _NET_SUPPORTING_WM_CHECK window’s _NET_WM_NAME?

I'm struggling with that for quite some time already.  wmctrl uses it
but I never got anything from a call like

   rc = XGetWindowProperty (dpy, dpyinfo->root_window,
			   XInternAtom (dpy, "_NET_WM_NAME", False),
                            0, max_len, False, XA_STRING,
/** 			   XInternAtom (dpy, "UTF8_STRING", False), **/
                            &actual_type, &actual_format, &actual_size,
                            &bytes_remaining, &name);

It reports success but name remains NULL.  If you have any clues about
what I'm doing wrong I'd be all ears.

martin




^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-08  8:45                                                                                                                                                                     ` martin rudalics
@ 2020-04-08  9:03                                                                                                                                                                       ` Adrián Medraño Calvo
  2020-04-08  9:25                                                                                                                                                                         ` martin rudalics
  0 siblings, 1 reply; 196+ messages in thread
From: Adrián Medraño Calvo @ 2020-04-08  9:03 UTC (permalink / raw)
  To: martin rudalics; +Cc: tumashu, emacs-devel@gnu.org, Dmitry Gutov

(Please correct mail address in CC to this one in further responses.)

> On 8. Apr 2020, at 10:45, martin rudalics <rudalics@gmx.at> wrote:
> 
> > Have you tried the _NET_SUPPORTING_WM_CHECK window’s _NET_WM_NAME?
> 
> I'm struggling with that for quite some time already.  wmctrl uses it
> but I never got anything from a call like
> 
>  rc = XGetWindowProperty (dpy, dpyinfo->root_window,
> 			   XInternAtom (dpy, "_NET_WM_NAME", False),
>                           0, max_len, False, XA_STRING,
> /** 			   XInternAtom (dpy, "UTF8_STRING", False), **/
>                           &actual_type, &actual_format, &actual_size,
>                           &bytes_remaining, &name);
> 
> It reports success but name remains NULL.  If you have any clues about
> what I'm doing wrong I'd be all ears.
> 
> martin
> 


This works for me:

~~~
(let ((id (x-window-property "_NET_SUPPORTING_WM_CHECK" nil "WINDOW" 0 nil t)))
  (x-window-property "_NET_WM_NAME" nil "UTF8_STRING" id nil))
~~~

I can’t help translating to Xlib API, but it’s there in Emacs C code.

You can also check with xwininfo and xprop:

~~~
$ xwininfo -root
xwininfo: Window id: 0x111 (the root window) (has no name)
[…]
$ xprop -id 0x111
[…]
_NET_SUPPORTING_WM_CHECK(WINDOW): window id # 0x600002
[…]
$ xprop -id 0x600002
_NET_WM_NAME(UTF8_STRING) = "whatever"
~~~

Hope it helps,
Adrián.


^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-08  9:03                                                                                                                                                                       ` Adrián Medraño Calvo
@ 2020-04-08  9:25                                                                                                                                                                         ` martin rudalics
  0 siblings, 0 replies; 196+ messages in thread
From: martin rudalics @ 2020-04-08  9:25 UTC (permalink / raw)
  To: Adrián Medraño Calvo; +Cc: tumashu, emacs-devel@gnu.org, Dmitry Gutov

 > This works for me:
 >
 > ~~~
 > (let ((id (x-window-property "_NET_SUPPORTING_WM_CHECK" nil "WINDOW" 0 nil t)))
 >    (x-window-property "_NET_WM_NAME" nil "UTF8_STRING" id nil))
 > ~~~

Works here as well, indeed.  Apparently one has to go through
that _NET_SUPPORTING_WM_CHECK before asking for _NET_WM_NAME.

 > Hope it helps,
 > Adrián.

Thanks, martin




^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-08  7:59                                                                                                                                                                             ` Robert Pluim
@ 2020-04-08 10:37                                                                                                                                                                               ` Dmitry Gutov
  2020-04-08 12:12                                                                                                                                                                                 ` Robert Pluim
  0 siblings, 1 reply; 196+ messages in thread
From: Dmitry Gutov @ 2020-04-08 10:37 UTC (permalink / raw)
  To: Robert Pluim; +Cc: martin rudalics, tumashu, emacs-devel@gnu.org

On 08.04.2020 10:59, Robert Pluim wrote:
>      >> Iʼd like to think that the Gnome guys will jump on this and fix the
>      >> issue with mutter quickly, but then again, maybe they'll just say
>      >> "youʼre mixing X and GTK, stop doing that and we'll talk".
> 
>      Dmitry> Yes, well. So far we're still waiting for at least*some*  response.
> 
> Did someone open a bug on the Gnome tracker? I canʼt see anything
> relevant in the 'mutter' issues list.

It's been mentioned here a few times: 
https://gitlab.gnome.org/GNOME/mutter/issues/840



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-08 10:37                                                                                                                                                                               ` Dmitry Gutov
@ 2020-04-08 12:12                                                                                                                                                                                 ` Robert Pluim
  0 siblings, 0 replies; 196+ messages in thread
From: Robert Pluim @ 2020-04-08 12:12 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: martin rudalics, emacs-devel@gnu.org, tumashu

>>>>> On Wed, 8 Apr 2020 13:37:45 +0300, Dmitry Gutov <dgutov@yandex.ru> said:

    Dmitry> On 08.04.2020 10:59, Robert Pluim wrote:
    >> >> Iʼd like to think that the Gnome guys will jump on this and fix the
    >> >> issue with mutter quickly, but then again, maybe they'll just say
    >> >> "youʼre mixing X and GTK, stop doing that and we'll talk".
    Dmitry> Yes, well. So far we're still waiting for at
    >> least*some*  response.
    >> Did someone open a bug on the Gnome tracker? I canʼt see anything
    >> relevant in the 'mutter' issues list.

    Dmitry> It's been mentioned here a few times:
    Dmitry> https://gitlab.gnome.org/GNOME/mutter/issues/840

Which has been sitting there for 6 months with no response. Oh well.

Robert



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-03-31 17:04                                                                                                                                                                         ` martin rudalics
  2020-04-03 11:09                                                                                                                                                                           ` Eli Zaretskii
@ 2020-04-12  6:44                                                                                                                                                                           ` Andreas Schwab
  2020-04-12  7:23                                                                                                                                                                             ` Eli Zaretskii
  2020-04-12  8:03                                                                                                                                                                             ` martin rudalics
  1 sibling, 2 replies; 196+ messages in thread
From: Andreas Schwab @ 2020-04-12  6:44 UTC (permalink / raw)
  To: martin rudalics; +Cc: tumashu, emacs-devel@gnu.org, Dmitry Gutov

On Mär 31 2020, martin rudalics wrote:

> @@ -7742,6 +7753,22 @@ frames (each of which corresponds to one page).  Each frame should be
>  #endif	/* USE_GTK */
>  #endif	/* USE_CAIRO */
>  
> +#ifdef USE_GTK
> +#ifdef HAVE_GTK3
> +DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0,
> +       doc: /* Toggle interactive GTK debugging.   */)
> +  (Lisp_Object enable)
> +{
> +  gboolean enable_debug = !NILP (enable);
> +
> +  block_input ();
> +  gtk_window_set_interactive_debugging (enable_debug);
> +  unblock_input ();
> +
> +  return NILP (enable) ? Qnil : Qt;
> +}
> +#endif /* HAVE_GTK3 */
> +#endif	/* USE_GTK */

https://build.opensuse.org/package/live_build_log/home:AndreasSchwab:emacs:master/emacs/13.1/ppc64

[ 1487s] /usr/lib64/gcc/powerpc64-suse-linux/4.8/../../../../powerpc64-suse-linux/bin/ld: xfns.o: in function `Fx_gtk_debug':
[ 1487s] /home/abuild/rpmbuild/BUILD/emacs-28.0.50/src/xfns.c:7757: undefined reference to `gtk_window_set_interactive_debugging'
[ 1487s] collect2: error: ld returned 1 exit status
[ 1487s] make[1]: *** [temacs] Error 1

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-12  6:44                                                                                                                                                                           ` Andreas Schwab
@ 2020-04-12  7:23                                                                                                                                                                             ` Eli Zaretskii
  2020-04-12  7:37                                                                                                                                                                               ` Andreas Schwab
  2020-04-12  8:03                                                                                                                                                                             ` martin rudalics
  1 sibling, 1 reply; 196+ messages in thread
From: Eli Zaretskii @ 2020-04-12  7:23 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: rudalics, emacs-devel, dgutov, tumashu

> From: Andreas Schwab <schwab@linux-m68k.org>
> Date: Sun, 12 Apr 2020 08:44:36 +0200
> Cc: tumashu <tumashu@163.com>, "emacs-devel@gnu.org" <emacs-devel@gnu.org>,
>  Dmitry Gutov <dgutov@yandex.ru>
> 
> [ 1487s] /usr/lib64/gcc/powerpc64-suse-linux/4.8/../../../../powerpc64-suse-linux/bin/ld: xfns.o: in function `Fx_gtk_debug':
> [ 1487s] /home/abuild/rpmbuild/BUILD/emacs-28.0.50/src/xfns.c:7757: undefined reference to `gtk_window_set_interactive_debugging'
> [ 1487s] collect2: error: ld returned 1 exit status
> [ 1487s] make[1]: *** [temacs] Error 1

Thanks.  Does the below fix this?  (I don't have access to a system
where the original problem happens.)

diff --git a/src/xfns.c b/src/xfns.c
index 0fc5530..c8a0af1 100644
--- a/src/xfns.c
+++ b/src/xfns.c
@@ -7754,7 +7754,7 @@ frames (each of which corresponds to one page).  Each frame should be
 #endif	/* USE_CAIRO */
 
 #ifdef USE_GTK
-#ifdef HAVE_GTK3
+#if GTK_CHECK_VERSION (3, 14, 0)
 DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0,
        doc: /* Toggle interactive GTK debugging.   */)
   (Lisp_Object enable)
@@ -7767,7 +7767,7 @@ DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0,
 
   return NILP (enable) ? Qnil : Qt;
 }
-#endif /* HAVE_GTK3 */
+#endif /* GTK >= 3.14.0 */
 #endif	/* USE_GTK */
 \f
 /***********************************************************************



^ permalink raw reply related	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-12  7:23                                                                                                                                                                             ` Eli Zaretskii
@ 2020-04-12  7:37                                                                                                                                                                               ` Andreas Schwab
  0 siblings, 0 replies; 196+ messages in thread
From: Andreas Schwab @ 2020-04-12  7:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: rudalics, emacs-devel, dgutov, tumashu

On Apr 12 2020, Eli Zaretskii wrote:

> diff --git a/src/xfns.c b/src/xfns.c
> index 0fc5530..c8a0af1 100644
> --- a/src/xfns.c
> +++ b/src/xfns.c
> @@ -7754,7 +7754,7 @@ frames (each of which corresponds to one page).  Each frame should be
>  #endif	/* USE_CAIRO */
>  
>  #ifdef USE_GTK
> -#ifdef HAVE_GTK3
> +#if GTK_CHECK_VERSION (3, 14, 0)
>  DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0,
>         doc: /* Toggle interactive GTK debugging.   */)
>    (Lisp_Object enable)
> @@ -7767,7 +7767,7 @@ DEFUN ("x-gtk-debug", Fx_gtk_debug, Sx_gtk_debug, 1, 1, 0,
>  
>    return NILP (enable) ? Qnil : Qt;
>  }
> -#endif /* HAVE_GTK3 */
> +#endif /* GTK >= 3.14.0 */
>  #endif	/* USE_GTK */
>  \f
>  /***********************************************************************

You also need to stub out the defsubr.

Andreas.

-- 
Andreas Schwab, schwab@linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."



^ permalink raw reply	[flat|nested] 196+ messages in thread

* Re: Emacs's set-frame-size can not work well with gnome-shell?
  2020-04-12  6:44                                                                                                                                                                           ` Andreas Schwab
  2020-04-12  7:23                                                                                                                                                                             ` Eli Zaretskii
@ 2020-04-12  8:03                                                                                                                                                                             ` martin rudalics
  1 sibling, 0 replies; 196+ messages in thread
From: martin rudalics @ 2020-04-12  8:03 UTC (permalink / raw)
  To: Andreas Schwab; +Cc: tumashu, Dmitry Gutov, emacs-devel@gnu.org

 > [ 1487s] /usr/lib64/gcc/powerpc64-suse-linux/4.8/../../../../powerpc64-suse-linux/bin/ld: xfns.o: in function `Fx_gtk_debug':
 > [ 1487s] /home/abuild/rpmbuild/BUILD/emacs-28.0.50/src/xfns.c:7757: undefined reference to `gtk_window_set_interactive_debugging'
 > [ 1487s] collect2: error: ld returned 1 exit status
 > [ 1487s] make[1]: *** [temacs] Error 1

Hopefully fixed now.  Please try again.

Thanks, martin



^ permalink raw reply	[flat|nested] 196+ messages in thread

end of thread, other threads:[~2020-04-12  8:03 UTC | newest]

Thread overview: 196+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-10  2:34 Emacs's set-frame-size can not work well with gnome-shell? tumashu
2020-01-10  9:56 ` martin rudalics
2020-01-11  1:29   ` tumashu
2020-01-11  7:50     ` martin rudalics
2020-01-11  9:56       ` Dmitry Gutov
2020-01-11 10:19         ` martin rudalics
2020-01-11 10:21           ` Dmitry Gutov
2020-01-11 10:35             ` martin rudalics
2020-01-11 11:21               ` Dmitry Gutov
2020-01-11 13:45                 ` martin rudalics
2020-01-14  2:09                   ` Dmitry Gutov
2020-01-14 15:50                     ` martin rudalics
2020-01-15  1:31                       ` Dmitry Gutov
2020-01-15  8:08                         ` martin rudalics
2020-01-15 23:53                           ` Dmitry Gutov
2020-01-16  8:03                             ` martin rudalics
2020-01-16  8:15                               ` Dmitry Gutov
2020-01-16  9:18                                 ` martin rudalics
2020-01-16  9:27                                   ` Dmitry Gutov
2020-01-16  9:44                                     ` martin rudalics
2020-01-16 10:12                                       ` Dmitry Gutov
2020-01-16 10:22                                         ` martin rudalics
2020-01-16 15:03                                           ` Dmitry Gutov
2020-01-16 18:33                                             ` martin rudalics
     [not found]                                               ` <15405719-d58d-44db-f1df-ad3bb272b2fc@yandex.ru>
     [not found]                                                 ` <aba0683f-466c-76cf-9024-e18bfc9fdc94@gmx.at>
2020-01-18  2:05                                                   ` Dmitry Gutov
2020-01-18  2:29                                                     ` Dmitry Gutov
2020-01-18  8:34                                                       ` martin rudalics
2020-01-18 12:27                                                         ` Dmitry Gutov
2020-01-18 13:48                                                           ` martin rudalics
2020-01-19  2:45                                                             ` Dmitry Gutov
2020-01-19  8:52                                                               ` martin rudalics
2020-01-20 14:14                                                                 ` Dmitry Gutov
2020-01-20 15:57                                                                   ` martin rudalics
2020-01-20 22:20                                                                     ` Dmitry Gutov
2020-01-21  8:29                                                                       ` martin rudalics
2020-01-21 11:36                                                                         ` Dmitry Gutov
2020-01-21 16:11                                                                           ` martin rudalics
2020-01-21 21:33                                                                             ` Dmitry Gutov
2020-01-22  9:07                                                                               ` martin rudalics
2020-01-22 10:57                                                                                 ` Dmitry Gutov
2020-01-18  8:32                                                     ` martin rudalics
2020-01-20 13:37                                                       ` Dmitry Gutov
2020-01-20 15:57                                                         ` martin rudalics
2020-01-20 23:02                                                           ` Dmitry Gutov
2020-01-21  8:29                                                             ` martin rudalics
2020-01-21 12:11                                                               ` Dmitry Gutov
2020-01-21 16:12                                                                 ` martin rudalics
2020-01-21 22:26                                                                   ` Dmitry Gutov
2020-01-22  9:08                                                                     ` martin rudalics
2020-01-22 11:35                                                                       ` Dmitry Gutov
2020-01-22 13:18                                                                         ` tumashu
2020-01-22 13:32                                                                           ` Dmitry Gutov
2020-01-22 16:19                                                                             ` Eli Zaretskii
2020-01-22 17:36                                                                             ` martin rudalics
2020-01-22 21:15                                                                               ` Dmitry Gutov
2020-01-25  8:41                                                                                 ` martin rudalics
2020-01-25 10:09                                                                                   ` Dmitry Gutov
2020-01-25 12:10                                                                                     ` martin rudalics
2020-01-26 11:59                                                                                       ` Dmitry Gutov
2020-01-26 17:38                                                                                         ` martin rudalics
2020-01-26 20:50                                                                                           ` Dmitry Gutov
2020-01-28  9:46                                                                                             ` martin rudalics
2020-01-28 15:19                                                                                               ` Dmitry Gutov
2020-01-28 16:20                                                                                                 ` martin rudalics
2020-01-30  2:14                                                                                                   ` Dmitry Gutov
2020-01-27 19:17                                                                                           ` martin rudalics
2020-01-27 21:15                                                                                             ` Dmitry Gutov
2020-01-28  9:47                                                                                               ` martin rudalics
2020-01-30  2:10                                                                                                 ` Dmitry Gutov
2020-01-30  9:38                                                                                                   ` martin rudalics
2020-01-30 17:21                                                                                                     ` martin rudalics
2020-01-30 18:15                                                                                                       ` Dmitry Gutov
2020-01-30 18:41                                                                                                         ` martin rudalics
2020-01-31  1:22                                                                                                           ` Dmitry Gutov
2020-01-31  9:29                                                                                                             ` martin rudalics
2020-01-31 11:52                                                                                                               ` Dmitry Gutov
2020-01-31 15:44                                                                                                                 ` martin rudalics
2020-01-31 22:22                                                                                                                   ` Dmitry Gutov
2020-02-01  9:35                                                                                                                     ` martin rudalics
2020-02-05  1:39                                                                                                                       ` Dmitry Gutov
2020-02-05  9:15                                                                                                                         ` martin rudalics
2020-02-10  7:06                                                                                                                           ` Dmitry Gutov
2020-02-10 17:53                                                                                                                             ` martin rudalics
2020-02-10 22:40                                                                                                                               ` Dmitry Gutov
2020-02-10  7:22                                                                                                                           ` Dmitry Gutov
2020-02-10 17:54                                                                                                                             ` martin rudalics
2020-02-10 22:49                                                                                                                               ` Dmitry Gutov
2020-02-13 18:42                                                                                                                                 ` martin rudalics
2020-02-13 23:48                                                                                                                                   ` Dmitry Gutov
2020-02-14  8:48                                                                                                                                     ` martin rudalics
2020-02-15 22:31                                                                                                                                       ` Dmitry Gutov
2020-02-16 10:01                                                                                                                                         ` martin rudalics
2020-02-16 20:47                                                                                                                                           ` Dmitry Gutov
2020-02-17 18:20                                                                                                                                             ` martin rudalics
2020-02-21 11:03                                                                                                                                               ` Dmitry Gutov
2020-02-21 11:13                                                                                                                                                 ` Dmitry Gutov
2020-02-21 16:08                                                                                                                                                   ` martin rudalics
2020-02-24  0:11                                                                                                                                                     ` Dmitry Gutov
2020-02-26 17:30                                                                                                                                                       ` martin rudalics
2020-02-28 16:32                                                                                                                                                         ` martin rudalics
2020-03-03 13:50                                                                                                                                                           ` Dmitry Gutov
2020-03-03 14:40                                                                                                                                                             ` martin rudalics
2020-03-03 18:27                                                                                                                                                               ` Dmitry Gutov
2020-03-04 17:29                                                                                                                                                                 ` martin rudalics
2020-03-06 23:38                                                                                                                                                                   ` Dmitry Gutov
2020-03-07  0:07                                                                                                                                                                   ` Dmitry Gutov
2020-03-06 23:03                                                                                                                                                         ` Dmitry Gutov
2020-02-16 23:01                                                                                                                                           ` Dmitry Gutov
2020-02-17 18:21                                                                                                                                             ` martin rudalics
2020-02-21 14:18                                                                                                                                               ` Dmitry Gutov
2020-02-21 16:08                                                                                                                                                 ` martin rudalics
2020-02-23  9:22                                                                                                                                                   ` Dmitry Gutov
2020-02-26 17:30                                                                                                                                                     ` martin rudalics
2020-03-06 23:32                                                                                                                                                       ` Dmitry Gutov
2020-03-09  9:03                                                                                                                                                         ` martin rudalics
2020-03-12  0:22                                                                                                                                                           ` Dmitry Gutov
2020-03-12  8:23                                                                                                                                                             ` martin rudalics
2020-03-13 16:57                                                                                                                                                               ` Dmitry Gutov
2020-03-13 17:46                                                                                                                                                                 ` martin rudalics
2020-03-16 19:51                                                                                                                                                                   ` Dmitry Gutov
2020-03-17  9:38                                                                                                                                                                     ` martin rudalics
2020-03-17 11:22                                                                                                                                                                       ` Dmitry Gutov
2020-03-31 17:04                                                                                                                                                                         ` martin rudalics
2020-04-03 11:09                                                                                                                                                                           ` Eli Zaretskii
2020-04-03 15:08                                                                                                                                                                             ` martin rudalics
2020-04-03 16:08                                                                                                                                                                               ` martin rudalics
2020-04-03 19:07                                                                                                                                                                               ` Dmitry Gutov
2020-04-04  8:51                                                                                                                                                                               ` Eli Zaretskii
2020-04-04  9:02                                                                                                                                                                                 ` martin rudalics
2020-04-04  9:30                                                                                                                                                                                   ` Eli Zaretskii
2020-04-06  9:03                                                                                                                                                                                     ` martin rudalics
2020-04-06 13:26                                                                                                                                                                                       ` Eli Zaretskii
2020-04-07  8:32                                                                                                                                                                                         ` martin rudalics
2020-04-07 14:04                                                                                                                                                                                           ` Eli Zaretskii
2020-04-06 18:36                                                                                                                                                                                       ` Dmitry Gutov
2020-04-07  8:33                                                                                                                                                                                         ` martin rudalics
2020-04-07 13:19                                                                                                                                                                                           ` Dmitry Gutov
2020-04-12  6:44                                                                                                                                                                           ` Andreas Schwab
2020-04-12  7:23                                                                                                                                                                             ` Eli Zaretskii
2020-04-12  7:37                                                                                                                                                                               ` Andreas Schwab
2020-04-12  8:03                                                                                                                                                                             ` martin rudalics
2020-04-06 22:51                                                                                                                                                               ` Dmitry Gutov
2020-04-07  8:33                                                                                                                                                                 ` martin rudalics
2020-04-07 14:25                                                                                                                                                                   ` Dmitry Gutov
2020-04-07 14:39                                                                                                                                                                     ` Robert Pluim
2020-04-07 14:50                                                                                                                                                                       ` Dmitry Gutov
2020-04-07 15:37                                                                                                                                                                         ` Robert Pluim
2020-04-07 19:25                                                                                                                                                                           ` Dmitry Gutov
2020-04-08  7:59                                                                                                                                                                             ` Robert Pluim
2020-04-08 10:37                                                                                                                                                                               ` Dmitry Gutov
2020-04-08 12:12                                                                                                                                                                                 ` Robert Pluim
2020-04-08  8:31                                                                                                                                                                   ` Support
2020-04-08  8:45                                                                                                                                                                     ` martin rudalics
2020-04-08  9:03                                                                                                                                                                       ` Adrián Medraño Calvo
2020-04-08  9:25                                                                                                                                                                         ` martin rudalics
2020-02-14  9:52                                                                                                                                     ` martin rudalics
2020-02-15 22:49                                                                                                                                       ` Dmitry Gutov
2020-02-16 10:01                                                                                                                                         ` martin rudalics
2020-01-27 23:20                                                                                           ` Dmitry Gutov
2020-01-27 23:32                                                                                             ` Dmitry Gutov
2020-01-28  9:48                                                                                               ` martin rudalics
2020-01-28 15:39                                                                                                 ` Dmitry Gutov
2020-01-28 16:20                                                                                                   ` martin rudalics
2020-01-28  9:48                                                                                             ` martin rudalics
2020-01-28 15:51                                                                                               ` Dmitry Gutov
2020-01-22 17:35                                                                         ` martin rudalics
2020-01-22 22:40                                                                           ` tumashu
2020-01-25  8:41                                                                             ` martin rudalics
2020-01-25 10:17                                                                               ` Dmitry Gutov
2020-01-25 10:29                                                                                 ` Eli Zaretskii
2020-01-25 10:52                                                                                   ` Dmitry Gutov
2020-01-25 12:11                                                                                 ` martin rudalics
2020-01-25 23:01                                                                                   ` Dmitry Gutov
2020-01-26  8:43                                                                                     ` martin rudalics
2020-01-26 11:02                                                                                       ` Dmitry Gutov
2020-01-26 15:32                                                                                         ` martin rudalics
2020-01-26 21:35                                                                                           ` Dmitry Gutov
2020-01-28  9:46                                                                                             ` martin rudalics
2020-01-30  2:23                                                                                               ` Dmitry Gutov
2020-01-30  9:38                                                                                                 ` martin rudalics
2020-01-30 17:32                                                                                                   ` Dmitry Gutov
2020-01-30 18:04                                                                                                     ` martin rudalics
2020-01-30 17:42                                                                                                   ` Dmitry Gutov
2020-01-30 18:04                                                                                                     ` martin rudalics
2020-01-26 11:03                                                                                   ` Dmitry Gutov
2020-01-23  0:21                                                                           ` Dmitry Gutov
2020-01-23  0:39                                                                             ` tumashu
2020-01-25  8:42                                                                             ` martin rudalics
2020-01-16  0:04                       ` Dmitry Gutov
2020-01-16  8:04                         ` martin rudalics
2020-01-16  8:25                           ` Dmitry Gutov
2020-01-11 10:36       ` tumashu
2020-01-11 13:45         ` martin rudalics
  -- strict thread matches above, loose matches on Subject: below --
2020-01-22  8:04 tumashu
2020-01-22  9:09 ` martin rudalics
2020-01-22 10:01   ` tumashu
2020-01-22 10:03   ` tumashu
2020-01-22 17:33     ` martin rudalics
2020-01-22 22:30       ` tumashu

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).