diff options
author | Leandro Ribeiro <leandro.ribeiro@collabora.com> | 2023-01-23 18:19:50 -0300 |
---|---|---|
committer | Derek Foreman <derek.foreman@collabora.com> | 2023-01-31 19:22:45 +0000 |
commit | 4eea29151240eb95564f137e6e612f9d583d3daf (patch) | |
tree | 8074de64c835c87eb50654f55abb495e0e0a071a /desktop-shell | |
parent | 397e66a4dd55a19f96a95513775ac149803d0a33 (diff) | |
download | weston-4eea29151240eb95564f137e6e612f9d583d3daf.tar.gz |
desktop-shell: avoid alternating surface between outputs
In commit d611ab24fd0004fb1a06fe2fc843251419fac784 "libweston: Update
view transforms more often", a call to weston_view_update_transform()
was introduced to desktop_surface_committed(). It was added between the
point in which we call unset_fullscreen() and
shell_configure_fullscreen(), right after the view geometry dirty bit is
set.
There's a scenario with dual displays in which this change resulted in
the surface being alternated between two outputs:
---
Dual display configuration:
1st display: DP1, with scale 1 - origin 0, 0
2nd display: DP2, with scale 2 - origin 1920, 0
We start the app with the cursor on DP2. Function
desktop_surface_committed() gets called a few times, and it ends up
setting shsurf->saved_x and shsurf->saved_y to the origin of DP2.
Application wants to become fullscreen on DP1, so when the surface gets
committed again and desktop_surface_committed() gets called, we have the
following sequence:
desktop_surface_committed():
was_fullscreen = shsurf->state.fullscreen
is_fullscreen = weston_desktop_surface_get_fullscreen()
if (!weston_surface_is_mapped(desktop_surf))
map(shell, desktop_surf)
return;
/* POINT A, this is important for understanding the issue. */
if (shsurf size didn't change and
fullscreen state didn't change)
return;
if (was_fullscreen)
/* This function calls weston_view_set_pos(saved_x,
* saved_y), and the saved position is the origin of
* DP2. Then it invalidates the saved position */
unset_fullscreen(shsurf)
if (is_fullscreen && !shsurf->saved_position_valid)
/* Saves the position (as it just have been
* invalidated), which will be the origin of DP2
* again. */
shsurf->saved_x = shsurf->view->geometry.x
shsurf->saved_y = shsurf->view->geometry.y
shsurf->saved_position_valid = true
/* This function calls weston_view_assign_output(), which then
* calls weston_surface_assign_output(). The effect of these two
* functions is that the view gets assigned to an output, and to
* choose the output it takes into consideration the position in
* which it is and the area that it occupies on the output. As
* the view has been moved to the origin of DP2, it gets
* assigned to this output. Then Weston sends the enter/leave
* surface events. */
weston_view_update_transform()
if (is_fullscreen)
/* This function positions the view on DP1, because
* that's the output in which the wine app wants to
* become fullscreen. */
shell_configure_fullscreen(shsurf)
/* Now we call weston_view_update_transform() again to each view
* of the surface, and so we end up sending enter/leave surface
* events. But notice that now we are positioned on DP1. */
wl_list_for_each(view, &surface->views, surface_link)
weston_view_update_transform(view);
The next time the surface gets committed and desktop_surface_committed()
gets called, the same sequence will happen. So we'll continue in this
weird loop.
The reason why the surface size changes and we don't return in POINT A
in this scenario is because the application uses a viewport, and then
when its surface moves to the output with scale 2 it sets the surface
size to half its size. That happens for apps that want to keep a
reasonable DPI on scaled displays.
This only happens after the change that introduced the call to
weston_view_update_transform() in this function. Without this call we'd
not reposition the view on DP2 and send enter/leave events at that
point.
---
So in order to avoid that, be more careful before calling
unset_fullscreen() and then shell_configure_fullscreen(). Only do that
when:
- the surface was not fullscreen, and now it becomes.
- the surface was fullscreen, but now it becomes fullscreen on a
different output.
In order to be consistent, do something similar to the maximized state.
Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
Diffstat (limited to 'desktop-shell')
-rw-r--r-- | desktop-shell/shell.c | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 9224cab8..317fab01 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -2051,8 +2051,8 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface, weston_desktop_surface_get_surface(desktop_surface); struct weston_view *view = shsurf->view; struct desktop_shell *shell = data; - bool was_fullscreen; - bool was_maximized; + bool was_fullscreen, should_set_fullscreen; + bool was_maximized, should_set_maximized; if (surface->width == 0) return; @@ -2065,6 +2065,12 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface, shsurf->state.maximized = weston_desktop_surface_get_maximized(desktop_surface); + should_set_fullscreen = shsurf->state.fullscreen && + (!was_fullscreen || shsurf->output != + shsurf->fullscreen_output); + should_set_maximized = shsurf->state.maximized && + !was_maximized; + if (!weston_surface_is_mapped(surface)) { map(shell, shsurf); /* as we need to survive the weston_surface destruction we'll @@ -2086,12 +2092,13 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface, was_maximized == shsurf->state.maximized) return; - if (was_fullscreen) + if (was_fullscreen && (!shsurf->state.fullscreen || + shsurf->output != shsurf->fullscreen_output)) unset_fullscreen(shsurf); - if (was_maximized) + if (was_maximized && !shsurf->state.maximized) unset_maximized(shsurf); - if ((shsurf->state.fullscreen || shsurf->state.maximized) && + if ((should_set_fullscreen || should_set_maximized) && !shsurf->saved_position_valid) { shsurf->saved_x = shsurf->view->geometry.x; shsurf->saved_y = shsurf->view->geometry.y; @@ -2107,9 +2114,9 @@ desktop_surface_committed(struct weston_desktop_surface *desktop_surface, weston_view_update_transform(shsurf->view); - if (shsurf->state.fullscreen) { + if (should_set_fullscreen) { shell_configure_fullscreen(shsurf); - } else if (shsurf->state.maximized) { + } else if (should_set_maximized) { set_maximized_position(shell, shsurf); surface->output = shsurf->output; } else { |