From 0668c0a3e8324b4919c1ab02a98caa0096f7c7de Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 23 May 2024 14:34:24 +0200 Subject: [PATCH 1/4] idle_inhibit: Ignore inhibitors when locked When a session is locked, no views are visible and there is no way to interact with the user session. This means that all inhibitors based on visibility - with the exception being inhibitors on the session lock surfaces themselves - become inert, allowing the session to go idle. The only inhibitor type on normal views that one could argue should remain active is INHIBIT_IDLE_OPEN, but for now we disable all view inhibitors regardless of type. --- sway/desktop/idle_inhibit_v1.c | 14 ++++++++++++++ sway/lock.c | 7 +++++++ sway/tree/view.c | 4 ++++ 3 files changed, 25 insertions(+) diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index f3af7aa1b..d241cdaf4 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -1,5 +1,6 @@ #include #include +#include #include "log.h" #include "sway/desktop/idle_inhibit_v1.h" #include "sway/input/seat.h" @@ -103,6 +104,19 @@ void sway_idle_inhibit_v1_user_inhibitor_destroy( } bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { + if (server.session_lock.lock) { + // A session lock is active. In this case, only application inhibitors + // on the session lock surface can have any effect. + if (inhibitor->mode != INHIBIT_IDLE_APPLICATION) { + return false; + } + struct wlr_surface *wlr_surface = inhibitor->wlr_inhibitor->surface; + if (!wlr_session_lock_surface_v1_try_from_wlr_surface(wlr_surface)) { + return false; + } + return wlr_surface->mapped; + } + switch (inhibitor->mode) { case INHIBIT_IDLE_APPLICATION:; // If there is no view associated with the inhibitor, assume visible diff --git a/sway/lock.c b/sway/lock.c index 289e8ca46..28618cc26 100644 --- a/sway/lock.c +++ b/sway/lock.c @@ -239,6 +239,9 @@ static void handle_unlock(struct wl_listener *listener, void *data) { struct sway_output *output = root->outputs->items[i]; arrange_layers(output); } + + // Views are now visible, so check if we need to activate inhibition again. + sway_idle_inhibit_v1_check_active(); } static void handle_abandon(struct wl_listener *listener, void *data) { @@ -302,6 +305,10 @@ static void handle_session_lock(struct wl_listener *listener, void *data) { wlr_session_lock_v1_send_locked(lock); server.session_lock.lock = sway_lock; + + // The lock screen covers everything, so check if any active inhibition got + // deactivated due to lost visibility. + sway_idle_inhibit_v1_check_active(); } static void handle_session_lock_destroy(struct wl_listener *listener, void *data) { diff --git a/sway/tree/view.c b/sway/tree/view.c index 4f757acf1..6232070ce 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c @@ -190,6 +190,10 @@ uint32_t view_configure(struct sway_view *view, double lx, double ly, int width, } bool view_inhibit_idle(struct sway_view *view) { + if (server.session_lock.lock) { + return false; + } + struct sway_idle_inhibitor_v1 *user_inhibitor = sway_idle_inhibit_v1_user_inhibitor_for_view(view); From 6ccfa7a80b284b93509e131acdbc7edc23bdf257 Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 23 May 2024 15:01:46 +0200 Subject: [PATCH 2/4] idle_inhibit: Explicitly handle layer surfaces Layer surfaces do not have a view, and while they can be occluded they are always visible on their associated output - assuming it is enabled. --- sway/desktop/idle_inhibit_v1.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index d241cdaf4..0fc79989a 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -119,8 +119,15 @@ bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { switch (inhibitor->mode) { case INHIBIT_IDLE_APPLICATION:; + struct wlr_surface *wlr_surface = inhibitor->wlr_inhibitor->surface; + if (wlr_layer_surface_v1_try_from_wlr_surface(wlr_surface)) { + // Layer surfaces can be occluded but are always on screen after + // they have been mapped. + return wlr_surface->mapped; + } + // If there is no view associated with the inhibitor, assume visible - struct sway_view *view = view_from_wlr_surface(inhibitor->wlr_inhibitor->surface); + struct sway_view *view = view_from_wlr_surface(wlr_surface); return !view || !view->container || view_is_visible(view); case INHIBIT_IDLE_FOCUS:; struct sway_seat *seat = NULL; From 444017fdacbfec33424fe39e81d8788f03b1dffe Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Thu, 23 May 2024 15:03:44 +0200 Subject: [PATCH 3/4] idle_inhibit: Assume view is invisible by default We have historically considered surfaces without a view visible. This made sense in case of layer surfaces which do not have a view, but it also allows unmapped surfaces to act as global inhibitors irrespective of the current view state, which is not the intention fo the protocol. As we now explicitly handle layer surfaces, assume that views are only visible if they can be found and their visibility checked. --- sway/desktop/idle_inhibit_v1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index 0fc79989a..9fc223d06 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -126,9 +126,9 @@ bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { return wlr_surface->mapped; } - // If there is no view associated with the inhibitor, assume visible + // If there is no view associated with the inhibitor, assume invisible struct sway_view *view = view_from_wlr_surface(wlr_surface); - return !view || !view->container || view_is_visible(view); + return view && view->container && view_is_visible(view); case INHIBIT_IDLE_FOCUS:; struct sway_seat *seat = NULL; wl_list_for_each(seat, &server.input->seats, link) { From 1a1bc78ce5868b4faad48dcaa76ba26a86b0ccab Mon Sep 17 00:00:00 2001 From: Kenny Levinsen Date: Tue, 11 Jun 2024 00:12:02 +0200 Subject: [PATCH 4/4] idle_inhibit: Check if layer surface output is enabled While we we cannot easily check for true visibility of layer surfaces as easily as for views, we can check at least check that the output associated with the surface is enabled. --- sway/desktop/idle_inhibit_v1.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index 9fc223d06..b495c204c 100644 --- a/sway/desktop/idle_inhibit_v1.c +++ b/sway/desktop/idle_inhibit_v1.c @@ -120,10 +120,13 @@ bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { switch (inhibitor->mode) { case INHIBIT_IDLE_APPLICATION:; struct wlr_surface *wlr_surface = inhibitor->wlr_inhibitor->surface; - if (wlr_layer_surface_v1_try_from_wlr_surface(wlr_surface)) { + struct wlr_layer_surface_v1 *layer_surface = + wlr_layer_surface_v1_try_from_wlr_surface(wlr_surface); + if (layer_surface) { // Layer surfaces can be occluded but are always on screen after // they have been mapped. - return wlr_surface->mapped; + return layer_surface->output && layer_surface->output->enabled && + wlr_surface->mapped; } // If there is no view associated with the inhibitor, assume invisible