Set lock focus per-seat

This commit is contained in:
Erik Reider 2026-05-15 13:02:30 +02:00
parent bafbcdd139
commit c2ae62e21c
4 changed files with 43 additions and 33 deletions

View file

@ -99,6 +99,7 @@ struct sway_seat {
char *prev_workspace_name; // for workspace back_and_forth
struct wlr_layer_surface_v1 *focused_layer;
struct wlr_surface *focused_lock;
// If the exclusive layer is set, views cannot receive keyboard focus
bool has_exclusive_layer;

View file

@ -13,7 +13,6 @@ struct sway_transaction;
struct sway_session_lock {
struct wlr_session_lock_v1 *lock;
struct wlr_surface *focused;
bool abandoned;
struct wl_list outputs; // struct sway_session_lock_output
@ -182,7 +181,7 @@ void sway_session_lock_add_output(struct sway_session_lock *lock,
bool sway_session_lock_has_surface(struct sway_session_lock *lock,
struct wlr_surface *surface);
void sway_session_lock_focus_output(struct sway_session_lock *lock,
struct sway_output *output);
struct sway_seat* seat, struct sway_output *output);
void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data);
#if WLR_HAS_XWAYLAND
void handle_xwayland_surface(struct wl_listener *listener, void *data);

View file

@ -1269,11 +1269,11 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
// Try focusing the current sway_output's lock-surface
struct sway_output *output = node ? node_get_output(node) : NULL;
if (output) {
sway_session_lock_focus_output(server.session_lock.lock, output);
sway_session_lock_focus_output(server.session_lock.lock, seat, output);
return;
}
// Fallback to the previously focused lock surface
seat_set_focus_surface(seat, server.session_lock.lock->focused, false);
seat_set_focus_surface(seat, seat->focused_lock, false);
}
}

View file

@ -30,38 +30,39 @@ struct sway_session_lock_output {
};
static void focus_surface(struct sway_session_lock *lock,
struct wlr_surface *focused) {
lock->focused = focused;
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
struct sway_seat *seat, struct wlr_surface *focused) {
if (seat) {
seat->focused_lock = focused;
seat_set_focus_surface(seat, focused, false);
}
}
static void refocus_output(struct sway_session_lock_output *output) {
// Move the seat focus to another surface if one is available
if (output->lock->focused == output->surface->surface) {
struct wlr_surface *next_focus = NULL;
struct wlr_surface *next_focus = NULL;
struct sway_session_lock_output *candidate;
wl_list_for_each(candidate, &output->lock->outputs, link) {
if (candidate == output || !candidate->surface) {
continue;
}
if (candidate->surface->surface->mapped) {
next_focus = candidate->surface->surface;
break;
}
struct sway_session_lock_output *candidate;
wl_list_for_each(candidate, &output->lock->outputs, link) {
if (candidate == output || !candidate->surface) {
continue;
}
focus_surface(output->lock, next_focus);
if (candidate->surface->surface->mapped) {
next_focus = candidate->surface->surface;
break;
}
}
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
if (seat->focused_lock == output->surface->surface) {
focus_surface(output->lock, seat, next_focus);
}
}
}
void sway_session_lock_focus_output(struct sway_session_lock *lock,
struct sway_output *output) {
struct sway_seat* seat, struct sway_output *output) {
// Try focusing the lock surface on the provided output
struct sway_session_lock_output *candidate;
wl_list_for_each(candidate, &lock->outputs, link) {
@ -70,8 +71,7 @@ void sway_session_lock_focus_output(struct sway_session_lock *lock,
}
if (candidate->surface->surface->mapped) {
// Set the focus for all seats
focus_surface(lock, candidate->surface->surface);
focus_surface(lock, seat, candidate->surface->surface);
break;
}
}
@ -80,15 +80,18 @@ void sway_session_lock_focus_output(struct sway_session_lock *lock,
static void handle_surface_map(struct wl_listener *listener, void *data) {
struct sway_session_lock_output *surf = wl_container_of(listener, surf, surface_map);
struct sway_seat *seat = input_manager_current_seat();
struct sway_workspace *focused_ws = seat_get_focused_workspace(seat);
struct sway_output *focused_output = focused_ws ? focused_ws->output : NULL;
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
struct sway_workspace *focused_ws = seat_get_focused_workspace(seat);
struct sway_output *focused_output = focused_ws ? focused_ws->output : NULL;
// Only set the initial focus surface when it's on the focused output.
// Fallback to the first mapped surface if no focused output can be found.
if (focused_output == surf->output
|| (!focused_output && surf->lock->focused == NULL)) {
focus_surface(surf->lock, surf->surface->surface);
// Only set the initial focus lock-surface when the surface is on the
// focused output. Fallback to the first mapped surface if no focused
// output can be found.
if (focused_output == surf->output
|| (!focused_output && seat->focused_lock == NULL)) {
focus_surface(surf->lock, seat, surf->surface->surface);
}
}
cursor_rebase_all();
}
@ -224,6 +227,11 @@ static void sway_session_lock_destroy(struct sway_session_lock* lock) {
wlr_scene_node_destroy(&lock_output->tree->node);
}
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
seat->focused_lock = NULL;
}
if (server.session_lock.lock == lock) {
server.session_lock.lock = NULL;
}
@ -245,6 +253,8 @@ static void handle_unlock(struct wl_listener *listener, void *data) {
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
seat->focused_lock = NULL;
// copied from seat_set_focus_layer -- deduplicate?
struct sway_node *previous = seat_get_focus_inactive(seat, &root->node);
if (previous) {