mirror of
				https://github.com/labwc/labwc.git
				synced 2025-11-03 09:01:51 -05:00 
			
		
		
		
	view/xwayland: avoid focusing views that don't want focus
XWayland views can self-declare that they don't want keyboard focus via the ICCCM WM_HINTS property. Most of the logic is already in place to avoid giving focus to such views (e.g. taskbars). Add a couple of missing pieces to make this work: - Hook up view_isfocusable() to look at WM_HINTS for XWayland views - Adjust desktop_focus_topmost_mapped_view() to skip unfocusable views
This commit is contained in:
		
							parent
							
								
									d503370a77
								
							
						
					
					
						commit
						7e72bf975f
					
				
					 10 changed files with 29 additions and 13 deletions
				
			
		| 
						 | 
				
			
			@ -378,7 +378,7 @@ void foreign_toplevel_update_outputs(struct view *view);
 | 
			
		|||
void desktop_focus_view(struct view *view, bool raise);
 | 
			
		||||
void desktop_arrange_all_views(struct server *server);
 | 
			
		||||
void desktop_focus_output(struct output *output);
 | 
			
		||||
struct view *desktop_topmost_mapped_view(struct server *server);
 | 
			
		||||
struct view *desktop_topmost_focusable_view(struct server *server);
 | 
			
		||||
 | 
			
		||||
enum lab_cycle_dir {
 | 
			
		||||
	LAB_CYCLE_DIR_NONE,
 | 
			
