mirror of
https://github.com/swaywm/sway.git
synced 2026-04-25 06:46:24 -04:00
Add support for screenlock protocol
This will always accept lock requests, including replacing a current locker if present. Based a prototype by: Manuel Stoeckl <code@mstoeckl.com>
This commit is contained in:
parent
30c28ff8f7
commit
2b2df8e3d8
8 changed files with 431 additions and 3 deletions
|
|
@ -15,6 +15,7 @@
|
||||||
#include <wlr/types/wlr_output_power_management_v1.h>
|
#include <wlr/types/wlr_output_power_management_v1.h>
|
||||||
#include <wlr/types/wlr_presentation_time.h>
|
#include <wlr/types/wlr_presentation_time.h>
|
||||||
#include <wlr/types/wlr_relative_pointer_v1.h>
|
#include <wlr/types/wlr_relative_pointer_v1.h>
|
||||||
|
#include <wlr/types/wlr_screenlocker_v1.h>
|
||||||
#include <wlr/types/wlr_server_decoration.h>
|
#include <wlr/types/wlr_server_decoration.h>
|
||||||
#include <wlr/types/wlr_text_input_v3.h>
|
#include <wlr/types/wlr_text_input_v3.h>
|
||||||
#include <wlr/types/wlr_xdg_shell.h>
|
#include <wlr/types/wlr_xdg_shell.h>
|
||||||
|
|
@ -85,6 +86,10 @@ struct sway_server {
|
||||||
struct wl_listener output_manager_apply;
|
struct wl_listener output_manager_apply;
|
||||||
struct wl_listener output_manager_test;
|
struct wl_listener output_manager_test;
|
||||||
|
|
||||||
|
struct wlr_screenlock_manager_v1 *screenlock;
|
||||||
|
struct wlr_texture *permalock_message;
|
||||||
|
struct wl_listener screenlock_set_mode;
|
||||||
|
|
||||||
struct wlr_output_power_manager_v1 *output_power_manager_v1;
|
struct wlr_output_power_manager_v1 *output_power_manager_v1;
|
||||||
struct wl_listener output_power_manager_set_mode;
|
struct wl_listener output_power_manager_set_mode;
|
||||||
struct wlr_input_method_manager_v2 *input_method;
|
struct wlr_input_method_manager_v2 *input_method;
|
||||||
|
|
@ -141,6 +146,7 @@ void handle_new_output(struct wl_listener *listener, void *data);
|
||||||
|
|
||||||
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
|
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
|
||||||
void handle_layer_shell_surface(struct wl_listener *listener, void *data);
|
void handle_layer_shell_surface(struct wl_listener *listener, void *data);
|
||||||
|
void handle_lock_set_mode(struct wl_listener *listener, void *data);
|
||||||
void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
|
void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
|
||||||
#if HAVE_XWAYLAND
|
#if HAVE_XWAYLAND
|
||||||
void handle_xwayland_surface(struct wl_listener *listener, void *data);
|
void handle_xwayland_surface(struct wl_listener *listener, void *data);
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ protocols = [
|
||||||
['idle.xml'],
|
['idle.xml'],
|
||||||
['wlr-input-inhibitor-unstable-v1.xml'],
|
['wlr-input-inhibitor-unstable-v1.xml'],
|
||||||
['wlr-output-power-management-unstable-v1.xml'],
|
['wlr-output-power-management-unstable-v1.xml'],
|
||||||
|
['wp-screenlocker-unstable-v1.xml'],
|
||||||
]
|
]
|
||||||
|
|
||||||
client_protocols = [
|
client_protocols = [
|
||||||
|
|
|
||||||
166
protocols/wp-screenlocker-unstable-v1.xml
Normal file
166
protocols/wp-screenlocker-unstable-v1.xml
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="zwp_screenlocker_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2021 Daniel De Graaf
|
||||||
|
|
||||||
|
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 (including the next
|
||||||
|
paragraph) 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="zwp_screenlocker_v1" version="1">
|
||||||
|
<description summary="Screen locking manager">
|
||||||
|
This interface provides notification of screen lock/unlock events,
|
||||||
|
displaying windows on a locked screen, and acting as a screenlocker.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy this object"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="locked">
|
||||||
|
<description summary="Triggered when the screen is locked">
|
||||||
|
This event will be sent on creation if the screen is currently locked,
|
||||||
|
and at the start of any lock action.
|
||||||
|
|
||||||
|
Note: windows on the unlocked desktop may still be visible (due to a
|
||||||
|
locking animation) even after this event is sent, so this event should
|
||||||
|
not be used to trigger post-lock actions such as a system sleep request.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="unlocked">
|
||||||
|
<description summary="Triggered when the screen is unlocked">
|
||||||
|
This event will be sent on creation if the screen is currently unlocked,
|
||||||
|
and at the end of any unlock action.
|
||||||
|
|
||||||
|
Note: windows on the unlocked desktop may become visible (due to an
|
||||||
|
unlocking animation) prior to this event being sent.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="lock">
|
||||||
|
<description summary="Request that this client become the screen locker">
|
||||||
|
Requesting a new lock handle will only succeed if this client has
|
||||||
|
permission to lock the screen. Compositors that handle screen locking
|
||||||
|
internally may choose to always reject this request. If an existing
|
||||||
|
client is acting as a screen locker, the compositor may choose to accept
|
||||||
|
or reject the new request.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_screenlocker_lock_v1"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="get_visibility">
|
||||||
|
<description summary="set the visibility of a surface on the lockscreen">
|
||||||
|
By default, no surfaces are visible on the locked desktop. Any surface
|
||||||
|
that should be visible on the locked desktop must set its visibility
|
||||||
|
using this visibility object.
|
||||||
|
|
||||||
|
This request is required for any toplevel surface displayed on the
|
||||||
|
locked desktop to ensure that sensitive information is not present on
|
||||||
|
the surface. The exact definition of sensitive may be defined by other
|
||||||
|
configuration, but might include notification details, keyboard
|
||||||
|
autocompletion, or configuration interfaces.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_screenlocker_visibility_v1"/>
|
||||||
|
<arg name="surface" type="object" interface="wl_surface"/>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_screenlocker_lock_v1" version="1">
|
||||||
|
<event name="rejected">
|
||||||
|
<description summary="The compositor has rejected the request">
|
||||||
|
This object is inert and should be destroyed.
|
||||||
|
|
||||||
|
If a compositor does not support external lockers, this event will always
|
||||||
|
be sent on the creation of a lock object.
|
||||||
|
</description>
|
||||||
|
<arg name="reason" type="string" allow-null="true" summary="reason for the rejection"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="locked">
|
||||||
|
<description summary="The lock request was accepted and the screen is locked">
|
||||||
|
The lock handle is active and only the locked desktop is visible on all
|
||||||
|
outputs. If a compositor implements a locking animation or similar
|
||||||
|
effect that results in both the locked and unlocked desktops being
|
||||||
|
visible, this event is sent after the effect completes.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="closed">
|
||||||
|
<description summary="This lock handle has been invalidated">
|
||||||
|
This object is inert and should be destroyed.
|
||||||
|
|
||||||
|
This will be sent if the compositor has unlocked the screen due to some
|
||||||
|
external event (for exmple, a dbus unlock message from logind), or if
|
||||||
|
another client has taken ownership of the lock.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="unlock">
|
||||||
|
<description summary="Unlock the screen">
|
||||||
|
Let the compositor know that it should unlock the screen.
|
||||||
|
|
||||||
|
It is valid to call this on a newly created lock handle without waiting
|
||||||
|
for an event; this will either cancel the lock or do nothing if the lock
|
||||||
|
handle is inert.
|
||||||
|
|
||||||
|
After this request has been sent by the client, this object will become
|
||||||
|
inert and should be destroyed.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy this object">
|
||||||
|
Destroying an active lock handle without first unlocking it will abandon
|
||||||
|
the lock. If a lock is abandoned, the compositor should take some
|
||||||
|
fallback action such as launching a new locker client in order to allow
|
||||||
|
the user to authenticate and unlock the session.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_screenlocker_visibility_v1" version="1">
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy this object">
|
||||||
|
Destroying this object will revert the surface to not be visible on the
|
||||||
|
lockscreen at the next commit.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<enum name="visibility">
|
||||||
|
<entry name="default" value="0" summary="Only visible when unlocked"/>
|
||||||
|
<entry name="lock_only" value="1" summary="Only visible when locked"/>
|
||||||
|
<entry name="both" value="2" summary="Visible regardless of lock state"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="set_visibility">
|
||||||
|
<description summary="set this surface visible on the lockscreen">
|
||||||
|
This value is double-buffered, see wl_surface.commit.
|
||||||
|
</description>
|
||||||
|
<arg name="visibility" type="uint" enum="zwp_screenlocker_visibility_v1.visibility"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="failed">
|
||||||
|
<description summary="the locked desktop cannot show this window">
|
||||||
|
This event is sent immediately if the associated window cannot be shown
|
||||||
|
on a locked desktop. This object is inert and should be destroyed.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
#include "sway/tree/root.h"
|
#include "sway/tree/root.h"
|
||||||
#include "sway/tree/view.h"
|
#include "sway/tree/view.h"
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
|
#include "wp-screenlocker-unstable-v1-protocol.h"
|
||||||
|
|
||||||
struct render_data {
|
struct render_data {
|
||||||
pixman_region32_t *damage;
|
pixman_region32_t *damage;
|
||||||
|
|
@ -143,6 +144,20 @@ static void render_surface_iterator(struct sway_output *output,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_screenlock_lock_surface *lock_surf;
|
||||||
|
uint32_t lock_mode = ZWP_SCREENLOCKER_VISIBILITY_V1_VISIBILITY_DEFAULT;
|
||||||
|
wl_list_for_each(lock_surf, &server.screenlock->lock_surfaces, link) {
|
||||||
|
if (surface == lock_surf->surface) {
|
||||||
|
lock_mode = lock_surf->current_mode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lock_mode == ZWP_SCREENLOCKER_VISIBILITY_V1_VISIBILITY_DEFAULT && server.screenlock->locked) {
|
||||||
|
return;
|
||||||
|
} else if (lock_mode == ZWP_SCREENLOCKER_VISIBILITY_V1_VISIBILITY_LOCK_ONLY && !server.screenlock->locked) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
struct wlr_fbox src_box;
|
struct wlr_fbox src_box;
|
||||||
wlr_surface_get_buffer_source_box(surface, &src_box);
|
wlr_surface_get_buffer_source_box(surface, &src_box);
|
||||||
|
|
||||||
|
|
@ -1048,6 +1063,39 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1});
|
wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (server.screenlock->locked) {
|
||||||
|
// repaint the background, to hide old data
|
||||||
|
float clear_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||||
|
if (!server.screenlock->lock_resource) {
|
||||||
|
// abandoned lock -> red BG
|
||||||
|
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.screenlock->lock_resource) {
|
||||||
|
// abandoned lock, show error message
|
||||||
|
wlr_renderer_scissor(renderer, NULL);
|
||||||
|
|
||||||
|
float matrix[9];
|
||||||
|
wlr_matrix_identity(matrix);
|
||||||
|
float x_expand = output->width / (float)server.permalock_message->width;
|
||||||
|
float y_expand = output->height / (float)server.permalock_message->height;
|
||||||
|
float expand = fmin(1.0, x_expand > y_expand ? y_expand : x_expand);
|
||||||
|
|
||||||
|
wlr_matrix_scale(matrix, expand, expand);
|
||||||
|
int x = output->width / 2 / expand - server.permalock_message->width / 2;
|
||||||
|
int y = output->height / 2 / expand - server.permalock_message->height / 2;
|
||||||
|
|
||||||
|
wlr_render_texture(renderer, server.permalock_message, matrix, x, y, 1.0);
|
||||||
|
|
||||||
|
goto render_overlay;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (output_has_opaque_overlay_layer_surface(output)) {
|
if (output_has_opaque_overlay_layer_surface(output)) {
|
||||||
goto render_overlay;
|
goto render_overlay;
|
||||||
}
|
}
|
||||||
|
|
@ -1099,11 +1147,13 @@ void output_render(struct sway_output *output, struct timespec *when,
|
||||||
render_layer_toplevel(output, damage,
|
render_layer_toplevel(output, damage,
|
||||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
|
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
|
||||||
|
|
||||||
|
if (!server.screenlock->locked) {
|
||||||
render_workspace(output, damage, workspace, workspace->current.focused);
|
render_workspace(output, damage, workspace, workspace->current.focused);
|
||||||
render_floating(output, damage);
|
render_floating(output, damage);
|
||||||
#if HAVE_XWAYLAND
|
#if HAVE_XWAYLAND
|
||||||
render_unmanaged(output, damage, &root->xwayland_unmanaged);
|
render_unmanaged(output, damage, &root->xwayland_unmanaged);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
render_layer_toplevel(output, damage,
|
render_layer_toplevel(output, damage,
|
||||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
|
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -290,6 +290,11 @@ static void handle_inhibit_deactivate(struct wl_listener *listener, void *data)
|
||||||
listener, input_manager, inhibit_deactivate);
|
listener, input_manager, inhibit_deactivate);
|
||||||
struct sway_seat *seat;
|
struct sway_seat *seat;
|
||||||
wl_list_for_each(seat, &input_manager->seats, link) {
|
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);
|
seat_set_exclusive_client(seat, NULL);
|
||||||
struct sway_node *previous = seat_get_focus(seat);
|
struct sway_node *previous = seat_get_focus(seat);
|
||||||
if (previous) {
|
if (previous) {
|
||||||
|
|
|
||||||
194
sway/lock.c
Normal file
194
sway/lock.c
Normal file
|
|
@ -0,0 +1,194 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
#include <drm_fourcc.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wlr/types/wlr_output_damage.h>
|
||||||
|
#include "cairo_util.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "pango.h"
|
||||||
|
#include "sway/input/seat.h"
|
||||||
|
#include "sway/config.h"
|
||||||
|
#include "sway/commands.h"
|
||||||
|
#include "sway/output.h"
|
||||||
|
#include "sway/server.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define PERMALOCK_CLIENT (struct wl_client *)(-1)
|
||||||
|
|
||||||
|
static struct wlr_texture *draw_permalock_message(void) {
|
||||||
|
sway_log(SWAY_DEBUG, "CREATING PERMALOCK MESSAGE");
|
||||||
|
struct sway_output *output = root->outputs->items[0];
|
||||||
|
|
||||||
|
int scale = output->wlr_output->scale;
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
|
||||||
|
const char* permalock_msg = "Lock screen crashed. Start a new lockscreen to unlock.";
|
||||||
|
|
||||||
|
// 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, 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, 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 lock_finished_delay;
|
||||||
|
struct lock_finished_item {
|
||||||
|
struct wl_listener listener;
|
||||||
|
struct lock_finished_delay *delay;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct lock_finished_delay {
|
||||||
|
struct wl_listener canceller;
|
||||||
|
int nr_outputs;
|
||||||
|
int nr_pending;
|
||||||
|
struct lock_finished_item items[0];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void lock_finished_cleanup(struct lock_finished_delay *delay) {
|
||||||
|
for (int i = 0; i < delay->nr_outputs; ++i) {
|
||||||
|
if (delay->items[i].listener.notify) {
|
||||||
|
wl_list_remove(&delay->items[i].listener.link);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wl_list_remove(&delay->canceller.link);
|
||||||
|
free(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lock_finished_frame(struct wl_listener *listener, void *data) {
|
||||||
|
struct lock_finished_item *item = wl_container_of(listener, item, listener);
|
||||||
|
struct lock_finished_delay *delay = item->delay;
|
||||||
|
wl_list_remove(&listener->link);
|
||||||
|
listener->notify = NULL;
|
||||||
|
delay->nr_pending--;
|
||||||
|
if (delay->nr_pending == 0) {
|
||||||
|
wlr_screenlock_send_lock_finished(server.screenlock);
|
||||||
|
lock_finished_cleanup(delay);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lock_finished_abort(struct wl_listener *listener, void *data) {
|
||||||
|
struct wlr_screenlock_change *signal = data;
|
||||||
|
if (signal->how == WLR_SCREENLOCK_MODE_CHANGE_UNLOCK) {
|
||||||
|
struct lock_finished_delay *delay = wl_container_of(listener, delay, canceller);
|
||||||
|
lock_finished_cleanup(delay);
|
||||||
|
}
|
||||||
|
// any other 'how' means we should continue
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_lock_set_mode(struct wl_listener *listener, void *data)
|
||||||
|
{
|
||||||
|
struct wlr_screenlock_change *signal = data;
|
||||||
|
struct wl_client *client = signal->new_client;
|
||||||
|
struct sway_seat *seat;
|
||||||
|
int nr_outputs = root->outputs->length;
|
||||||
|
|
||||||
|
switch (signal->how) {
|
||||||
|
case WLR_SCREENLOCK_MODE_CHANGE_LOCK:
|
||||||
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
|
seat_set_exclusive_client(seat, client);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delay lock_finished until the frame is displayed on all enabled displays
|
||||||
|
struct lock_finished_delay *delay = calloc(1, sizeof(*delay) + nr_outputs * sizeof(delay->items[0]));
|
||||||
|
delay->nr_outputs = nr_outputs;
|
||||||
|
|
||||||
|
for (int i = 0; i < nr_outputs; ++i) {
|
||||||
|
struct sway_output *output = root->outputs->items[i];
|
||||||
|
if (output && output->enabled && output->wlr_output && output->damage) {
|
||||||
|
wl_signal_add(&output->damage->events.frame, &delay->items[i].listener);
|
||||||
|
delay->items[i].listener.notify = lock_finished_frame;
|
||||||
|
delay->items[i].delay = delay;
|
||||||
|
delay->nr_pending++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delay->nr_pending) {
|
||||||
|
wl_signal_add(&server.screenlock->events.change_request,
|
||||||
|
&delay->canceller);
|
||||||
|
delay->canceller.notify = lock_finished_abort;
|
||||||
|
} else {
|
||||||
|
wlr_screenlock_send_lock_finished(server.screenlock);
|
||||||
|
free(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLR_SCREENLOCK_MODE_CHANGE_REPLACE:
|
||||||
|
case WLR_SCREENLOCK_MODE_CHANGE_RESPAWN:
|
||||||
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
|
seat_set_exclusive_client(seat, client);
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_screenlock_send_lock_finished(server.screenlock);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLR_SCREENLOCK_MODE_CHANGE_UNLOCK:
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No animation, send finished now
|
||||||
|
wlr_screenlock_send_unlock_finished(server.screenlock);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case WLR_SCREENLOCK_MODE_CHANGE_ABANDON:
|
||||||
|
sway_log(SWAY_ERROR, "Lockscreen client died, showing fallback message");
|
||||||
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
|
seat_set_exclusive_client(seat, PERMALOCK_CLIENT);
|
||||||
|
}
|
||||||
|
if (!server.permalock_message) {
|
||||||
|
server.permalock_message = draw_permalock_message();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// redraw everything
|
||||||
|
for (int i = 0; i < root->outputs->length; ++i) {
|
||||||
|
struct sway_output *output = root->outputs->items[i];
|
||||||
|
output_damage_whole(output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ sway_sources = files(
|
||||||
'decoration.c',
|
'decoration.c',
|
||||||
'ipc-json.c',
|
'ipc-json.c',
|
||||||
'ipc-server.c',
|
'ipc-server.c',
|
||||||
|
'lock.c',
|
||||||
'main.c',
|
'main.c',
|
||||||
'server.c',
|
'server.c',
|
||||||
'swaynag.c',
|
'swaynag.c',
|
||||||
|
|
|
||||||
|
|
@ -162,6 +162,11 @@ bool server_init(struct sway_server *server) {
|
||||||
server->foreign_toplevel_manager =
|
server->foreign_toplevel_manager =
|
||||||
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
|
||||||
|
|
||||||
|
server->screenlock = wlr_screenlock_manager_v1_create(server->wl_display);
|
||||||
|
server->screenlock_set_mode.notify = handle_lock_set_mode;
|
||||||
|
wl_signal_add(&server->screenlock->events.change_request,
|
||||||
|
&server->screenlock_set_mode);
|
||||||
|
|
||||||
server->drm_lease_manager=
|
server->drm_lease_manager=
|
||||||
wlr_drm_lease_v1_manager_create(server->wl_display, server->backend);
|
wlr_drm_lease_v1_manager_create(server->wl_display, server->backend);
|
||||||
if (server->drm_lease_manager) {
|
if (server->drm_lease_manager) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue