Skip to content

Commit

Permalink
WIP: Implement the session lock protocol
Browse files Browse the repository at this point in the history
This sort of handles basic locking and unlocking.

BUGS:
- The swaylock indicator isn't displayed. Perhaps this is because
  swaylock uses a subsurface to draw it, and wlr-surface-node
  doesn't support child surfaces?

TODO:
- Deal with outputs being resized
- Use keyboard grabs (fail to lock if grabbed?)
- Blank the screen instead of just relying on the lock app to
  display the surface. Or at least wait for the surface to
  be committed before saying the lock succeeded.
  • Loading branch information
lcolitti committed Feb 25, 2024
1 parent 982605d commit cf7fcac
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 1 deletion.
3 changes: 2 additions & 1 deletion plugins/protocols/meson.build
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
protocol_plugins = [
'foreign-toplevel', 'gtk-shell', 'wayfire-shell', 'xdg-activation', 'shortcuts-inhibit'
'foreign-toplevel', 'gtk-shell', 'wayfire-shell', 'xdg-activation', 'shortcuts-inhibit',
'session-lock'
]

all_include_dirs = [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc]
Expand Down
198 changes: 198 additions & 0 deletions plugins/protocols/session-lock.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
#include "wayfire/core.hpp"

#include "wayfire/seat.hpp"
#include "wayfire/scene-input.hpp"
#include "wayfire/scene-operations.hpp"
#include "wayfire/unstable/wlr-surface-node.hpp"
#include "wayfire/output.hpp"
#include "wayfire/output-layout.hpp"

#include <wayfire/plugin.hpp>
#include <wayfire/nonstd/wlroots-full.hpp>
#include <wayfire/util/log.hpp>

