Avoid refocusing destroyed lock surfaces

886699c1fffd9ea083edf76b167a76fd6991a114
Alexis Sellier committed ago 1 parent d85b756f
swm.c +17 -3
2953 2953
    wlr_scene_node_destroy(&lock->scene->node);
2954 2954
    cur_lock = nullptr;
2955 2955
    pool_release(&session_lock_pool, lock);
2956 2956
}
2957 2957
2958 +
/* Return the first surface available to receive lock-screen keyboard focus. */
2959 +
static struct wlr_session_lock_surface_v1 *lock_surface_next(
2960 +
    struct wlr_session_lock_v1 *lock, struct wlr_session_lock_surface_v1 *removed
2961 +
) {
2962 +
    struct wlr_session_lock_surface_v1 *surface;
2963 +
2964 +
    if (!lock)
2965 +
        return nullptr;
2966 +
    wl_list_for_each(surface, &lock->surfaces, link) {
2967 +
        if (surface != removed)
2968 +
            return surface;
2969 +
    }
2970 +
    return nullptr;
2971 +
}
2972 +
2958 2973
/* Remove a display's session-lock surface and restore its background. */
2959 2974
void destroy_lock_surface(struct wl_listener *listener, void *data) {
2960 2975
    monitor_t                          *m = wl_container_of(listener, m, destroy_lock_surface);
2961 2976
    struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface;
2962 2977
2967 2982
    lock_surface->surface->data = nullptr;
2968 2983
2969 2984
    if (lock_surface->surface != seat->keyboard_state.focused_surface)
2970 2985
        return;
2971 2986
2972 -
    if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) {
2973 -
        surface = wl_container_of(cur_lock->surfaces.next, surface, link);
2987 +
    if (locked && (surface = lock_surface_next(cur_lock, lock_surface)))
2974 2988
        client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat));
2975 -
    } else if (!locked) {
2989 +
    else if (!locked) {
2976 2990
        focus_client(focus_top(selmon), 1);
2977 2991
    } else {
2978 2992
        wlr_seat_keyboard_clear_focus(seat);
2979 2993
        input_method_set_focus(nullptr);
2980 2994
    }
test/unit.c +12 -0
385 385
    scaled_surface       = nullptr;
386 386
    monitor_set_scale(&monitor);
387 387
    assert(scaled_surface == &surface);
388 388
}
389 389
390 +
/* Verify destroying a focused lock surface skips that surface during refocus. */
391 +
static void test_lock_surface_refocus(void) {
392 +
    struct wlr_session_lock_v1         lock    = {};
393 +
    struct wlr_session_lock_surface_v1 removed = {}, remaining = {};
394 +
395 +
    wl_list_init(&lock.surfaces);
396 +
    wl_list_insert(lock.surfaces.prev, &removed.link);
397 +
    wl_list_insert(lock.surfaces.prev, &remaining.link);
398 +
    assert(lock_surface_next(&lock, &removed) == &remaining);
399 +
}
400 +
390 401
/* Verify directed output moves preserve a window's display-relative position. */
391 402
static void test_monitor_translation(void) {
392 403
    monitor_t oldmon = { .m = { 0, 0, 1920, 1080 } };
393 404
    monitor_t newmon = { .m = { 1920, 100, 2560, 1440 } };
394 405
    client_t  client = { .geom = { 100, 50, 640, 480 }, .prev = { 200, 75, 800, 600 } };
1152 1163
        { "input-method", test_input_method_lifecycle },
1153 1164
        { "output-role-scale-change", test_output_role_scale_change },
1154 1165
        { "input-early-paths", test_input_early_paths },
1155 1166
        { "command-line", test_command_line_errors },
1156 1167
        { "monitor-translation", test_monitor_translation },
1168 +
        { "lock-surface-refocus", test_lock_surface_refocus },
1157 1169
        { "pointer-and-decoration", test_pointer_and_decoration_lifecycle },
1158 1170
        { "keybindings-and-repeat", test_keybindings_and_repeat },
1159 1171
    };
1160 1172
1161 1173
    if (argc == 2 && !strcmp(argv[1], "--list")) {