summaryrefslogtreecommitdiff
path: root/desktop-shell
diff options
context:
space:
mode:
authorLeandro Ribeiro <leandro.ribeiro@collabora.com>2023-01-23 18:19:50 -0300
committerDerek Foreman <derek.foreman@collabora.com>2023-01-31 19:22:45 +0000
commit4eea29151240eb95564f137e6e612f9d583d3daf (patch)
tree8074de64c835c87eb50654f55abb495e0e0a071a /desktop-shell
parent397e66a4dd55a19f96a95513775ac149803d0a33 (diff)
downloadweston-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.c21
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 {