class wf_session_lock_impl : public wf::plugin_interface_t
{
class lock_surface_node_t : public wf::scene::wlr_surface_node_t
{
public:
lock_surface_node_t(wlr_surface *surface, bool autocommit) :
wf::scene::wlr_surface_node_t(surface, autocommit)
{
interaction = new lock_surface_keyboard_interaction(surface);
}

wf::keyboard_focus_node_t keyboard_refocus(wf::output_t *output) override
{
wf::keyboard_focus_node_t node = {
.node = this,
.importance = wf::focus_importance::HIGH,
.allow_focus_below = false,
};
return node;
}

class lock_surface_keyboard_interaction : public wf::keyboard_interaction_t
{
public:
lock_surface_keyboard_interaction(wlr_surface *surface) : surface(surface)
{}

void handle_keyboard_enter(wf::seat_t *seat)
{
// TODO: use a keyboard grab instead?
wlr_seat_keyboard_enter(seat->seat, surface, nullptr, 0, nullptr);
}

void handle_keyboard_leave(wf::seat_t *seat)
{
// TODO: refocus?
wlr_seat_keyboard_clear_focus(seat->seat);
}

void handle_keyboard_key(wf::seat_t *seat, wlr_keyboard_key_event event)
{
wlr_seat_keyboard_notify_key(seat->seat, event.time_msec, event.keycode, event.state);
}

private:
wlr_surface *surface;
};

wf::keyboard_interaction_t& keyboard_interaction()
{
return *interaction;
}

private:
wf::keyboard_interaction_t *interaction;
};

class wayfire_session_lock
{
public:
wayfire_session_lock(wf_session_lock_impl *parent, wlr_session_lock_v1 *data)
{
plugin = parent;
lock = data;

new_surface.set_callback([this] (void *data)
{
wlr_session_lock_surface_v1 *lock_surface = (wlr_session_lock_surface_v1*)data;
uint32_t serial = wlr_session_lock_surface_v1_configure(lock_surface,
lock_surface->output->width,
lock_surface->output->height);
LOGI("surface_configure output=", lock_surface->output->name, " ",
lock_surface->output->width, "x",
lock_surface->output->height,
" serial=", serial);

surfaces.push_back(lock_surface);

auto node = new std::shared_ptr<wf::scene::wlr_surface_node_t>(
new lock_surface_node_t(lock_surface->surface, true));

lock_surface->data = node;
auto target_layer = wf::scene::layer::TOP;
auto wo = wf::get_core().output_layout->find_output(lock_surface->output);
auto layer_node = wo->node_for_layer(target_layer);

(*node)->set_enabled(true);
wf::scene::add_front(layer_node, *node);
wf::get_core().seat->set_active_node(*node);

lock_surface_destroy.set_callback([lock_surface, this] (void *data)
{
auto node = (std::shared_ptr<wf::scene::wlr_surface_node_t>*)lock_surface->data;
if (node != nullptr)
{
wf::scene::remove_child(*node);
}

lock_surface_destroy.disconnect();
});
lock_surface_destroy.connect(&lock_surface->events.destroy);
});
new_surface.connect(&lock->events.new_surface);

unlock.set_callback([this] (void *data)
{
LOGI("unlock");
});
unlock.connect(&lock->events.unlock);

destroy.set_callback([this] (void *data)
{
new_surface.disconnect();
unlock.disconnect();
destroy.disconnect();
LOGI("destroy");
plugin->unlock();
});
destroy.connect(&lock->events.destroy);
}

private:
wf_session_lock_impl *plugin;
wlr_session_lock_v1 *lock;
std::vector<wlr_session_lock_surface_v1*> surfaces;
wf::wl_listener_wrapper new_surface;
wf::wl_listener_wrapper unlock;
wf::wl_listener_wrapper destroy;
wf::wl_listener_wrapper lock_surface_destroy;
};

public:
void init() override
{
auto display = wf::get_core().display;
manager = wlr_session_lock_manager_v1_create(display);

new_lock.set_callback([this] (void *data)
{
wlr_session_lock_v1 *wlr_lock = (wlr_session_lock_v1*)data;
if (cur_lock.get() == nullptr)
{
cur_lock.reset(new wayfire_session_lock(this, wlr_lock));
// TODO: blank the screen, or set a timeout for the lock app to commit a surface.
wlr_session_lock_v1_send_locked(wlr_lock);
LOGI("new_lock");
} else
{
LOGI("new_lock: already locked");
wlr_session_lock_v1_destroy(wlr_lock);
}
});
new_lock.connect(&manager->events.new_lock);

destroyed.set_callback([this] (void *data)
{
LOGI("session_lock destroyed");
});
destroyed.connect(&manager->events.destroy);
}

void fini() override
{
// TODO: unlock everything?
}

bool is_unloadable() override
{
return false;
}

void unlock()
{
cur_lock.reset();
}

private:
wlr_session_lock_manager_v1 *manager;
wf::wl_listener_wrapper new_lock;
wf::wl_listener_wrapper destroyed;

std::shared_ptr<wayfire_session_lock> cur_lock;
};

DECLARE_WAYFIRE_PLUGIN(wf_session_lock_impl);
1 change: 1 addition & 0 deletions proto/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ server_protocols = [
[wl_protocol_dir, 'unstable/relative-pointer/relative-pointer-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/tablet/tablet-unstable-v2.xml'],
[wl_protocol_dir, 'unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml'],
[wl_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'],
'wayfire-shell-unstable-v2.xml',
'gtk-shell.xml',
'wlr-layer-shell-unstable-v1.xml',
Expand Down
2 changes: 2 additions & 0 deletions src/api/wayfire/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ class compositor_core_t : public wf::object_base_t, public signal::provider_t
wlr_xdg_foreign_registry *foreign_registry;
wlr_xdg_foreign_v1 *foreign_v1;
wlr_xdg_foreign_v2 *foreign_v2;

wlr_session_lock_manager_v1 *session_lock;
} protocols;

std::string to_string() const
Expand Down
1 change: 1 addition & 0 deletions src/api/wayfire/nonstd/wlroots-full.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ extern "C"
#include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_fractional_scale_v1.h>
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_session_lock_v1.h>

// Activation plugin
#include <wlr/types/wlr_xdg_activation_v1.h>
Expand Down
1 change: 1 addition & 0 deletions src/api/wayfire/nonstd/wlroots.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ extern "C"
struct wlr_presentation;
struct wlr_primary_selection_v1_device_manager;
struct wlr_drm_lease_v1_manager;
struct wlr_session_lock_manager_v1;

struct wlr_xdg_foreign_v1;
struct wlr_xdg_foreign_v2;
Expand Down

0 comments on commit cf7fcac

Please sign in to comment.