mirror of
				https://codeberg.org/dwl/dwl.git
				synced 2025-10-29 05:40:19 -04:00 
			
		
		
		
	implement ext-session-lock-v1
This commit is contained in:
		
							parent
							
								
									d42a977b5b
								
							
						
					
					
						commit
						79b051f242
					
				
					 1 changed files with 167 additions and 8 deletions
				
			
		
							
								
								
									
										175
									
								
								dwl.c
									
										
									
									
									
								
							
							
						
						
									
										175
									
								
								dwl.c
									
										
									
									
									
								
							|  | @ -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))) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Leonardo Hernández Hernández
						Leonardo Hernández Hernández