mirror of
https://github.com/swaywm/sway.git
synced 2026-04-23 06:46:27 -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_presentation_time.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_text_input_v3.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_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 wl_listener output_power_manager_set_mode;
|
||||
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_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);
|
||||
#if HAVE_XWAYLAND
|
||||
void handle_xwayland_surface(struct wl_listener *listener, void *data);
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ protocols = [
|
|||
['idle.xml'],
|
||||
['wlr-input-inhibitor-unstable-v1.xml'],
|
||||
['wlr-output-power-management-unstable-v1.xml'],
|
||||
['wp-screenlocker-unstable-v1.xml'],
|
||||
]
|
||||
|
||||
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/view.h"
|
||||
#include "sway/tree/workspace.h"
|
||||
#include "wp-screenlocker-unstable-v1-protocol.h"
|
||||
|
||||
struct render_data {
|
||||
pixman_region32_t *damage;
|
||||
|
|
@ -143,6 +144,20 @@ static void render_surface_iterator(struct sway_output *output,
|
|||
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;
|
||||
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});
|
||||
}
|
||||
|
||||
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)) {
|
||||
goto render_overlay;
|
||||
}
|
||||
|
|
@ -1099,11 +1147,13 @@ void output_render(struct sway_output *output, struct timespec *when,
|
|||
render_layer_toplevel(output, damage,
|
||||
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM]);
|
||||
|
||||
render_workspace(output, damage, workspace, workspace->current.focused);
|
||||
render_floating(output, damage);
|
||||
if (!server.screenlock->locked) {
|
||||
render_workspace(output, damage, workspace, workspace->current.focused);
|
||||
render_floating(output, damage);
|
||||
#if HAVE_XWAYLAND
|
||||
render_unmanaged(output, damage, &root->xwayland_unmanaged);
|
||||
render_unmanaged(output, damage, &root->xwayland_unmanaged);
|
||||
#endif
|
||||
}
|
||||
render_layer_toplevel(output, damage,
|
||||
&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);
|
||||
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) {
|
||||
|
|
|
|||
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',
|
||||
'ipc-json.c',
|
||||
'ipc-server.c',
|
||||
'lock.c',
|
||||
'main.c',
|
||||
'server.c',
|
||||
'swaynag.c',
|
||||
|
|
|
|||
|
|
@ -162,6 +162,11 @@ bool server_init(struct sway_server *server) {
|
|||
server->foreign_toplevel_manager =
|
||||
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=
|
||||
wlr_drm_lease_v1_manager_create(server->wl_display, server->backend);
|
||||
if (server->drm_lease_manager) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue