After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 782183 - wayland: new window momentarily displays on wrong monitor
wayland: new window momentarily displays on wrong monitor
Status: RESOLVED FIXED
Product: mutter
Classification: Core
Component: wayland
3.24.x
Other Linux
: Normal normal
: ---
Assigned To: mutter-maint
mutter-maint
Depends on:
Blocks:
 
 
Reported: 2017-05-04 20:24 UTC by Christian Hergert
Modified: 2017-05-22 07:28 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Screencast (173.74 KB, video/webm)
2017-05-05 08:32 UTC, Olivier Fourdan
  Details
MUTTER_VERBOSE=1 logs (14.32 KB, text/plain)
2017-05-09 08:06 UTC, Olivier Fourdan
  Details
[RFC PATCH] wayland: place window if moved before placement (1.66 KB, patch)
2017-05-10 09:39 UTC, Olivier Fourdan
none Details | Review
[PATCH] wayland: place window if maximized before placement (1.46 KB, patch)
2017-05-16 09:36 UTC, Olivier Fourdan
committed Details | Review

Description Christian Hergert 2017-05-04 20:24:49 UTC
When running an application under Valgrind, I notice a behavior with a 2-monitor setup.

I'm running on gnome-shell 3.24.1, with my terminal/etc on the secondary monitor. Running my app under Valgrind like "valgrind ./some-test-app", the window briefly displays on the primary monitor before jumping to the secondary monitor where my mouse cursor is.

I assume this always happens, but it's just too quick for me to notice in the general case.
Comment 1 Olivier Fourdan 2017-05-05 07:33:22 UTC
I don't see that here with 3.22 on F25...

But anyhow this cannot be gtk+ as clients have no control on toplevel positioning under Wayland so this can only be a compositor issue...

That sounds like bug 750552 which was fixed long time ago though (see also bug 780820)
Comment 2 Olivier Fourdan 2017-05-05 08:32:24 UTC
Created attachment 351165 [details]
Screencast

I tried hard to reproduce on F26 with mutter 3.24 on an old and slow laptop, and all is fine with gtk3-demo.

Usually, things like that show well is a screencast (which makes things even slower) and here I see no problem at all in the screencast.

I do notice though that when an application starts either maximized or fullscreen (like totem replying the screencast) it does show up first on the primary monitor *then* gets relocated to the other monitor.

Maybe that's your issue? Can you tell a bit more about the issue you're seeing, maybe try to see if you can capture a screencast, or even better a log of mutter with MUTTER_VERBOSE set?
Comment 3 Christian Hergert 2017-05-08 22:11:27 UTC
(In reply to Olivier Fourdan from comment #2)
> I do notice though that when an application starts either maximized or
> fullscreen (like totem replying the screencast) it does show up first on the
> primary monitor *then* gets relocated to the other monitor.

This is exactly the issue, I forgot to mention the app is maximized before gtk_window_present() is called.
Comment 4 Olivier Fourdan 2017-05-09 08:06:01 UTC
Created attachment 351410 [details]
MUTTER_VERBOSE=1 logs

MUTTER_VERBOSE=1 of the issue when it happens.

We clearly see the window is first shown on the first monitor:

PLACEMENT: Putting window W2 on active workspace
WINDOW_STATE: Putting W2 in the move_resize queue
WINDOW_STATE: Putting W2 in the calc_showing queue
...
GEOMETRY: Clearing the move_resize queue
WINDOW_STATE: Removing W2 (Videos) from the move_resize queue
GEOMETRY: Constraining W2 (Videos) in move from 0,0 0x0 to 0,0 0x0
WORKAREA: Window W2 (Videos) monitor 0 has work area 0,0 1024 x 768
...

and then shortly after moved to the second monitor:

...
PLACEMENT: Placing window W2 (Videos)
XINERAMA: Natural monitor is 1024,0 +1024,768
WORKAREA: Window W2 (Videos) monitor 1 has work area 1024,0 1024 x 768
WORKAREA: Window W2 (Videos) monitor 1 has work area 1024,0 1024 x 768
WINDOW_OPS: Maximizing W2 (Videos)
Comment 5 Olivier Fourdan 2017-05-09 14:51:28 UTC
What happens (it seems) is that the window is first moved to a "wrong" location where it shows and when the set_maximized() is received, it gets moved to the "active" monitor which in Wayland happens to be the onw with the pointer.

What places the window at the wrong position initially is the initial apply_pending_state() which places the surface at (-26,-23) (the shadows offset):

  • #0 meta_window_actor_sync_actor_geometry
    at mutter/src/compositor/meta-window-actor.c line 1270
  • #1 meta_compositor_sync_window_geometry
    at mutter/src/compositor/compositor.c line 1018
  • #2 meta_window_move_resize_internal
    at mutter/src/core/window.c line 3743
  • #3 meta_window_wayland_move_resize
    at mutter/src/wayland/meta-window-wayland.c line 683
  • #4 xdg_toplevel_role_commit
    at mutter/src/wayland/meta-wayland-xdg-shell.c line 637
  • #5 meta_wayland_surface_role_commit
    at mutter/src/wayland/meta-wayland-surface.c line 1928
  • #6 apply_pending_state
    at mutter/src/wayland/meta-wayland-surface.c line 826
  • #7 ffi_call_unix64
    at ../src/x86/unix64.S line 76
  • #8 ffi_call
    at ../src/x86/ffi64.c line 525
  • #9 wl_closure_invoke
    at src/connection.c line 935
  • #10 wl_client_connection_data
    at src/wayland-server.c line 406
  • #11 wl_event_loop_dispatch
    at src/event-loop.c line 423
  • #12 wayland_event_source_dispatch
    at mutter/src/wayland/meta-wayland.c line 80
  • #13 g_main_dispatch
    at /glib/glib/gmain.c line 3234
  • #14 g_main_context_dispatch
    at /glib/glib/gmain.c line 3899
  • #15 g_main_context_iterate
    at /glib/glib/gmain.c line 3972
  • #16 g_main_loop_run
    at /glib/glib/gmain.c line 4168
  • #17 meta_run
    at mutter/src/core/main.c line 646
  • #18 main
    at mutter/src/core/mutter.c line 85

Then the animation is played from that "wrong" location and the window is finally showed at its final location on the "other" monitor.
Comment 6 Olivier Fourdan 2017-05-10 09:39:54 UTC
Created attachment 351522 [details] [review]
[RFC PATCH] wayland: place window if moved before placement

If a client changes the state of a surface to issue a set_maximize or a
set_fullscreen, the surface is resized before the window is actually
placed by mutter, which will show the initial animation at the wrong
location, before moving the window to the current monitor which is where
the pointer is placed.

Set the internal flag "placed" when this occurs so that mutter won't
relocate the window.
Comment 7 Olivier Fourdan 2017-05-10 13:20:55 UTC
Review of attachment 351522 [details] [review]:

Won't work, it breaks placement entirely as pretty much all clients issue a resize before showing.
Comment 8 Olivier Fourdan 2017-05-10 15:23:17 UTC
Oh, looks like we show the window "too early" before it's placed:

  • #0 start_simple_effect
    at mutter/src/compositor/meta-window-actor.c line 1066
  • #1 meta_window_actor_show
    at mutter/src/compositor/meta-window-actor.c line 1335
  • #2 meta_compositor_show_window
    at mutter/src/compositor/compositor.c line 784
  • #3 meta_window_show
    at mutter/src/core/window.c line 2405
  • #4 implement_showing
    at mutter/src/core/window.c line 1648
  • #5 meta_window_calc_showing
    at mutter/src/core/window.c line 1657
  • #6 idle_calc_showing
    at mutter/src/core/window.c line 1744
  • #7 run_repaint_laters
    at mutter/src/core/util.c line 809
  • #8 run_all_repaint_laters
    at mutter/src/core/util.c line 826
  • #9 _clutter_run_repaint_functions
    at mutter/clutter/clutter/clutter-main.c line 3433
  • #10 master_clock_update_stages
    at mutter/clutter/clutter/clutter-master-clock-default.c line 437
  • #11 clutter_clock_dispatch
    at mutter/clutter/clutter/clutter-master-clock-default.c line 567
  • #12 g_main_dispatch
    at glib/glib/gmain.c line 3234
  • #13 g_main_context_dispatch
    at glib/glib/gmain.c line 3899
  • #14 g_main_context_iterate
    at glib/glib/gmain.c line 3972
  • #15 g_main_loop_run
    at glib/glib/gmain.c line 4168
  • #16 meta_run
    at mutter/src/core/main.c line 646
  • #17 main
    at mutter/src/core/mutter.c line 85

So we play a "map effect" at the wrong position, then the window is placed appropriately and so moved to its final destination on the other monitor...
Comment 9 Olivier Fourdan 2017-05-16 09:36:46 UTC
Created attachment 351955 [details] [review]
[PATCH] wayland: place window if maximized before placement

If a client changes the state of a surface to issue a set_maximize, this
causes the window to be showing early due to apply_pending_state() being
called before placement.

If the monitor on which the window is to be shown initially is different
from the one where the pointer is placed, this causes the effect to be
played at the wrong location before the window reaches its monitor
location.

Force the window to be placed prior to change its state to maximized in
xdg-shell so that mutter won't relocate the window afterwards.
Comment 10 Jonas Ådahl 2017-05-18 09:52:48 UTC
Review of attachment 351955 [details] [review]:

::: src/wayland/meta-wayland-xdg-shell.c
@@ +352,3 @@
+   * this has no effect...
+   */
+  meta_window_force_placement (surface->window);

I think I understand why this helps, but my understanding doesn't seem to be what is described in the commit message...

1) a side effect of calling this is that window->placed is set to TRUE, which in turn avoids the defer-maximize-to-post-placement. For example, the issue is also fixed either by commenting out that early-out in meta_window_maximize() or changing the above line here to "window->placed = TRUE;".

2) this means the call below will actually do the move_resize call which will constrain etc resulting in meta_wayland_xdg_toplevel_send_configure() being called with the maximize dimensions.

3) this means that the meta_wayland_xdg_toplevel_send_configure(0,0) call in xdg_toplevel_role_commit() won't be called.

As far as I can tell, the incorrect call send_configure(0,0) was the issue here, as it meant the client first sent a non-maximized window geometry, which was used when showing and initial placing. After placing, the correct configure was sent, and then when the client had redrawn, the actual maximized surface content was provided.


So... our window management code is quite frustrating, and this fix has an after taste of work-around. I wonder if we can't fix this some better way.

First thing I can think of is to move part of the maximize code behind a MetaWindowClass vfunc, as there are multiple things in meta_window_maximize() that is X11 only (such as unshading, and this defer-maximize thing).

Another idea, is to get rid of that deferred-maximize thing all together. It seems to originate from 2003 with no explanation as to why, and I don't know how to trigger it either. When checking how it works with the panel-gtk test case under X11, window-props.c handles initial maximization in a different way. Given that meta_window_maximize() seems to be called mostly by interactive window management operations, the two places I think needs consideration are: meta_window_apply_session_info() (should probably set the defer-maximize variables, as done in window-props.c), and meta_window_x11_client_message().
Comment 11 Olivier Fourdan 2017-05-19 07:46:29 UTC
(In reply to Jonas Ådahl from comment #10)
> 
> [...]
> 
> First thing I can think of is to move part of the maximize code behind a
> MetaWindowClass vfunc, as there are multiple things in
> meta_window_maximize() that is X11 only (such as unshading, and this
> defer-maximize thing).
> 
> Another idea, is to get rid of that deferred-maximize thing all together. It
> seems to originate from 2003 with no explanation as to why, and I don't know
> how to trigger it either. When checking how it works with the panel-gtk test
> case under X11, window-props.c handles initial maximization in a different
> way. Given that meta_window_maximize() seems to be called mostly by
> interactive window management operations, the two places I think needs
> consideration are: meta_window_apply_session_info() (should probably set the
> defer-maximize variables, as done in window-props.c), and
> meta_window_x11_client_message().

I am not sure I follow, what is it you call "deferred-maximize", is it maximize_horizontally_after_placement and maximize_vertically_after_placement?
Comment 12 Olivier Fourdan 2017-05-19 07:56:13 UTC
Assuming this is maximize_*_after_placement, then this would be originally commit 010e620 for bug 111902
Comment 13 Jonas Ådahl 2017-05-19 08:21:44 UTC
(In reply to Olivier Fourdan from comment #11)
> (In reply to Jonas Ådahl from comment #10)

...

> I am not sure I follow, what is it you call "deferred-maximize", is it
> maximize_horizontally_after_placement and
> maximize_vertically_after_placement?

Yes. As in, it's deferred and not implemented until after placing.
Comment 14 Olivier Fourdan 2017-05-19 08:22:45 UTC
I think there is another thing to consider, if we remove the "maximize_*_after_placement" logic, the windows will most likely be misplaced when eventually they're de-maximized (as maximization is supposed to save the previous size/position so that de-maximizing a window restores the previous pre-maximization location and size on screen).
Comment 15 Jonas Ådahl 2017-05-19 08:40:46 UTC
(In reply to Olivier Fourdan from comment #14)
> I think there is another thing to consider, if we remove the
> "maximize_*_after_placement" logic, the windows will most likely be
> misplaced when eventually they're de-maximized (as maximization is supposed
> to save the previous size/position so that de-maximizing a window restores
> the previous pre-maximization location and size on screen).

AFAICS, with force_place() before maximize() will end up not setting any old rect. I think that also actually makes sense. We should probably not have mutter pretend to know what to restore to, as in Wayland that is up to the client. Initially we send 0x0, and I guess when restoring to something unknonw, we should send 0x0 too.
Comment 16 Olivier Fourdan 2017-05-19 08:51:34 UTC
For the size, sure the client is in charge, but the location still needs to be set/restored, and placement depends on the size.

BTW, I think there is more to it than just maximize_*_after_placement, if you remove that from meta_window_maximize() (as a test), the initial map animation still shows on the first monitor when the window is maximized on the second monitor (which is this bug. different from bug 781353 even if related)

To reproduce:

1. MUTTER_DEBUG_NUM_DUMMY_MONITORS=2 jhbuild run mutter --wayland --nested
2. Place the mouse pointer on the (fake) screen on the right
3. Launch an application that starts maximized (e.g. totem if closed while maximized)

=> The inital map animation plays on the monitor on the left and the window eventually shows on the monitor on the right (where the pointer is located, as this makes the "current" monitor)
Comment 17 Jonas Ådahl 2017-05-19 10:05:09 UTC
Review of attachment 351955 [details] [review]:

::: src/wayland/meta-wayland-xdg-shell.c
@@ +351,3 @@
+  /* Make sure the window is placed first, and if it's already placed,
+   * this has no effect...
+   */

We have been discussing this issue on IRC, and concluded that its probably not the right time to fix things "too" properly, and as this work around fixes the issue AFAIK without introducing any new issues, I think it's best to land it.

This comment seems a bit unnecessary though, as it states what is stated below. The reason why is probably a better thing to document here, but its also documented in the commit message so, maybe its not necessary anyway.

BTW, I think the commit message is a bit incorrect. Nothing is causing anything to be "showing early", as showing still will strictly be delayed until a buffer is attached.
Comment 18 Olivier Fourdan 2017-05-22 07:28:30 UTC
Comment on attachment 351955 [details] [review]
[PATCH] wayland: place window if maximized before placement

attachment 351955 [details] [review] pushed to git master as commit 561d71b - wayland: place window if maximized before placement

attachment 351955 [details] [review] pushed to branch gnome-3-24 as commit 7801df7 - wayland: place window if maximized before placement