diff options
| author | Leonardo Hernández Hernández <leohdz172@protonmail.com> | 2022-02-13 11:56:57 -0600 | 
|---|---|---|
| committer | Leonardo Hernández Hernández <leohdz172@protonmail.com> | 2022-12-06 14:11:41 -0600 | 
| commit | 79b051f2425af8a1e91a61fba145beb00f522973 (patch) | |
| tree | 8b253a921e056ff30b423d669c0b55ba5740ca45 | |
| parent | d42a977b5ba8ae09753c7f6fcf4e2044bac7d92e (diff) | |
implement ext-session-lock-v1
| -rw-r--r-- | dwl.c | 175 | 
1 files changed, 167 insertions, 8 deletions
@@ -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 @@ -829,6 +858,25 @@ createlayersurface(struct wl_listener *listener, void *data)  }  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)  {  	/* This event is raised by the backend when a new output (aka a display or @@ -1033,6 +1081,49 @@ destroylayersurfacenotify(struct wl_listener *listener, void *data)  }  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)  {  	/* Called when the surface is destroyed and should never be shown again. */ @@ -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; @@ -1316,6 +1424,31 @@ killclient(const Arg *arg)  }  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)  {  	LayerSurface *l = wl_container_of(listener, l, map); @@ -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( @@ -2252,6 +2392,13 @@ toggleview(const Arg *arg)  }  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)  {  	LayerSurface *layersurface = wl_container_of(listener, layersurface, unmap); @@ -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))) {  | 
