Skip to content

Commit

Permalink
example lockscreen protocol implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mstoeckl committed Jun 12, 2021
1 parent 3bf9919 commit 8bb8e7a
Show file tree
Hide file tree
Showing 17 changed files with 501 additions and 2 deletions.
18 changes: 16 additions & 2 deletions config.in
Original file line number Diff line number Diff line change
Expand Up @@ -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/)
Expand All @@ -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
Expand Down Expand Up @@ -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/*
1 change: 1 addition & 0 deletions include/sway/commands.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
29 changes: 29 additions & 0 deletions include/sway/lock.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#ifndef _SWAY_LOCK_H
#define _SWAY_LOCK_H

#include <wlr/types/wlr_buffer.h>

#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 */
2 changes: 2 additions & 0 deletions include/sway/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 10 additions & 0 deletions include/sway/security.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#ifndef _SWAY_SECURITY_H
#define _SWAY_SECURITY_H

#include <stdbool.h>
#include <wayland-server-core.h>

bool security_global_filter(const struct wl_client *client,
const struct wl_global *global, void *data);

#endif /* _SWAY_SECURITY_H */
3 changes: 3 additions & 0 deletions include/sway/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define _SWAY_SERVER_H
#include <stdbool.h>
#include <wayland-server-core.h>
#include <sway/lock.h>
#include <wlr/backend.h>
#include <wlr/backend/session.h>
#include <wlr/render/wlr_renderer.h>
Expand Down Expand Up @@ -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;
Expand Down
47 changes: 47 additions & 0 deletions protocols/ext-unlocker-v1.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="ext_unlocker_v1">
<copyright>
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.
</copyright>

<interface name="ext_unlocker_v1" version="1">
<description summary="protocol for a session (un)locker">
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.
</description>

<request name="destroy" type="destructor">
<description summary="destroy ext_unlocker_v1 object">
Announce that this object will no longer be used.
</description>
</request>

<request name="unlock">
<description summary="unlock screen">
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.
</description>
</request>
</interface>
</protocol>
1 change: 1 addition & 0 deletions protocols/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
1 change: 1 addition & 0 deletions sway/commands.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
49 changes: 49 additions & 0 deletions sway/commands/lock_screen.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#define _POSIX_C_SOURCE 200809L
#include <string.h>

#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;
}
47 changes: 47 additions & 0 deletions sway/desktop/render.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
}
Expand Down
5 changes: 5 additions & 0 deletions sway/input/input-manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Loading

0 comments on commit 8bb8e7a

Please sign in to comment.