		||||
| 
						 | 
				
			
			@ -393,7 +393,7 @@ enum lab_cycle_dir {
 | 
			
		|||
 */
 | 
			
		||||
struct view *desktop_cycle_view(struct server *server, struct view *start_view,
 | 
			
		||||
	enum lab_cycle_dir dir);
 | 
			
		||||
void desktop_focus_topmost_mapped_view(struct server *server);
 | 
			
		||||
void desktop_focus_topmost_view(struct server *server);
 | 
			
		||||
 | 
			
		||||
void keyboard_cancel_keybind_repeat(struct keyboard *keyboard);
 | 
			
		||||
void keyboard_key_notify(struct wl_listener *listener, void *data);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -69,6 +69,8 @@ struct view_impl {
 | 
			
		|||
	struct view *(*get_root)(struct view *self);
 | 
			
		||||
	void (*append_children)(struct view *self, struct wl_array *children);
 | 
			
		||||
	struct view_size_hints (*get_size_hints)(struct view *self);
 | 
			
		||||
	/* if not implemented, view is assumed to want focus */
 | 
			
		||||
	bool (*wants_focus)(struct view *self);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct view {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -190,7 +190,7 @@ desktop_cycle_view(struct server *server, struct view *start_view,
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
struct view *
 | 
			
		||||
desktop_topmost_mapped_view(struct server *server)
 | 
			
		||||
desktop_topmost_focusable_view(struct server *server)
 | 
			
		||||
{
 | 
			
		||||
	struct view *view;
 | 
			
		||||
	struct wl_list *node_list;
 | 
			
		||||
| 
						 | 
				
			
			@ -202,7 +202,7 @@ desktop_topmost_mapped_view(struct server *server)
 | 
			
		|||
			continue;
 | 
			
		||||
		}
 | 
			
		||||
		view = node_view_from_node(node);
 | 
			
		||||
		if (view->mapped) {
 | 
			
		||||
		if (view->mapped && view_isfocusable(view)) {
 | 
			
		||||
			return view;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -210,9 +210,9 @@ desktop_topmost_mapped_view(struct server *server)
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
desktop_focus_topmost_mapped_view(struct server *server)
 | 
			
		||||
desktop_focus_topmost_view(struct server *server)
 | 
			
		||||
{
 | 
			
		||||
	struct view *view = desktop_topmost_mapped_view(server);
 | 
			
		||||
	struct view *view = desktop_topmost_focusable_view(server);
 | 
			
		||||
	if (view) {
 | 
			
		||||
		desktop_focus_view(view, /*raise*/ true);
 | 
			
		||||
	} else {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -496,7 +496,7 @@ seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer)
 | 
			
		|||
{
 | 
			
		||||
	if (!layer) {
 | 
			
		||||
		seat->focused_layer = NULL;
 | 
			
		||||
		desktop_focus_topmost_mapped_view(seat->server);
 | 
			
		||||
		desktop_focus_topmost_view(seat->server);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
	seat_focus(seat, layer->surface);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -227,7 +227,7 @@ handle_unlock(struct wl_listener *listener, void *data)
 | 
			
		|||
{
 | 
			
		||||
	struct session_lock *lock = wl_container_of(listener, lock, unlock);
 | 
			
		||||
	session_lock_destroy(lock);
 | 
			
		||||
	desktop_focus_topmost_mapped_view(g_server);
 | 
			
		||||
	desktop_focus_topmost_view(g_server);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -118,6 +118,9 @@ view_isfocusable(struct view *view)
 | 
			
		|||
	if (!view->surface) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	if (view->impl->wants_focus && !view->impl->wants_focus(view)) {
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
	return (view->mapped || view->minimized);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -289,7 +289,7 @@ workspaces_switch_to(struct workspace *target, bool update_focus)
 | 
			
		|||
	if (update_focus) {
 | 
			
		||||
		struct view *view = server->focused_view;
 | 
			
		||||
		if (!view || !view_is_always_on_top(view)) {
 | 
			
		||||
			desktop_focus_topmost_mapped_view(server);
 | 
			
		||||
			desktop_focus_topmost_view(server);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -554,7 +554,7 @@ xdg_toplevel_view_unmap(struct view *view, bool client_request)
 | 
			
		|||
		view->mapped = false;
 | 
			
		||||
		wlr_scene_node_set_enabled(&view->scene_tree->node, false);
 | 
			
		||||
		wl_list_remove(&view->commit.link);
 | 
			
		||||
		desktop_focus_topmost_mapped_view(view->server);
 | 
			
		||||
		desktop_focus_topmost_view(view->server);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -88,7 +88,7 @@ focus_next_surface(struct server *server, struct wlr_xwayland_surface *xsurface)
 | 
			
		|||
	 * to the topmost mapped view. This fixes dmenu
 | 
			
		||||
	 * not giving focus back when closed with ESC.
 | 
			
		||||
	 */
 | 
			
		||||
	desktop_focus_topmost_mapped_view(server);
 | 
			
		||||
	desktop_focus_topmost_view(server);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +166,7 @@ unmanaged_handle_request_activate(struct wl_listener *listener, void *data)
 | 
			
		|||
	 * Validate that the unmanaged surface trying to grab focus is actually
 | 
			
		||||
	 * a child of the topmost mapped view before granting the request.
 | 
			
		||||
	 */
 | 
			
		||||
	struct view *view = desktop_topmost_mapped_view(server);
 | 
			
		||||
	struct view *view = desktop_topmost_focusable_view(server);
 | 
			
		||||
	if (view && view->type == LAB_XWAYLAND_VIEW) {
 | 
			
		||||
		struct wlr_xwayland_surface *surf =
 | 
			
		||||
			wlr_xwayland_surface_from_wlr_surface(view->surface);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,6 +30,16 @@ xwayland_view_get_size_hints(struct view *view)
 | 
			
		|||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
xwayland_view_wants_focus(struct view *view)
 | 
			
		||||
{
 | 
			
		||||
	xcb_icccm_wm_hints_t *hints = xwayland_surface_from_view(view)->hints;
 | 
			
		||||
	if (!hints) {
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	return (bool)hints->input;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static struct wlr_xwayland_surface *
 | 
			
		||||
top_parent_of(struct view *view)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			@ -505,7 +515,7 @@ xwayland_view_unmap(struct view *view, bool client_request)
 | 
			
		|||
	view->mapped = false;
 | 
			
		||||
	wl_list_remove(&view->commit.link);
 | 
			
		||||
	wlr_scene_node_set_enabled(&view->scene_tree->node, false);
 | 
			
		||||
	desktop_focus_topmost_mapped_view(view->server);
 | 
			
		||||
	desktop_focus_topmost_view(view->server);
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * If the view was explicitly unmapped by the client (rather
 | 
			
		||||
| 
						 | 
				
			
			@ -634,6 +644,7 @@ static const struct view_impl xwayland_view_impl = {
 | 
			
		|||
	.get_root = xwayland_view_get_root,
 | 
			
		||||
	.append_children = xwayland_view_append_children,
 | 
			
		||||
	.get_size_hints = xwayland_view_get_size_hints,
 | 
			
		||||
	.wants_focus = xwayland_view_wants_focus,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue