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_focus_view(struct view *view, bool raise);
|
||||||
void desktop_arrange_all_views(struct server *server);
|
void desktop_arrange_all_views(struct server *server);
|
||||||
void desktop_focus_output(struct output *output);
|
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 {
|
enum lab_cycle_dir {
|
||||||
LAB_CYCLE_DIR_NONE,
|
LAB_CYCLE_DIR_NONE,
|
||||||
|
|
@ -393,7 +393,7 @@ enum lab_cycle_dir {
|
||||||
*/
|
*/
|
||||||
struct view *desktop_cycle_view(struct server *server, struct view *start_view,
|
struct view *desktop_cycle_view(struct server *server, struct view *start_view,
|
||||||
enum lab_cycle_dir dir);
|
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_cancel_keybind_repeat(struct keyboard *keyboard);
|
||||||
void keyboard_key_notify(struct wl_listener *listener, void *data);
|
void keyboard_key_notify(struct wl_listener *listener, void *data);
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ struct view_impl {
|
||||||
struct view *(*get_root)(struct view *self);
|
struct view *(*get_root)(struct view *self);
|
||||||
void (*append_children)(struct view *self, struct wl_array *children);
|
void (*append_children)(struct view *self, struct wl_array *children);
|
||||||
struct view_size_hints (*get_size_hints)(struct view *self);
|
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 {
|
struct view {
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,7 @@ desktop_cycle_view(struct server *server, struct view *start_view,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct view *
|
struct view *
|
||||||
desktop_topmost_mapped_view(struct server *server)
|
desktop_topmost_focusable_view(struct server *server)
|
||||||
{
|
{
|
||||||
struct view *view;
|
struct view *view;
|
||||||
struct wl_list *node_list;
|
struct wl_list *node_list;
|
||||||
|
|
@ -202,7 +202,7 @@ desktop_topmost_mapped_view(struct server *server)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
view = node_view_from_node(node);
|
view = node_view_from_node(node);
|
||||||
if (view->mapped) {
|
if (view->mapped && view_isfocusable(view)) {
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -210,9 +210,9 @@ desktop_topmost_mapped_view(struct server *server)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
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) {
|
if (view) {
|
||||||
desktop_focus_view(view, /*raise*/ true);
|
desktop_focus_view(view, /*raise*/ true);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -496,7 +496,7 @@ seat_set_focus_layer(struct seat *seat, struct wlr_layer_surface_v1 *layer)
|
||||||
{
|
{
|
||||||
if (!layer) {
|
if (!layer) {
|
||||||
seat->focused_layer = NULL;
|
seat->focused_layer = NULL;
|
||||||
desktop_focus_topmost_mapped_view(seat->server);
|
desktop_focus_topmost_view(seat->server);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
seat_focus(seat, layer->surface);
|
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);
|
struct session_lock *lock = wl_container_of(listener, lock, unlock);
|
||||||
session_lock_destroy(lock);
|
session_lock_destroy(lock);
|
||||||
desktop_focus_topmost_mapped_view(g_server);
|
desktop_focus_topmost_view(g_server);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,9 @@ view_isfocusable(struct view *view)
|
||||||
if (!view->surface) {
|
if (!view->surface) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (view->impl->wants_focus && !view->impl->wants_focus(view)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return (view->mapped || view->minimized);
|
return (view->mapped || view->minimized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,7 @@ workspaces_switch_to(struct workspace *target, bool update_focus)
|
||||||
if (update_focus) {
|
if (update_focus) {
|
||||||
struct view *view = server->focused_view;
|
struct view *view = server->focused_view;
|
||||||
if (!view || !view_is_always_on_top(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;
|
view->mapped = false;
|
||||||
wlr_scene_node_set_enabled(&view->scene_tree->node, false);
|
wlr_scene_node_set_enabled(&view->scene_tree->node, false);
|
||||||
wl_list_remove(&view->commit.link);
|
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
|
* to the topmost mapped view. This fixes dmenu
|
||||||
* not giving focus back when closed with ESC.
|
* not giving focus back when closed with ESC.
|
||||||
*/
|
*/
|
||||||
desktop_focus_topmost_mapped_view(server);
|
desktop_focus_topmost_view(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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
|
* Validate that the unmanaged surface trying to grab focus is actually
|
||||||
* a child of the topmost mapped view before granting the request.
|
* 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) {
|
if (view && view->type == LAB_XWAYLAND_VIEW) {
|
||||||
struct wlr_xwayland_surface *surf =
|
struct wlr_xwayland_surface *surf =
|
||||||
wlr_xwayland_surface_from_wlr_surface(view->surface);
|
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 *
|
static struct wlr_xwayland_surface *
|
||||||
top_parent_of(struct view *view)
|
top_parent_of(struct view *view)
|
||||||
{
|
{
|
||||||
|
|
@ -505,7 +515,7 @@ xwayland_view_unmap(struct view *view, bool client_request)
|
||||||
view->mapped = false;
|
view->mapped = false;
|
||||||
wl_list_remove(&view->commit.link);
|
wl_list_remove(&view->commit.link);
|
||||||
wlr_scene_node_set_enabled(&view->scene_tree->node, false);
|
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
|
* 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,
|
.get_root = xwayland_view_get_root,
|
||||||
.append_children = xwayland_view_append_children,
|
.append_children = xwayland_view_append_children,
|
||||||
.get_size_hints = xwayland_view_get_size_hints,
|
.get_size_hints = xwayland_view_get_size_hints,
|
||||||
|
.wants_focus = xwayland_view_wants_focus,
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue