Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: add ability for clients to be shown over the lock screen #8461

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/sway/layers.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ struct sway_layer_surface {
struct wl_listener node_destroy;
struct wl_listener new_popup;

bool show_over_lockscreen;
bool mapped;

struct wlr_scene_tree *popups;
Expand Down
4 changes: 4 additions & 0 deletions include/sway/lockscreen-overlay.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#include <wayland-server-core.h>

struct sway_lockscreen_overlay;
struct sway_lockscreen_overlay *sway_lockscreen_overlay_create(struct wl_display *display);
2 changes: 2 additions & 0 deletions include/sway/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ struct sway_server {
struct wl_listener manager_destroy;
} session_lock;

struct sway_lockscreen_overlay *lockscreen_overlay;

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;
Expand Down
38 changes: 38 additions & 0 deletions protocols/kde-lockscreen-overlay-v1.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="kde_lockscreen_overlay_v1">
<copyright><![CDATA[
SPDX-FileCopyrightText: 2022 Aleix Pol Gonzalez <[email protected]>

SPDX-License-Identifier: LGPL-2.1-or-later
]]></copyright>

<interface name="kde_lockscreen_overlay_v1" version="1">
<description summary="Allow surfaces over the lockscreen">
Allows a client to request a surface to be visible when the system is locked.

This is meant to be used for specific high urgency cases like phone calls or alarms.

Warning! The protocol described in this file is a desktop environment
implementation detail. Regular clients must not use this protocol.
Backward incompatible changes may be added without bumping the major
version of the extension.
</description>

<enum name="error">
<entry name="invalid_surface_state" value="0" summary="the client provided an invalid surface state"/>
</enum>

<request name="allow">
<description summary="Tell about which surface could be raised above the lockscreen">
Informs the compositor that the surface could be shown when the screen is locked. This request should be called while the surface is unmapped.
</description>
<arg name="surface" type="object" interface="wl_surface"/>
</request>

<request name="destroy" type="destructor">
<description summary="Destroy the kde_lockscreen_overlay_v1">
This won't affect the surface previously marked with the allow request.
</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 @@ -18,6 +18,7 @@ protocols = [
'wlr-layer-shell-unstable-v1.xml',
'idle.xml',
'wlr-output-power-management-unstable-v1.xml',
'kde-lockscreen-overlay-v1.xml',
]

wl_protos_src = []
Expand Down
37 changes: 28 additions & 9 deletions sway/desktop/layer_shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,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 @@ -54,7 +55,7 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
}

static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area,
struct wlr_box *usable_area, struct wlr_scene_tree *tree, bool exclusive) {
struct wlr_box *usable_area, struct wlr_scene_tree *tree, bool exclusive, bool locked) {
struct wlr_scene_node *node;
wl_list_for_each(node, &tree->children, link) {
struct sway_layer_surface *surface = scene_descriptor_try_get(node,
Expand All @@ -64,6 +65,17 @@ static void arrange_surface(struct sway_output *output, const struct wlr_box *fu
continue;
}

if (!surface->show_over_lockscreen) {
wlr_scene_node_set_enabled(node, !locked);
/* wlr_scene_node_set_enabled(node, true); */
if (locked) {
continue;
}
} else {
// TODO: not sure why this is required
wlr_scene_node_set_enabled(node, true);
}

if (!surface->scene->layer_surface->initialized) {
continue;
}
Expand All @@ -82,19 +94,26 @@ void arrange_layers(struct sway_output *output) {
&usable_area.width, &usable_area.height);
const struct wlr_box full_area = usable_area;

arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, true);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, true);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, true);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, true);
bool locked = server.session_lock.lock;

if (locked) {
sway_log(SWAY_INFO, "arranging locked layout");
}

arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, true, locked);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, true, locked);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, true, locked);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, true, locked);

arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, false);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, false);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, false);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, false);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, false, locked);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, false, locked);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, false, locked);
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, false, locked);

if (!wlr_box_equal(&usable_area, &output->usable_area)) {
sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
output->usable_area = usable_area;
arrange_locks();
arrange_output(output);
} else {
arrange_popups(root->layers.popup);
Expand Down
15 changes: 12 additions & 3 deletions sway/desktop/transaction.c
Original file line number Diff line number Diff line change
Expand Up @@ -623,13 +623,22 @@ void arrange_popups(struct wlr_scene_tree *popups) {

static void arrange_root(struct sway_root *root) {
struct sway_container *fs = root->fullscreen_global;
bool locked = server.session_lock.lock;

wlr_scene_node_set_enabled(&root->layers.shell_background->node, !fs);
wlr_scene_node_set_enabled(&root->layers.shell_bottom->node, !fs);
wlr_scene_node_set_enabled(&root->layers.tiling->node, !fs);
wlr_scene_node_set_enabled(&root->layers.floating->node, !fs);
wlr_scene_node_set_enabled(&root->layers.tiling->node, !fs && !locked);
wlr_scene_node_set_enabled(&root->layers.floating->node, !fs && !locked);
wlr_scene_node_set_enabled(&root->layers.shell_top->node, !fs);
wlr_scene_node_set_enabled(&root->layers.fullscreen->node, !fs);
wlr_scene_node_set_enabled(&root->layers.fullscreen->node, !fs && !locked);
wlr_scene_node_set_enabled(&root->layers.fullscreen_global->node, !locked);
#if WLR_HAS_XWAYLAND
wlr_scene_node_set_enabled(&root->layers.unmanaged->node, !locked);
#endif

if (server.session_lock.lock) {
sway_log(SWAY_INFO, "arranging locked layout");
}

// hide all contents in the scratchpad
for (int i = 0; i < root->scratchpad->length; i++) {
Expand Down
15 changes: 14 additions & 1 deletion sway/input/seat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1068,7 +1068,20 @@ void seat_configure_xcursor(struct sway_seat *seat) {
bool seat_is_input_allowed(struct sway_seat *seat,
struct wlr_surface *surface) {
if (server.session_lock.lock) {
return sway_session_lock_has_surface(server.session_lock.lock, surface);
if (sway_session_lock_has_surface(server.session_lock.lock, surface)) {
return true;
}

struct wlr_layer_surface_v1 *layer_surface =
wlr_layer_surface_v1_try_from_wlr_surface(surface);
struct sway_layer_surface *layer =
layer_surface ? layer_surface->data : NULL;

if (layer && layer->show_over_lockscreen) {
return true;
}

return false;
}
return true;
}
Expand Down
24 changes: 19 additions & 5 deletions sway/lock.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
#include "log.h"
#include "sway/input/cursor.h"
#include "sway/input/keyboard.h"
#include "sway/desktop/transaction.h"
#include "sway/input/seat.h"
#include "sway/layers.h"
#include "sway/output.h"
#include "sway/server.h"
#include "sway/tree/arrange.h"
#include "sway/lock.h"

struct sway_session_lock_output {
Expand Down Expand Up @@ -79,13 +81,13 @@ static void handle_surface_destroy(struct wl_listener *listener, void *data) {
}

static void lock_output_reconfigure(struct sway_session_lock_output *output) {
int width = output->output->width;
int height = output->output->height;
struct wlr_box usable_area = output->output->usable_area;

wlr_scene_rect_set_size(output->background, width, height);
wlr_scene_node_set_position(&output->tree->node, usable_area.x, usable_area.y);
wlr_scene_rect_set_size(output->background, usable_area.width, usable_area.height);

if (output->surface) {
wlr_session_lock_surface_v1_configure(output->surface, width, height);
wlr_session_lock_surface_v1_configure(output->surface, usable_area.width, usable_area.height);
}
}

Expand Down Expand Up @@ -234,6 +236,9 @@ static void handle_unlock(struct wl_listener *listener, void *data) {
struct sway_output *output = root->outputs->items[i];
arrange_layers(output);
}

arrange_root();
transaction_commit_dirty();
}

static void handle_abandon(struct wl_listener *listener, void *data) {
Expand Down Expand Up @@ -295,8 +300,17 @@ static void handle_session_lock(struct wl_listener *listener, void *data) {
sway_lock->destroy.notify = handle_abandon;
wl_signal_add(&lock->events.destroy, &sway_lock->destroy);

wlr_session_lock_v1_send_locked(lock);
server.session_lock.lock = sway_lock;

for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
arrange_layers(output);
}

arrange_root();
transaction_commit_dirty();

wlr_session_lock_v1_send_locked(lock);
}

static void handle_session_lock_destroy(struct wl_listener *listener, void *data) {
Expand Down
87 changes: 87 additions & 0 deletions sway/lockscreen-overlay.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "sway/lockscreen-overlay.h"
#include "sway/desktop/transaction.h"
#include "sway/layers.h"

#include "kde-lockscreen-overlay-v1-protocol.h"
#include "log.h"
#include "sway/tree/arrange.h"

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

#include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_layer_shell_v1.h>

struct sway_lockscreen_overlay {
};

static void kde_lockscreen_overlay_allow(struct wl_client *client,
struct wl_resource *resource, struct wl_resource *surface) {
sway_log(SWAY_ERROR, "at %s:%d", __func__, __LINE__);

struct wlr_surface *overlay_surface = wlr_surface_from_resource(surface);
// TODO: send a protocol error for each of these checks?
if (!overlay_surface) {
sway_log(SWAY_ERROR, "No overlay surface found");
return;
}

struct wlr_layer_surface_v1 *wlr_layer_surface =
wlr_layer_surface_v1_try_from_wlr_surface(overlay_surface);
if (!wlr_layer_surface) {
sway_log(SWAY_ERROR, "no wlr_layer surface found");
return;
}

struct sway_layer_surface *layer_surface = wlr_layer_surface->data;
if (!layer_surface) {
sway_log(SWAY_ERROR, "no sway_layer surface found");
return;
}

layer_surface->show_over_lockscreen = true;

arrange_layers(layer_surface->output);
arrange_root();
transaction_commit_dirty();
}

static void kde_lockscreen_overlay_destroy(struct wl_client *client,
struct wl_resource *resource) {
wl_resource_destroy(resource);
}

static const struct kde_lockscreen_overlay_v1_interface impl = {
.allow = kde_lockscreen_overlay_allow,
.destroy = kde_lockscreen_overlay_destroy,
};

static void lockscreen_overlay_bind(
struct wl_client *client,
void *data,
uint32_t version,
uint32_t id
) {
struct sway_lockscreen_overlay *overlay = data;

struct wl_resource *resource = wl_resource_create(client,
&kde_lockscreen_overlay_v1_interface, version, id);
if (!resource) {
wl_client_post_no_memory(client);
return;
}

wl_resource_set_implementation(resource, &impl, overlay, NULL);
}

struct sway_lockscreen_overlay *sway_lockscreen_overlay_create(struct wl_display *display) {
struct sway_lockscreen_overlay *overlay = calloc(1, sizeof(*overlay));

wl_global_create(
display,
&kde_lockscreen_overlay_v1_interface, 1,
overlay, lockscreen_overlay_bind
);

return overlay;
}
1 change: 1 addition & 0 deletions sway/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ sway_sources = files(
'ipc-json.c',
'ipc-server.c',
'lock.c',
'lockscreen-overlay.c',
'main.c',
'realtime.c',
'scene_descriptor.c',
Expand Down
3 changes: 3 additions & 0 deletions sway/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include "sway/server.h"
#include "sway/input/cursor.h"
#include "sway/tree/root.h"
#include "sway/lockscreen-overlay.h"

#if WLR_HAS_XWAYLAND
#include <wlr/xwayland/shell.h>
Expand Down Expand Up @@ -352,6 +353,8 @@ bool server_init(struct sway_server *server) {
wlr_ext_foreign_toplevel_list_v1_create(server->wl_display, SWAY_FOREIGN_TOPLEVEL_LIST_VERSION);
server->foreign_toplevel_manager =
wlr_foreign_toplevel_manager_v1_create(server->wl_display);
server->lockscreen_overlay =
sway_lockscreen_overlay_create(server->wl_display);

sway_session_lock_init();

Expand Down
2 changes: 1 addition & 1 deletion sway/tree/root.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@ struct sway_root *root_create(struct wl_display *wl_display) {
#if WLR_HAS_XWAYLAND
root->layers.unmanaged = alloc_scene_tree(root->layer_tree, &failed);
#endif
root->layers.session_lock = alloc_scene_tree(root->layer_tree, &failed);
root->layers.shell_overlay = alloc_scene_tree(root->layer_tree, &failed);
root->layers.popup = alloc_scene_tree(root->layer_tree, &failed);
root->layers.seat = alloc_scene_tree(root->layer_tree, &failed);
root->layers.session_lock = alloc_scene_tree(root->layer_tree, &failed);

if (!failed && !scene_descriptor_assign(&root->layers.seat->node,
SWAY_SCENE_DESC_NON_INTERACTIVE, (void *)1)) {
Expand Down