From 8bb8e7a2b1d2f572798c030cfab294ae733dd094 Mon Sep 17 00:00:00 2001 From: Manuel Stoeckl Date: Mon, 7 Jun 2021 20:49:33 -0400 Subject: [PATCH] example lockscreen protocol implementation --- config.in | 18 ++- include/sway/commands.h | 1 + include/sway/lock.h | 29 ++++ include/sway/output.h | 2 + include/sway/security.h | 10 ++ include/sway/server.h | 3 + protocols/ext-unlocker-v1.xml | 47 ++++++ protocols/meson.build | 1 + sway/commands.c | 1 + sway/commands/lock_screen.c | 49 +++++++ sway/desktop/render.c | 47 ++++++ sway/input/input-manager.c | 5 + sway/lock.c | 262 ++++++++++++++++++++++++++++++++++ sway/meson.build | 3 + sway/security.c | 16 +++ sway/server.c | 6 + sway/tree/output.c | 3 + 17 files changed, 501 insertions(+), 2 deletions(-) create mode 100644 include/sway/lock.h create mode 100644 include/sway/security.h create mode 100644 protocols/ext-unlocker-v1.xml create mode 100644 sway/commands/lock_screen.c create mode 100644 sway/lock.c create mode 100644 sway/security.c diff --git a/config.in b/config.in index 8031523ecd..c7fe6eeed6 100644 --- a/config.in +++ b/config.in @@ -20,6 +20,8 @@ set $term foot # on the original workspace that the command was run on. set $menu dmenu_path | dmenu | xargs swaymsg exec -- +set $lock swaylock -f -c 000000 + ### Output configuration # # Default wallpaper (more resolutions are available in @datadir@/backgrounds/sway/) @@ -36,9 +38,9 @@ output * bg @datadir@/backgrounds/sway/Sway_Wallpaper_Blue_1920x1080.png fill # Example configuration: # # exec swayidle -w \ -# timeout 300 'swaylock -f -c 000000' \ +# timeout 300 'swaymsg -- lock_screen $lock' \ # timeout 600 'swaymsg "output * dpms off"' resume 'swaymsg "output * dpms on"' \ -# before-sleep 'swaylock -f -c 000000' +# before-sleep 'swaymsg -- lock_screen $lock' # # This will lock your screen after 300 seconds of inactivity, then turn off # your displays after another 300 seconds, and turn your screens back on when @@ -214,4 +216,16 @@ bar { } } +# +# Lock screen. +# +bindsym $mod+Shift+L lock_screen --fail-unlocked $lock + +# For additional security, you can configure sway to deny access if +# the lock screen crashes. You may (depending on what caused the crash) +# be able to recover from this by running the lock screen again. +# +# bindsym --locked $mod+Shift+L lock_screen --fail-locked $lock + + include @sysconfdir@/sway/config.d/* diff --git a/include/sway/commands.h b/include/sway/commands.h index 29a6bec3f2..de19020e02 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -143,6 +143,7 @@ sway_cmd cmd_hide_edge_borders; sway_cmd cmd_include; sway_cmd cmd_inhibit_idle; sway_cmd cmd_input; +sway_cmd cmd_lock_screen; sway_cmd cmd_seat; sway_cmd cmd_ipc; sway_cmd cmd_kill; diff --git a/include/sway/lock.h b/include/sway/lock.h new file mode 100644 index 0000000000..28cbbd3659 --- /dev/null +++ b/include/sway/lock.h @@ -0,0 +1,29 @@ +#ifndef _SWAY_LOCK_H +#define _SWAY_LOCK_H + +#include + +#define PERMALOCK_CLIENT (struct wl_client *)(-1) + +struct sway_lock_state { + // true -> if lock screen crashes, unrecoverable + bool fail_locked; + // if this is not NULL, screen is locked. If the lock screen crashed, + // this may be set to PERMALOCK_CLIENT . + struct wl_client *client; + struct wl_listener client_destroy; + + struct wlr_texture *permalock_message; + struct wl_global *ext_unlocker_v1_global; +}; + +// todo: need destroy +void sway_lock_state_create(struct sway_lock_state *state, + struct wl_display *display); +struct cmd_results *run_lockscreen_cmd(const char *cmd, bool fail_locked); + +struct sway_output; +/** Create a texture which briefly explains the permalock state. */ +struct wlr_texture *draw_permalock_message(struct sway_output *output); + +#endif /* _SWAY_LOCK_H */ diff --git a/include/sway/output.h b/include/sway/output.h index 0ebcc77da2..680bacc6a5 100644 --- a/include/sway/output.h +++ b/include/sway/output.h @@ -56,6 +56,8 @@ struct sway_output { uint32_t refresh_nsec; int max_render_time; // In milliseconds struct wl_event_source *repaint_timer; + + struct wlr_texture *permalock_message; }; struct sway_output *output_create(struct wlr_output *wlr_output); diff --git a/include/sway/security.h b/include/sway/security.h new file mode 100644 index 0000000000..ad32bd3e97 --- /dev/null +++ b/include/sway/security.h @@ -0,0 +1,10 @@ +#ifndef _SWAY_SECURITY_H +#define _SWAY_SECURITY_H + +#include +#include + +bool security_global_filter(const struct wl_client *client, + const struct wl_global *global, void *data); + +#endif /* _SWAY_SECURITY_H */ diff --git a/include/sway/server.h b/include/sway/server.h index 3a5670d928..2c71464366 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -2,6 +2,7 @@ #define _SWAY_SERVER_H #include #include +#include #include #include #include @@ -90,6 +91,8 @@ struct sway_server { struct wlr_xdg_activation_v1 *xdg_activation_v1; struct wl_listener xdg_activation_v1_request_activate; + struct sway_lock_state lock_screen; + // The timeout for transactions, after which a transaction is applied // regardless of readiness. size_t txn_timeout_ms; diff --git a/protocols/ext-unlocker-v1.xml b/protocols/ext-unlocker-v1.xml new file mode 100644 index 0000000000..5e6cc647b8 --- /dev/null +++ b/protocols/ext-unlocker-v1.xml @@ -0,0 +1,47 @@ + + + + Copyright 2021 Manuel Stoeckl + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + + + + + This protocol provides an interface for letting a special lock screen + client, which was created when the session was locked, communicate to + the compositor that the session should be unlocked. + + + + + Announce that this object will no longer be used. + + + + + + Let the compositor know that it should unlock the screen. + + After this request has been sent by the client, sending it again shall + have no effect. + + + + diff --git a/protocols/meson.build b/protocols/meson.build index 124e97777c..7858aaabe5 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -19,6 +19,7 @@ protocols = [ ['idle.xml'], ['wlr-input-inhibitor-unstable-v1.xml'], ['wlr-output-power-management-unstable-v1.xml'], + ['ext-unlocker-v1.xml'], ] client_protocols = [ diff --git a/sway/commands.c b/sway/commands.c index b09a04c71d..d33529eba5 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -73,6 +73,7 @@ static const struct cmd_handler handlers[] = { { "gaps", cmd_gaps }, { "hide_edge_borders", cmd_hide_edge_borders }, { "input", cmd_input }, + { "lock_screen", cmd_lock_screen}, { "mode", cmd_mode }, { "mouse_warping", cmd_mouse_warping }, { "new_float", cmd_new_float }, diff --git a/sway/commands/lock_screen.c b/sway/commands/lock_screen.c new file mode 100644 index 0000000000..c1c64a24c1 --- /dev/null +++ b/sway/commands/lock_screen.c @@ -0,0 +1,49 @@ +#define _POSIX_C_SOURCE 200809L +#include + +#include "log.h" +#include "util.h" +#include "stringop.h" +#include "sway/commands.h" +#include "sway/config.h" +#include "sway/server.h" +#include "sway/input/seat.h" +#include "sway/output.h" + +struct cmd_results *cmd_lock_screen(int argc, char **argv) { + struct cmd_results *error = NULL; + if ((error = cmd_exec_validate(argc, argv))) { + return error; + } + bool fail_locked; + if (strcmp(argv[0], "--fail-locked") == 0) { + fail_locked = true; + argv++; + argc--; + } else if (strcmp(argv[0], "--fail-unlocked") == 0) { + fail_locked = false; + argv++; + argc--; + } else { + return cmd_results_new(CMD_FAILURE, "must set either --fail-locked or --fail-unlocked"); + } + + char *cmd; + if (argc == 1 && (argv[0][0] == '\'' || argv[0][0] == '"')) { + cmd = strdup(argv[0]); + strip_quotes(cmd); + } else { + cmd = join_args(argv, argc); + } + + if (config->reloading) { + char *args = join_args(argv, argc); + sway_log(SWAY_DEBUG, "Ignoring 'cmd_lock_screen %s' due to reload", args); + free(args); + return cmd_results_new(CMD_SUCCESS, NULL); + } + + struct cmd_results *res = run_lockscreen_cmd(cmd, fail_locked); + free(cmd); + return res; +} diff --git a/sway/desktop/render.c b/sway/desktop/render.c index bf1b8666c7..8da0758b38 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c @@ -21,6 +21,7 @@ #include "sway/input/input-manager.h" #include "sway/input/seat.h" #include "sway/layers.h" +#include "sway/lock.h" #include "sway/output.h" #include "sway/server.h" #include "sway/tree/arrange.h" @@ -144,6 +145,11 @@ static void render_surface_iterator(struct sway_output *output, return; } + struct wl_client* client = wl_resource_get_client(surface->resource); + if (server.lock_screen.client && server.lock_screen.client != client) { + return; + } + struct wlr_fbox src_box; wlr_surface_get_buffer_source_box(surface, &src_box); @@ -1048,6 +1054,47 @@ void output_render(struct sway_output *output, struct timespec *when, pixman_region32_union_rect(damage, damage, 0, 0, width, height); } + if (server.lock_screen.client) { + /* assume lock screen client is overlay surface, etc */ + + // repaint the background, to hide old data + float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f}; + if (server.lock_screen.client == PERMALOCK_CLIENT) { + clear_color[0] = 1.f; + } + int nrects; + pixman_box32_t *rects = pixman_region32_rectangles(damage, &nrects); + for (int i = 0; i < nrects; ++i) { + scissor_output(wlr_output, &rects[i]); + wlr_renderer_clear(renderer, clear_color); + } + + if (server.lock_screen.client == PERMALOCK_CLIENT) { + if (!output->permalock_message) { + output->permalock_message = draw_permalock_message(output); + } + + wlr_renderer_scissor(renderer, NULL); + + if (output->permalock_message) { + float matrix[9]; + /* todo: rescale message to fit into screen */ + wlr_matrix_identity(matrix); + float x_expand = output->width / (float)output->permalock_message->width; + float y_expand = output->height / (float)output->permalock_message->height; + float expand = x_expand > y_expand ? y_expand : x_expand; + + wlr_matrix_scale(matrix, expand, expand); + int x = output->width / 2 / expand - output->permalock_message->width / 2; + int y = output->height / 2 / expand - output->permalock_message->height / 2; + + wlr_render_texture(renderer, output->permalock_message, matrix, x, y, 1.0); + } + } + + // then go to clear lock screen + goto render_overlay; + } if (output_has_opaque_overlay_layer_surface(output)) { goto render_overlay; } diff --git a/sway/input/input-manager.c b/sway/input/input-manager.c index f04a8ce09a..84893af5da 100644 --- a/sway/input/input-manager.c +++ b/sway/input/input-manager.c @@ -290,6 +290,11 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data) listener, input_manager, inhibit_deactivate); struct sway_seat *seat; wl_list_for_each(seat, &input_manager->seats, link) { + if (seat->exclusive_client != input_manager->inhibit->active_client) { + // the permalock screen can also set exclusive clients, + // so don't undo its work. + continue; + } seat_set_exclusive_client(seat, NULL); struct sway_node *previous = seat_get_focus(seat); if (previous) { diff --git a/sway/lock.c b/sway/lock.c new file mode 100644 index 0000000000..c4786805d1 --- /dev/null +++ b/sway/lock.c @@ -0,0 +1,262 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include "cairo_util.h" +#include "ext-unlocker-v1-protocol.h" +#include "log.h" +#include "pango.h" +#include "sway/input/seat.h" +#include "sway/config.h" +#include "sway/commands.h" +#include "sway/lock.h" +#include "sway/output.h" +#include "sway/server.h" +#include "util.h" + +static void handle_unlocker_unlock(struct wl_client *client, + struct wl_resource *resource) { + if (server.lock_screen.client != client) { + sway_log(SWAY_ERROR, "INVALID UNLOCK, IGNORING"); + return; + } + + // The lockscreen may now shut down on its own schedule + server.lock_screen.client = NULL; + wl_list_remove(&server.lock_screen.client_destroy.link); + wl_list_init(&server.lock_screen.client_destroy.link); + sway_log(SWAY_ERROR, "RECEIVED UNLOCK"); + + struct sway_seat *seat; + wl_list_for_each(seat, &server.input->seats, link) { + seat_set_exclusive_client(seat, NULL); + // copied from input_manager -- deduplicate? + struct sway_node *previous = seat_get_focus(seat); + if (previous) { + // Hack to get seat to re-focus the return value of get_focus + seat_set_focus(seat, NULL); + seat_set_focus(seat, previous); + } + } + + // redraw everything + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + output_damage_whole(output); + } +} + +static const struct ext_unlocker_v1_interface unlock_impl = { + .unlock = handle_unlocker_unlock, +}; + +static void screenlock_bind(struct wl_client *client, void *data, + uint32_t version, uint32_t id) { + if (client != server.lock_screen.client) { + sway_log(SWAY_ERROR, "WRONG LOCKSCREEN CLIENT"); + wl_client_post_implementation_error(client, "wrong client, todo filter globals"); + return; + } + struct wl_resource *resource = wl_resource_create(client, + &ext_unlocker_v1_interface, version, id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &unlock_impl, NULL, NULL); +} + + +static void handle_lockscreen_client_destroy(struct wl_listener *listener, void *data) { + struct wl_client *client = data; + if (server.lock_screen.client != client) { + // this was an earlier lock screen client that had already + // unlocked; ignore it. No ABA risk since lock_screen.client + // must be live. + sway_log(SWAY_ERROR, "AN OLD LOCKSCREEN CLIENT DIED"); + return; + } + + wl_list_remove(&server.lock_screen.client_destroy.link); + wl_list_init(&server.lock_screen.client_destroy.link); + + /* client closed, but did not unlock and reset the server.lock_screen_client */ + if (server.lock_screen.fail_locked) { + // TODO: implement 'unlock_screen' command which which to recover + // from permalocking; or make a repeated 'lock_screen' work? + // or force people to swaymsg -- lock_screen --fail-unlocked /bin/false ? + sway_log(SWAY_ERROR, "THE LOCKSCREEN CLIENT DIED, PERMALOCKING"); + server.lock_screen.client = PERMALOCK_CLIENT; + struct sway_seat *seat; + wl_list_for_each(seat, &server.input->seats, link) { + seat_set_exclusive_client(seat, PERMALOCK_CLIENT); + } + } else { + server.lock_screen.client = NULL; + + sway_log(SWAY_ERROR, "THE LOCKSCREEN CLIENT DIED, UNLOCKING"); + struct sway_seat *seat; + wl_list_for_each(seat, &server.input->seats, link) { + seat_set_exclusive_client(seat, NULL); + // copied from input_manager -- deduplicate? + struct sway_node *previous = seat_get_focus(seat); + if (previous) { + // Hack to get seat to re-focus the return value of get_focus + seat_set_focus(seat, NULL); + seat_set_focus(seat, previous); + } + } + } + + // redraw everything + for (int i = 0; i < root->outputs->length; ++i) { + struct sway_output *output = root->outputs->items[i]; + output_damage_whole(output); + } +} + +void sway_lock_state_create(struct sway_lock_state *state, + struct wl_display *display) { + state->ext_unlocker_v1_global = + wl_global_create(display, &ext_unlocker_v1_interface, + 1, NULL, screenlock_bind); +} + +struct wlr_texture *draw_permalock_message(struct sway_output *output) { + sway_log(SWAY_ERROR, "CREATING PERMALOCK MESSAGE"); + + int width = 0; + int height = 0; + + const char* permalock_msg = "Lock screen crashed. Can only unlock by running lock_screen again."; + + // We must use a non-nil cairo_t for cairo_set_font_options to work. + // Therefore, we cannot use cairo_create(NULL). + cairo_surface_t *dummy_surface = cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, 0, 0); + cairo_t *c = cairo_create(dummy_surface); + cairo_set_antialias(c, CAIRO_ANTIALIAS_BEST); + cairo_font_options_t *fo = cairo_font_options_create(); + cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_NONE); + cairo_set_font_options(c, fo); + get_text_size(c, config->font, &width, &height, NULL, output->wlr_output->scale, + config->pango_markup, "%s", permalock_msg); + cairo_surface_destroy(dummy_surface); + cairo_destroy(c); + + cairo_surface_t *surface = cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, width, height); + cairo_t *cairo = cairo_create(surface); + cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); + cairo_set_font_options(cairo, fo); + cairo_font_options_destroy(fo); + cairo_set_source_rgba(cairo, 1.0,1.0,1.0,0.0); + cairo_paint(cairo); + PangoContext *pango = pango_cairo_create_context(cairo); + cairo_set_source_rgba(cairo, 0.,0.,0.,1.0); + cairo_move_to(cairo, 0, 0); + + pango_printf(cairo, config->font, output->wlr_output->scale, config->pango_markup, + "%s", permalock_msg); + + cairo_surface_flush(surface); + unsigned char *data = cairo_image_surface_get_data(surface); + int stride = cairo_image_surface_get_stride(surface); + struct wlr_renderer *renderer = wlr_backend_get_renderer( + output->wlr_output->backend); + struct wlr_texture *tex = wlr_texture_from_pixels( + renderer, DRM_FORMAT_ARGB8888, stride, width, height, data); + cairo_surface_destroy(surface); + g_object_unref(pango); + cairo_destroy(cairo); + return tex; +} + + +struct cmd_results *run_lockscreen_cmd(const char *cmd, bool fail_locked) { + int sockets[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) { + sway_log_errno(SWAY_ERROR, "socketpair failed"); + return cmd_results_new(CMD_FAILURE, "socketpair failed"); + } + if (!sway_set_cloexec(sockets[0], true) || !sway_set_cloexec(sockets[1], true)) { + return cmd_results_new(CMD_FAILURE, "cloexec failed"); + } + + /* Replace any existing lock screen with the new one */ + if (server.lock_screen.client) { + if (server.lock_screen.client != PERMALOCK_CLIENT) { + wl_list_remove(&server.lock_screen.client_destroy.link); + wl_list_init(&server.lock_screen.client_destroy.link); + wl_client_destroy(server.lock_screen.client); + } + server.lock_screen.client = NULL; + } + + server.lock_screen.fail_locked = fail_locked; + + server.lock_screen.client = wl_client_create(server.wl_display, sockets[0]); + if (!server.lock_screen.client) { + sway_log_errno(SWAY_ERROR, "wl_client_create failed"); + if (!fail_locked) { + return cmd_results_new(CMD_FAILURE, "wl_client_create failed"); + } + server.lock_screen.client = PERMALOCK_CLIENT; + } else { + server.lock_screen.client_destroy.notify = handle_lockscreen_client_destroy; + wl_client_add_destroy_listener(server.lock_screen.client, + &server.lock_screen.client_destroy); + } + + // only lock screen gets input; this applies immediately, + // before the lock screen program is set up + struct sway_seat *seat; + wl_list_for_each(seat, &server.input->seats, link) { + seat_set_exclusive_client(seat, server.lock_screen.client); + } + + pid_t pid = fork(); + if (pid < 0) { + sway_log(SWAY_ERROR, "Failed to create fork for swaybar"); + return cmd_results_new(CMD_FAILURE, "fork failed"); + } else if (pid == 0) { + // Remove the SIGUSR1 handler that wlroots adds for xwayland + sigset_t set; + sigemptyset(&set); + sigprocmask(SIG_SETMASK, &set, NULL); + signal(SIGPIPE, SIG_DFL); + + pid = fork(); + if (pid < 0) { + sway_log_errno(SWAY_ERROR, "fork failed"); + _exit(EXIT_FAILURE); + } else if (pid == 0) { + if (!sway_set_cloexec(sockets[1], false)) { + _exit(EXIT_FAILURE); + } + + char wayland_socket_str[16]; + snprintf(wayland_socket_str, sizeof(wayland_socket_str), + "%d", sockets[1]); + setenv("WAYLAND_SOCKET", wayland_socket_str, true); + + execlp("sh", "sh", "-c", cmd, (void *)NULL); + _exit(EXIT_FAILURE); + } + _exit(EXIT_SUCCESS); + } + + if (close(sockets[1]) != 0) { + sway_log_errno(SWAY_ERROR, "close failed"); + return cmd_results_new(CMD_FAILURE, "close failed"); + } + + if (waitpid(pid, NULL, 0) < 0) { + sway_log_errno(SWAY_ERROR, "waitpid failed"); + return cmd_results_new(CMD_FAILURE, "waitpid failed"); + } + sway_log(SWAY_ERROR, "LOCKSCREEN CLIENT STARTED"); + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/meson.build b/sway/meson.build index 1402db1542..5a03051f0f 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -5,7 +5,9 @@ sway_sources = files( 'decoration.c', 'ipc-json.c', 'ipc-server.c', + 'lock.c', 'main.c', + 'security.c', 'server.c', 'swaynag.c', 'xdg_activation_v1.c', @@ -67,6 +69,7 @@ sway_sources = files( 'commands/gaps.c', 'commands/hide_edge_borders.c', 'commands/inhibit_idle.c', + 'commands/lock_screen.c', 'commands/kill.c', 'commands/mark.c', 'commands/max_render_time.c', diff --git a/sway/security.c b/sway/security.c new file mode 100644 index 0000000000..2ee60539df --- /dev/null +++ b/sway/security.c @@ -0,0 +1,16 @@ +#include "sway/security.h" +#include "sway/server.h" + +bool security_global_filter(const struct wl_client *client, + const struct wl_global *global, void *data) { + struct sway_server *server = data; + if (global == server->lock_screen.ext_unlocker_v1_global + && client != server->lock_screen.client) { + // do not provide the unlocker global to non-lockscreen + // clients. Note: a client that _used_ to be the lock screen + // will not be sent this global again, but may still have + // access to it from before. + return false; + } + return true; +} diff --git a/sway/server.c b/sway/server.c index 2e5ab10453..6ab6d1396b 100644 --- a/sway/server.c +++ b/sway/server.c @@ -38,12 +38,14 @@ #include "sway/desktop/idle_inhibit_v1.h" #include "sway/input/input-manager.h" #include "sway/output.h" +#include "sway/security.h" #include "sway/server.h" #include "sway/tree/root.h" #if HAVE_XWAYLAND #include "sway/xwayland.h" #endif + bool server_privileged_prepare(struct sway_server *server) { sway_log(SWAY_DEBUG, "Preparing Wayland server initialization"); server->wl_display = wl_display_create(); @@ -166,6 +168,10 @@ bool server_init(struct sway_server *server) { wl_signal_add(&server->xdg_activation_v1->events.request_activate, &server->xdg_activation_v1_request_activate); + sway_lock_state_create(&server->lock_screen, server->wl_display); + + wl_display_set_global_filter(server->wl_display, security_global_filter, server); + // Avoid using "wayland-0" as display socket char name_candidate[16]; for (int i = 1; i <= 32; ++i) { diff --git a/sway/tree/output.c b/sway/tree/output.c index c095dce06e..0f57a4e66f 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c @@ -241,6 +241,9 @@ void output_destroy(struct sway_output *output) { list_free(output->workspaces); list_free(output->current.workspaces); wl_event_source_remove(output->repaint_timer); + if (output->permalock_message) { + wlr_texture_destroy(output->permalock_message); + } free(output); }