implement ext-session-lock-v1

This commit is contained in:
Leonardo Hernández Hernández 2022-02-13 11:56:57 -06:00
parent d42a977b5b
commit 79b051f242
No known key found for this signature in database
GPG Key ID: E538897EE11B9624
1 changed files with 167 additions and 8 deletions

175
dwl.c
View File

@ -40,6 +40,7 @@
#include <wlr/types/wlr_screencopy_v1.h>
#include <wlr/types/wlr_seat.h>
#include <wlr/types/wlr_server_decoration.h>
#include <wlr/types/wlr_session_lock_v1.h>
#include <wlr/types/wlr_single_pixel_buffer_v1.h>
#include <wlr/types/wlr_subcompositor.h>
#include <wlr/types/wlr_viewporter.h>
@ -73,7 +74,7 @@
/* enums */
enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */
enum { XDGShell, LayerShell, X11Managed, X11Unmanaged }; /* client types */
enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, NUM_LAYERS }; /* scene layers */
enum { LyrBg, LyrBottom, LyrTop, LyrOverlay, LyrTile, LyrFloat, LyrFS, LyrDragIcon, LyrBlock, NUM_LAYERS }; /* scene layers */
#ifdef XWAYLAND
enum { NetWMWindowTypeDialog, NetWMWindowTypeSplash, NetWMWindowTypeToolbar,
NetWMWindowTypeUtility, NetLast }; /* EWMH atoms */
@ -173,6 +174,8 @@ struct Monitor {
struct wlr_scene_rect *fullscreen_bg; /* See createmon() for info */
struct wl_listener frame;
struct wl_listener destroy;
struct wl_listener destroy_lock_surface;
struct wlr_session_lock_surface_v1 *lock_surface;
struct wlr_box m; /* monitor area, layout-relative */
struct wlr_box w; /* window area, layout-relative */
struct wl_list layers[4]; /* LayerSurface::link */
@ -202,6 +205,15 @@ typedef struct {
int monitor;
} Rule;
typedef struct {
struct wlr_scene_tree *scene;
struct wlr_session_lock_v1 *lock;
struct wl_listener new_surface;
struct wl_listener unlock;
struct wl_listener destroy;
} SessionLock;
/* function declarations */
static void applybounds(Client *c, struct wlr_box *bbox);
static void applyrules(Client *c);
@ -222,6 +234,7 @@ static void commitnotify(struct wl_listener *listener, void *data);
static void createidleinhibitor(struct wl_listener *listener, void *data);
static void createkeyboard(struct wlr_keyboard *keyboard);
static void createlayersurface(struct wl_listener *listener, void *data);
static void createlocksurface(struct wl_listener *listener, void *data);
static void createmon(struct wl_listener *listener, void *data);
static void createnotify(struct wl_listener *listener, void *data);
static void createpointer(struct wlr_pointer *pointer);
@ -229,7 +242,11 @@ static void cursorframe(struct wl_listener *listener, void *data);
static void destroydragicon(struct wl_listener *listener, void *data);
static void destroyidleinhibitor(struct wl_listener *listener, void *data);
static void destroylayersurfacenotify(struct wl_listener *listener, void *data);
static void destroylock(SessionLock *lock, int unlocked);
static void destroylocksurface(struct wl_listener *listener, void *data);
static void destroynotify(struct wl_listener *listener, void *data);
static void destroysessionlock(struct wl_listener *listener, void *data);
static void destroysessionmgr(struct wl_listener *listener, void *data);
static Monitor *dirtomon(enum wlr_direction dir);
static void focusclient(Client *c, int lift);
static void focusmon(const Arg *arg);
@ -242,6 +259,7 @@ static int keybinding(uint32_t mods, xkb_keysym_t sym);
static void keypress(struct wl_listener *listener, void *data);
static void keypressmod(struct wl_listener *listener, void *data);
static void killclient(const Arg *arg);
static void locksession(struct wl_listener *listener, void *data);
static void maplayersurfacenotify(struct wl_listener *listener, void *data);
static void mapnotify(struct wl_listener *listener, void *data);
static void maximizenotify(struct wl_listener *listener, void *data);
@ -281,6 +299,7 @@ static void togglefloating(const Arg *arg);
static void togglefullscreen(const Arg *arg);
static void toggletag(const Arg *arg);
static void toggleview(const Arg *arg);
static void unlocksession(struct wl_listener *listener, void *data);
static void unmaplayersurfacenotify(struct wl_listener *listener, void *data);
static void unmapnotify(struct wl_listener *listener, void *data);
static void updatemons(struct wl_listener *listener, void *data);
@ -297,6 +316,7 @@ static void zoom(const Arg *arg);
static const char broken[] = "broken";
static const char *cursor_image = "left_ptr";
static pid_t child_pid = -1;
static int locked;
static void *exclusive_focus;
static struct wl_display *dpy;
static struct wlr_backend *backend;
@ -321,6 +341,10 @@ static struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard_mgr;
static struct wlr_cursor *cursor;
static struct wlr_xcursor_manager *cursor_mgr;
static struct wlr_session_lock_manager_v1 *session_lock_mgr;
static struct wlr_scene_rect *locked_bg;
static struct wlr_session_lock_v1 *cur_lock;
static struct wlr_seat *seat;
static struct wl_list keyboards;
static unsigned int cursor_mode;
@ -355,6 +379,8 @@ static struct wl_listener request_set_psel = {.notify = setpsel};
static struct wl_listener request_set_sel = {.notify = setsel};
static struct wl_listener request_start_drag = {.notify = requeststartdrag};
static struct wl_listener start_drag = {.notify = startdrag};
static struct wl_listener session_lock_create_lock = {.notify = locksession};
static struct wl_listener session_lock_mgr_destroy = {.notify = destroysessionmgr};
#ifdef XWAYLAND
static void activatex11(struct wl_listener *listener, void *data);
@ -504,8 +530,8 @@ arrangelayers(Monitor *m)
for (i = 0; i < LENGTH(layers_above_shell); i++) {
wl_list_for_each_reverse(layersurface,
&m->layers[layers_above_shell[i]], link) {
if (layersurface->layer_surface->current.keyboard_interactive &&
layersurface->mapped) {
if (!locked && layersurface->layer_surface->current.keyboard_interactive
&& layersurface->mapped) {
/* Deactivate the focused client. */
focusclient(NULL, 0);
exclusive_focus = layersurface;
@ -544,6 +570,10 @@ buttonpress(struct wl_listener *listener, void *data)
switch (event->state) {
case WLR_BUTTON_PRESSED:
cursor_mode = CurPressed;
if (locked)
break;
/* Change focus if the button was _pressed_ over a client */
xytonode(cursor->x, cursor->y, NULL, &c, NULL, NULL, NULL);
if (c && (!client_is_unmanaged(c) || client_wants_focus(c)))
@ -558,11 +588,10 @@ buttonpress(struct wl_listener *listener, void *data)
return;
}
}
cursor_mode = CurPressed;
break;
case WLR_BUTTON_RELEASED:
/* If you released any buttons, we exit interactive move/resize mode. */
if (cursor_mode != CurNormal && cursor_mode != CurPressed) {
if (!locked && cursor_mode != CurNormal && cursor_mode != CurPressed) {
cursor_mode = CurNormal;
/* Clear the pointer focus, this way if the cursor is over a surface
* we will send an enter event after which the client will provide us
@ -828,6 +857,25 @@ createlayersurface(struct wl_listener *listener, void *data)
wlr_layer_surface->current = old_state;
}
void
createlocksurface(struct wl_listener *listener, void *data)
{
SessionLock *lock = wl_container_of(listener, lock, new_surface);
struct wlr_session_lock_surface_v1 *lock_surface = data;
Monitor *m = lock_surface->output->data;
struct wlr_scene_tree *scene_tree = lock_surface->surface->data =
wlr_scene_subsurface_tree_create(lock->scene, lock_surface->surface);
m->lock_surface = lock_surface;
wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
wlr_session_lock_surface_v1_configure(lock_surface, m->m.width, m->m.height);
LISTEN(&lock_surface->events.destroy, &m->destroy_lock_surface, destroylocksurface);
if (m == selmon)
client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat));
}
void
createmon(struct wl_listener *listener, void *data)
{
@ -1032,6 +1080,49 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data)
free(layersurface);
}
void
destroylock(SessionLock *lock, int unlock)
{
wlr_seat_keyboard_notify_clear_focus(seat);
if ((locked = !unlock))
goto destroy;
wlr_scene_node_set_enabled(&locked_bg->node, 0);
focusclient(focustop(selmon), 0);
motionnotify(0);
destroy:
wl_list_remove(&lock->new_surface.link);
wl_list_remove(&lock->unlock.link);
wl_list_remove(&lock->destroy.link);
wlr_scene_node_destroy(&lock->scene->node);
cur_lock = NULL;
free(lock);
}
void
destroylocksurface(struct wl_listener *listener, void *data)
{
Monitor *m = wl_container_of(listener, m, destroy_lock_surface);
struct wlr_session_lock_surface_v1 *surface, *lock_surface = m->lock_surface;
m->lock_surface = NULL;
wl_list_remove(&m->destroy_lock_surface.link);
if (lock_surface->surface == seat->keyboard_state.focused_surface) {
if (locked && cur_lock && !wl_list_empty(&cur_lock->surfaces)) {
surface = wl_container_of(cur_lock->surfaces.next, surface, link);
client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat));
} else if (!locked) {
focusclient(focustop(selmon), 1);
} else {
wlr_seat_keyboard_clear_focus(seat);
}
}
}
void
destroynotify(struct wl_listener *listener, void *data)
{
@ -1052,6 +1143,20 @@ destroynotify(struct wl_listener *listener, void *data)
free(c);
}
void
destroysessionlock(struct wl_listener *listener, void *data)
{
SessionLock *lock = wl_container_of(listener, lock, destroy);
destroylock(lock, 0);
}
void
destroysessionmgr(struct wl_listener *listener, void *data)
{
wl_list_remove(&session_lock_create_lock.link);
wl_list_remove(&session_lock_mgr_destroy.link);
}
Monitor *
dirtomon(enum wlr_direction dir)
{
@ -1074,6 +1179,9 @@ focusclient(Client *c, int lift)
struct wlr_surface *old = seat->keyboard_state.focused_surface;
int i;
if (locked)
return;
/* Raise client in stacking order if requested */
if (c && lift)
wlr_scene_node_raise_to_top(&c->scene->node);
@ -1276,7 +1384,7 @@ keypress(struct wl_listener *listener, void *data)
/* On _press_ if there is no active screen locker,
* attempt to process a compositor keybinding. */
if (!input_inhibit_mgr->active_inhibitor
if (!locked && !input_inhibit_mgr->active_inhibitor
&& event->state == WL_KEYBOARD_KEY_STATE_PRESSED)
for (i = 0; i < nsyms; i++)
handled = keybinding(mods, syms[i]) || handled;
@ -1315,6 +1423,31 @@ killclient(const Arg *arg)
client_send_close(sel);
}
void
locksession(struct wl_listener *listener, void *data)
{
struct wlr_session_lock_v1 *session_lock = data;
SessionLock *lock;
wlr_scene_node_set_enabled(&locked_bg->node, 1);
if (cur_lock) {
wlr_session_lock_v1_destroy(session_lock);
return;
}
lock = ecalloc(1, sizeof(*lock));
focusclient(NULL, 0);
lock->scene = wlr_scene_tree_create(layers[LyrBlock]);
cur_lock = lock->lock = session_lock;
locked = 1;
session_lock->data = lock;
LISTEN(&session_lock->events.new_surface, &lock->new_surface, createlocksurface);
LISTEN(&session_lock->events.destroy, &lock->destroy, destroysessionlock);
LISTEN(&session_lock->events.unlock, &lock->unlock, unlocksession);
wlr_session_lock_v1_send_locked(session_lock);
}
void
maplayersurfacenotify(struct wl_listener *listener, void *data)
{
@ -1985,6 +2118,7 @@ setup(void)
layers[LyrTop] = wlr_scene_tree_create(&scene->tree);
layers[LyrOverlay] = wlr_scene_tree_create(&scene->tree);
layers[LyrDragIcon] = wlr_scene_tree_create(&scene->tree);
layers[LyrBlock] = wlr_scene_tree_create(&scene->tree);
/* Create a renderer with the default implementation */
if (!(drw = wlr_renderer_autocreate(backend)))
@ -2049,6 +2183,12 @@ setup(void)
wl_signal_add(&xdg_shell->events.new_surface, &new_xdg_surface);
input_inhibit_mgr = wlr_input_inhibit_manager_create(dpy);
session_lock_mgr = wlr_session_lock_manager_v1_create(dpy);
wl_signal_add(&session_lock_mgr->events.new_lock, &session_lock_create_lock);
wl_signal_add(&session_lock_mgr->events.destroy, &session_lock_mgr_destroy);
locked_bg = wlr_scene_rect_create(layers[LyrBlock], sgeom.width, sgeom.height,
(float [4]){0.1, 0.1, 0.1, 1.0});
wlr_scene_node_set_enabled(&locked_bg->node, 0);
/* Use decoration protocols to negotiate server-side decorations */
wlr_server_decoration_manager_set_default_mode(
@ -2251,6 +2391,13 @@ toggleview(const Arg *arg)
printstatus();
}
void
unlocksession(struct wl_listener *listener, void *data)
{
SessionLock *lock = wl_container_of(listener, lock, unlock);
destroylock(lock, 1);
}
void
unmaplayersurfacenotify(struct wl_listener *listener, void *data)
{
@ -2334,6 +2481,7 @@ updatemons(struct wl_listener *listener, void *data)
wlr_output_layout_add_auto(output_layout, m->wlr_output);
/* Now that we update the output layout we can get its box */
wlr_output_layout_get_box(output_layout, NULL, &sgeom);
wlr_scene_rect_set_size(locked_bg, sgeom.width, sgeom.height);
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled)
continue;
@ -2351,16 +2499,27 @@ updatemons(struct wl_listener *listener, void *data)
wlr_scene_node_set_position(&m->fullscreen_bg->node, m->m.x, m->m.y);
wlr_scene_rect_set_size(m->fullscreen_bg, m->m.width, m->m.height);
if (m->lock_surface) {
struct wlr_scene_tree *scene_tree = m->lock_surface->surface->data;
wlr_scene_node_set_position(&scene_tree->node, m->m.x, m->m.y);
wlr_session_lock_surface_v1_configure(m->lock_surface, m->m.width,
m->m.height);
}
config_head->state.enabled = 1;
config_head->state.mode = m->wlr_output->current_mode;
config_head->state.x = m->m.x;
config_head->state.y = m->m.y;
}
if (selmon && selmon->wlr_output->enabled)
if (selmon && selmon->wlr_output->enabled) {
wl_list_for_each(c, &clients, link)
if (!c->mon && client_is_mapped(c))
setmon(c, selmon, c->tags);
if (selmon->lock_surface)
client_notify_enter(selmon->lock_surface->surface,
wlr_seat_get_keyboard(seat));
}
wlr_output_manager_v1_set_configuration(output_mgr, config);
}
@ -2421,7 +2580,7 @@ xytonode(double x, double y, struct wlr_surface **psurface,
Client *c = NULL;
LayerSurface *l = NULL;
const int *layer;
int focus_order[] = { LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg };
int focus_order[] = { LyrBlock, LyrOverlay, LyrTop, LyrFS, LyrFloat, LyrTile, LyrBottom, LyrBg };
for (layer = focus_order; layer < END(focus_order); layer++) {
if ((node = wlr_scene_node_at(&layers[*layer]->node, x, y, nx, ny))) {