desktop-shell: Properly handle lowered fullscreen surfaces
lower_fullscreen_surface() was removing fullscreen surfaces from
the fullscreen layer and inserting them in the normal workspace
layer. However, those fullscreen surfaces were never put back in
the fullscreen layer, causing bugs such as unrelated surfaces
being drawn between a fullscreen surface and its black view.
Change the lower_fullscreen_surface() logic so that it lowers
fullscreen surfaces to the workspace layer *and* hides the
black views. Make this reversible by re-configuring the lowered
fullscreen surface: when it is re-configured, the black view
will be shown again and the surface will be restacked in the
fullscreen layer.
https://bugs.freedesktop.org/show_bug.cgi?id=73575
https://bugs.freedesktop.org/show_bug.cgi?id=74221
https://bugs.freedesktop.org/show_bug.cgi?id=74222
diff --git a/desktop-shell/exposay.c b/desktop-shell/exposay.c
index 9c649e7..1d8b40e 100644
--- a/desktop-shell/exposay.c
+++ b/desktop-shell/exposay.c
@@ -160,7 +160,7 @@
shell->exposay.column_current = esurface->column;
shell->exposay.cur_output = esurface->eoutput;
- activate(shell, view->surface, shell->exposay.seat);
+ activate(shell, view->surface, shell->exposay.seat, false);
shell->exposay.focus_current = view;
}
@@ -318,8 +318,6 @@
if (shell->exposay.focus_current == esurface->view)
highlight = esurface;
- set_alpha_if_fullscreen(get_shell_surface(view->surface));
-
exposay_animate_in(esurface);
i++;
@@ -538,10 +536,10 @@
* to the new. */
if (switch_focus && shell->exposay.focus_current)
activate(shell, shell->exposay.focus_current->surface,
- shell->exposay.seat);
+ shell->exposay.seat, true);
else if (shell->exposay.focus_prev)
activate(shell, shell->exposay.focus_prev->surface,
- shell->exposay.seat);
+ shell->exposay.seat, true);
wl_list_for_each(esurface, &shell->exposay.surface_list, link)
exposay_animate_out(esurface);
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index 43b93f6..9eda814 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -166,6 +166,7 @@
bool maximized;
bool fullscreen;
bool relative;
+ bool lowered;
} state, next_state, requested_state; /* surface states */
bool state_changed;
bool state_requested;
@@ -234,13 +235,6 @@
int unresponsive;
};
-void
-set_alpha_if_fullscreen(struct shell_surface *shsurf)
-{
- if (shsurf && shsurf->state.fullscreen)
- shsurf->fullscreen.black_view->alpha = 0.25;
-}
-
static struct desktop_shell *
shell_surface_get_shell(struct shell_surface *shsurf);
@@ -630,7 +624,7 @@
shell = state->seat->compositor->shell_interface.shell;
if (next) {
state->keyboard_focus = NULL;
- activate(shell, next, state->seat);
+ activate(shell, next, state->seat, true);
} else {
if (shell->focus_animation_type == ANIMATION_DIM_LAYER) {
if (state->ws->focus_animation)
@@ -1839,10 +1833,10 @@
struct weston_seat *seat = grab->grab.pointer->seat;
if (shsurf && button == BTN_LEFT && state) {
- activate(shsurf->shell, shsurf->surface, seat);
+ activate(shsurf->shell, shsurf->surface, seat, true);
surface_move(shsurf, seat, 0);
} else if (shsurf && button == BTN_RIGHT && state) {
- activate(shsurf->shell, shsurf->surface, seat);
+ activate(shsurf->shell, shsurf->surface, seat, true);
surface_rotate(shsurf, seat);
}
}
@@ -2157,7 +2151,7 @@
switch (shsurf->type) {
case SHELL_SURFACE_POPUP:
case SHELL_SURFACE_TOPLEVEL:
- if (shsurf->state.fullscreen) {
+ if (shsurf->state.fullscreen && !shsurf->state.lowered) {
return &shsurf->shell->fullscreen_layer.view_list;
} else if (shsurf->parent) {
/* Move the surface to its parent layer so
@@ -2540,7 +2534,7 @@
wl_list_for_each(seat, &shsurf->shell->compositor->seat_list, link) {
if (!seat->keyboard)
continue;
- activate(shsurf->shell, view->surface, seat);
+ activate(shsurf->shell, view->surface, seat, true);
}
}
@@ -2703,6 +2697,8 @@
&shsurf->fullscreen.black_view->layer_link);
weston_view_geometry_dirty(shsurf->fullscreen.black_view);
weston_surface_damage(shsurf->surface);
+
+ shsurf->state.lowered = false;
}
/* Create black surface and append it to the associated fullscreen surface.
@@ -2719,6 +2715,10 @@
if (shsurf->fullscreen.type != WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER)
restore_output_mode(output);
+ /* Reverse the effect of lower_fullscreen_layer() */
+ wl_list_remove(&shsurf->view->layer_link);
+ wl_list_insert(&shsurf->shell->fullscreen_layer.view_list, &shsurf->view->layer_link);
+
shell_ensure_fullscreen_black_view(shsurf);
surface_subsurfaces_boundingbox(shsurf->surface, &surf_x, &surf_y,
@@ -4436,8 +4436,12 @@
surface_rotate(surface, seat);
}
-/* Move all fullscreen layers down to the current workspace in a non-reversible
- * manner. This should be used when implementing shell-wide overlays, such as
+/* Move all fullscreen layers down to the current workspace and hide their
+ * black views. The surfaces' state is set to both fullscreen and lowered,
+ * and this is reversed when such a surface is re-configured, see
+ * shell_configure_fullscreen() and shell_ensure_fullscreen_black_view().
+ *
+ * This should be used when implementing shell-wide overlays, such as
* the alt-tab switcher, which need to de-promote fullscreen layers. */
void
lower_fullscreen_layer(struct desktop_shell *shell)
@@ -4449,16 +4453,32 @@
wl_list_for_each_reverse_safe(view, prev,
&shell->fullscreen_layer.view_list,
layer_link) {
+ struct shell_surface *shsurf = get_shell_surface(view->surface);
+
+ if (!shsurf)
+ continue;
+
+ /* We can have a non-fullscreen popup for a fullscreen surface
+ * in the fullscreen layer. */
+ if (shsurf->state.fullscreen) {
+ /* Hide the black view */
+ wl_list_remove(&shsurf->fullscreen.black_view->layer_link);
+ wl_list_init(&shsurf->fullscreen.black_view->layer_link);
+ }
+
+ /* Lower the view to the workspace layer */
wl_list_remove(&view->layer_link);
wl_list_insert(&ws->layer.view_list, &view->layer_link);
weston_view_damage_below(view);
weston_surface_damage(view->surface);
+
+ shsurf->state.lowered = true;
}
}
void
activate(struct desktop_shell *shell, struct weston_surface *es,
- struct weston_seat *seat)
+ struct weston_seat *seat, bool configure)
{
struct weston_surface *main_surface;
struct focus_state *state;
@@ -4482,7 +4502,7 @@
shsurf = get_shell_surface(main_surface);
assert(shsurf);
- if (shsurf->state.fullscreen)
+ if (shsurf->state.fullscreen && configure)
shell_configure_fullscreen(shsurf);
else
restore_all_output_modes(shell->compositor);
@@ -4531,7 +4551,7 @@
if (get_shell_surface_type(main_surface) == SHELL_SURFACE_NONE)
return;
- activate(shell, focus, seat);
+ activate(shell, focus, seat, true);
}
static void
@@ -4951,7 +4971,7 @@
if (shell->locked)
break;
wl_list_for_each(seat, &compositor->seat_list, link)
- activate(shell, shsurf->surface, seat);
+ activate(shell, shsurf->surface, seat, true);
break;
case SHELL_SURFACE_POPUP:
case SHELL_SURFACE_NONE:
@@ -5402,7 +5422,7 @@
if (switcher->current)
activate(switcher->shell, switcher->current,
- (struct weston_seat *) keyboard->seat);
+ (struct weston_seat *) keyboard->seat, true);
wl_list_remove(&switcher->listener.link);
weston_keyboard_end_grab(keyboard);
if (keyboard->input_method_resource)
diff --git a/desktop-shell/shell.h b/desktop-shell/shell.h
index 4ed11d5..09f8b79 100644
--- a/desktop-shell/shell.h
+++ b/desktop-shell/shell.h
@@ -206,9 +206,6 @@
char *client;
};
-void
-set_alpha_if_fullscreen(struct shell_surface *shsurf);
-
struct weston_output *
get_default_output(struct weston_compositor *compositor);
@@ -226,7 +223,7 @@
void
activate(struct desktop_shell *shell, struct weston_surface *es,
- struct weston_seat *seat);
+ struct weston_seat *seat, bool configure);
void
exposay_binding(struct weston_seat *seat,