Add support for ext-session-lock-v1

This is a new protocol to lock the session [1]. It should be more
reliable than layer-shell + input-inhibitor.

[1]: https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/131
This commit is contained in:
Simon Ser 2021-12-20 17:25:44 +01:00
parent 978ce49894
commit 1d1c75b631
3 changed files with 100 additions and 29 deletions

View File

@ -89,6 +89,8 @@ struct swaylock_state {
int failed_attempts; int failed_attempts;
bool run_display; bool run_display;
struct zxdg_output_manager_v1 *zxdg_output_manager; struct zxdg_output_manager_v1 *zxdg_output_manager;
struct ext_session_lock_manager_v1 *ext_session_lock_manager_v1;
struct ext_session_lock_v1 *ext_session_lock_v1;
}; };
struct swaylock_surface { struct swaylock_surface {
@ -101,6 +103,7 @@ struct swaylock_surface {
struct wl_surface *child; // surface made into subsurface struct wl_surface *child; // surface made into subsurface
struct wl_subsurface *subsurface; struct wl_subsurface *subsurface;
struct zwlr_layer_surface_v1 *layer_surface; struct zwlr_layer_surface_v1 *layer_surface;
struct ext_session_lock_surface_v1 *ext_session_lock_surface_v1;
struct pool_buffer buffers[2]; struct pool_buffer buffers[2];
struct pool_buffer indicator_buffers[2]; struct pool_buffer indicator_buffers[2];
struct pool_buffer *current_buffer; struct pool_buffer *current_buffer;

85
main.c
View File

@ -26,6 +26,7 @@
#include "wlr-input-inhibitor-unstable-v1-client-protocol.h" #include "wlr-input-inhibitor-unstable-v1-client-protocol.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h" #include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h" #include "xdg-output-unstable-v1-client-protocol.h"
#include "ext-session-lock-v1-client-protocol.h"
static uint32_t parse_color(const char *color) { static uint32_t parse_color(const char *color) {
if (color[0] == '#') { if (color[0] == '#') {
@ -97,6 +98,9 @@ static void destroy_surface(struct swaylock_surface *surface) {
if (surface->layer_surface != NULL) { if (surface->layer_surface != NULL) {
zwlr_layer_surface_v1_destroy(surface->layer_surface); zwlr_layer_surface_v1_destroy(surface->layer_surface);
} }
if (surface->ext_session_lock_surface_v1 != NULL) {
ext_session_lock_surface_v1_destroy(surface->ext_session_lock_surface_v1);
}
if (surface->surface != NULL) { if (surface->surface != NULL) {
wl_surface_destroy(surface->surface); wl_surface_destroy(surface->surface);
} }
@ -109,6 +113,7 @@ static void destroy_surface(struct swaylock_surface *surface) {
} }
static const struct zwlr_layer_surface_v1_listener layer_surface_listener; static const struct zwlr_layer_surface_v1_listener layer_surface_listener;
static const struct ext_session_lock_surface_v1_listener ext_session_lock_surface_v1_listener;
static cairo_surface_t *select_image(struct swaylock_state *state, static cairo_surface_t *select_image(struct swaylock_state *state,
struct swaylock_surface *surface); struct swaylock_surface *surface);
@ -120,7 +125,7 @@ static bool surface_is_opaque(struct swaylock_surface *surface) {
return (surface->state->args.colors.background & 0xff) == 0xff; return (surface->state->args.colors.background & 0xff) == 0xff;
} }
static void create_layer_surface(struct swaylock_surface *surface) { static void create_surface(struct swaylock_surface *surface) {
struct swaylock_state *state = surface->state; struct swaylock_state *state = surface->state;
surface->image = select_image(state, surface); surface->image = select_image(state, surface);
@ -134,10 +139,15 @@ static void create_layer_surface(struct swaylock_surface *surface) {
assert(surface->subsurface); assert(surface->subsurface);
wl_subsurface_set_sync(surface->subsurface); wl_subsurface_set_sync(surface->subsurface);
if (state->ext_session_lock_v1) {
surface->ext_session_lock_surface_v1 = ext_session_lock_v1_get_lock_surface(
state->ext_session_lock_v1, surface->surface, surface->output);
ext_session_lock_surface_v1_add_listener(surface->ext_session_lock_surface_v1,
&ext_session_lock_surface_v1_listener, surface);
} else {
surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface( surface->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
state->layer_shell, surface->surface, surface->output, state->layer_shell, surface->surface, surface->output,
ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen"); ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, "lockscreen");
assert(surface->layer_surface);
zwlr_layer_surface_v1_set_size(surface->layer_surface, 0, 0); zwlr_layer_surface_v1_set_size(surface->layer_surface, 0, 0);
zwlr_layer_surface_v1_set_anchor(surface->layer_surface, zwlr_layer_surface_v1_set_anchor(surface->layer_surface,
@ -150,6 +160,7 @@ static void create_layer_surface(struct swaylock_surface *surface) {
surface->layer_surface, true); surface->layer_surface, true);
zwlr_layer_surface_v1_add_listener(surface->layer_surface, zwlr_layer_surface_v1_add_listener(surface->layer_surface,
&layer_surface_listener, surface); &layer_surface_listener, surface);
}
if (surface_is_opaque(surface) && if (surface_is_opaque(surface) &&
surface->state->args.mode != BACKGROUND_MODE_CENTER && surface->state->args.mode != BACKGROUND_MODE_CENTER &&
@ -161,7 +172,9 @@ static void create_layer_surface(struct swaylock_surface *surface) {
wl_region_destroy(region); wl_region_destroy(region);
} }
if (!state->ext_session_lock_v1) {
wl_surface_commit(surface->surface); wl_surface_commit(surface->surface);
}
} }
static void layer_surface_configure(void *data, static void layer_surface_configure(void *data,
@ -188,6 +201,23 @@ static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
.closed = layer_surface_closed, .closed = layer_surface_closed,
}; };
static void ext_session_lock_surface_v1_handle_configure(void *data,
struct ext_session_lock_surface_v1 *lock_surface, uint32_t serial,
uint32_t width, uint32_t height) {
struct swaylock_surface *surface = data;
surface->width = width;
surface->height = height;
surface->indicator_width = 0;
surface->indicator_height = 0;
ext_session_lock_surface_v1_ack_configure(lock_surface, serial);
render_frame_background(surface);
render_frame(surface);
}
static const struct ext_session_lock_surface_v1_listener ext_session_lock_surface_v1_listener = {
.configure = ext_session_lock_surface_v1_handle_configure,
};
static const struct wl_callback_listener surface_frame_listener; static const struct wl_callback_listener surface_frame_listener;
static void surface_frame_handle_done(void *data, struct wl_callback *callback, static void surface_frame_handle_done(void *data, struct wl_callback *callback,
@ -302,6 +332,21 @@ struct zxdg_output_v1_listener _xdg_output_listener = {
.description = handle_xdg_output_description, .description = handle_xdg_output_description,
}; };
static void ext_session_lock_v1_handle_locked(void *data, struct ext_session_lock_v1 *lock) {
// Who cares
}
static void ext_session_lock_v1_handle_finished(void *data, struct ext_session_lock_v1 *lock) {
swaylock_log(LOG_ERROR, "Failed to lock session -- "
"is another lockscreen running?");
exit(2);
}
static const struct ext_session_lock_v1_listener ext_session_lock_v1_listener = {
.locked = ext_session_lock_v1_handle_locked,
.finished = ext_session_lock_v1_handle_finished,
};
static void handle_global(void *data, struct wl_registry *registry, static void handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version) { uint32_t name, const char *interface, uint32_t version) {
struct swaylock_state *state = data; struct swaylock_state *state = data;
@ -341,9 +386,12 @@ static void handle_global(void *data, struct wl_registry *registry,
wl_list_insert(&state->surfaces, &surface->link); wl_list_insert(&state->surfaces, &surface->link);
if (state->run_display) { if (state->run_display) {
create_layer_surface(surface); create_surface(surface);
wl_display_roundtrip(state->display); wl_display_roundtrip(state->display);
} }
} else if (strcmp(interface, ext_session_lock_manager_v1_interface.name) == 0) {
state->ext_session_lock_manager_v1 = wl_registry_bind(registry, name,
&ext_session_lock_manager_v1_interface, 1);
} }
} }
@ -1182,21 +1230,35 @@ int main(int argc, char **argv) {
struct wl_registry *registry = wl_display_get_registry(state.display); struct wl_registry *registry = wl_display_get_registry(state.display);
wl_registry_add_listener(registry, &registry_listener, &state); wl_registry_add_listener(registry, &registry_listener, &state);
wl_display_roundtrip(state.display); wl_display_roundtrip(state.display);
assert(state.compositor && state.layer_shell && state.shm);
if (!state.input_inhibit_manager) { if (!state.compositor || !state.shm) {
free(state.args.font); swaylock_log(LOG_ERROR, "Missing wl_compositor or wl_shm");
swaylock_log(LOG_ERROR, "Compositor does not support the input "
"inhibitor protocol, refusing to run insecurely");
return 1; return 1;
} }
if (state.ext_session_lock_manager_v1) {
swaylock_log(LOG_DEBUG, "Using ext-session-lock-v1");
state.ext_session_lock_v1 = ext_session_lock_manager_v1_lock(state.ext_session_lock_manager_v1);
ext_session_lock_v1_add_listener(state.ext_session_lock_v1,
&ext_session_lock_v1_listener, &state);
} else if (state.layer_shell && state.input_inhibit_manager) {
swaylock_log(LOG_DEBUG, "Using wlr-layer-shell + wlr-input-inhibitor");
zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager); zwlr_input_inhibit_manager_v1_get_inhibitor(state.input_inhibit_manager);
} else {
swaylock_log(LOG_ERROR, "Missing ext-session-lock-v1, wlr-layer-shell "
"and wlr-input-inhibitor");
return 1;
}
if (wl_display_roundtrip(state.display) == -1) { if (wl_display_roundtrip(state.display) == -1) {
free(state.args.font); free(state.args.font);
if (state.input_inhibit_manager) {
swaylock_log(LOG_ERROR, "Exiting - failed to inhibit input:" swaylock_log(LOG_ERROR, "Exiting - failed to inhibit input:"
" is another lockscreen already running?"); " is another lockscreen already running?");
return 2; return 2;
} }
return 1;
}
if (state.zxdg_output_manager) { if (state.zxdg_output_manager) {
struct swaylock_surface *surface; struct swaylock_surface *surface;
@ -1214,7 +1276,7 @@ int main(int argc, char **argv) {
struct swaylock_surface *surface; struct swaylock_surface *surface;
wl_list_for_each(surface, &state.surfaces, link) { wl_list_for_each(surface, &state.surfaces, link) {
create_layer_surface(surface); create_surface(surface);
} }
if (state.args.daemonize) { if (state.args.daemonize) {
@ -1237,6 +1299,11 @@ int main(int argc, char **argv) {
loop_poll(state.eventloop); loop_poll(state.eventloop);
} }
if (state.ext_session_lock_v1) {
ext_session_lock_v1_unlock_and_destroy(state.ext_session_lock_v1);
wl_display_flush(state.display);
}
free(state.args.font); free(state.args.font);
return 0; return 0;
} }

View File

@ -36,7 +36,7 @@ if is_freebsd
endif endif
wayland_client = dependency('wayland-client') wayland_client = dependency('wayland-client')
wayland_protos = dependency('wayland-protocols', version: '>=1.14', fallback: 'wayland-protocols') wayland_protos = dependency('wayland-protocols', version: '>=1.25', fallback: 'wayland-protocols')
xkbcommon = dependency('xkbcommon') xkbcommon = dependency('xkbcommon')
cairo = dependency('cairo') cairo = dependency('cairo')
gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf'))
@ -86,6 +86,7 @@ client_protos_headers = []
client_protocols = [ client_protocols = [
[wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
[wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'],
['wlr-layer-shell-unstable-v1.xml'], ['wlr-layer-shell-unstable-v1.xml'],
['wlr-input-inhibitor-unstable-v1.xml'], ['wlr-input-inhibitor-unstable-v1.xml'],
] ]