From bb676013ed1b1b48847694a2159e3b009636b181 Mon Sep 17 00:00:00 2001 From: Markus Ongyerth Date: Sun, 25 Feb 2018 09:57:30 +0100 Subject: [PATCH] add xwayland unmanaged tests to support dmenu This adds `wlr_xwayland_surface_is_unamanged`, to allow compositors more fine grained control over XWayland focus. A surface that is unmanaged should not receive focus, while other windows that are just override redirect may want it (dmenu). The way unamanged is determined is taken from wlc. --- include/rootston/desktop.h | 1 + include/wlr/xwayland.h | 1 + include/wlr/xwm.h | 9 +++++++++ rootston/desktop.c | 6 +++++- rootston/seat.c | 2 +- rootston/xwayland.c | 2 ++ xwayland/xwayland.c | 21 +++++++++++++++++++++ xwayland/xwm.c | 20 ++++++++++++++++++++ 8 files changed, 60 insertions(+), 2 deletions(-) diff --git a/include/rootston/desktop.h b/include/rootston/desktop.h index ab3ae61a..467de8ab 100644 --- a/include/rootston/desktop.h +++ b/include/rootston/desktop.h @@ -78,6 +78,7 @@ void view_apply_damage(struct roots_view *view); void view_damage_whole(struct roots_view *view); void view_update_position(struct roots_view *view, double x, double y); void view_update_size(struct roots_view *view, uint32_t width, uint32_t height); +void view_initial_focus(struct roots_view *view); void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data); void handle_xdg_shell_surface(struct wl_listener *listener, void *data); diff --git a/include/wlr/xwayland.h b/include/wlr/xwayland.h index ad7ceb83..0d4b91ed 100644 --- a/include/wlr/xwayland.h +++ b/include/wlr/xwayland.h @@ -186,4 +186,5 @@ void wlr_xwayland_surface_set_fullscreen(struct wlr_xwayland_surface *surface, void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland, struct wlr_seat *seat); +bool wlr_xwayland_surface_is_unmanaged(const struct wlr_xwayland_surface *surface); #endif diff --git a/include/wlr/xwm.h b/include/wlr/xwm.h index 65681607..7d518f7e 100644 --- a/include/wlr/xwm.h +++ b/include/wlr/xwm.h @@ -39,6 +39,12 @@ enum atom_name { INCR, TEXT, TIMESTAMP, + NET_WM_WINDOW_TYPE_UTILITY, + NET_WM_WINDOW_TYPE_TOOLTIP, + NET_WM_WINDOW_TYPE_DND, + NET_WM_WINDOW_TYPE_DROPDOWN_MENU, + NET_WM_WINDOW_TYPE_POPUP_MENU, + NET_WM_WINDOW_TYPE_COMBO, ATOM_LAST, }; @@ -113,4 +119,7 @@ void xwm_selection_finish(struct wlr_xwm *xwm); void xwm_set_seat(struct wlr_xwm *xwm, struct wlr_seat *seat); +bool wlr_xwm_atoms_contains(struct wlr_xwm *xwm, xcb_atom_t *atoms, + size_t num_atoms, enum atom_name needle); + #endif diff --git a/rootston/desktop.c b/rootston/desktop.c index 8ac741bb..a8b070ce 100644 --- a/rootston/desktop.c +++ b/rootston/desktop.c @@ -426,13 +426,17 @@ void view_init(struct roots_view *view, struct roots_desktop *desktop) { view_damage_whole(view); } -void view_setup(struct roots_view *view) { +void view_initial_focus(struct roots_view *view) { struct roots_input *input = view->desktop->server->input; // TODO what seat gets focus? the one with the last input event? struct roots_seat *seat; wl_list_for_each(seat, &input->seats, link) { roots_seat_set_focus(seat, view); } +} + +void view_setup(struct roots_view *view) { + view_initial_focus(view); view_center(view); view_update_output(view, NULL); diff --git a/rootston/seat.c b/rootston/seat.c index 1b7d05c4..9acbb737 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -721,7 +721,7 @@ void roots_seat_set_focus(struct roots_seat *seat, struct roots_view *view) { #ifdef WLR_HAS_XWAYLAND if (view && view->type == ROOTS_XWAYLAND_VIEW && - view->xwayland_surface->override_redirect) { + wlr_xwayland_surface_is_unmanaged(view->xwayland_surface)) { return; } #endif diff --git a/rootston/xwayland.c b/rootston/xwayland.c index e9e0d5e0..1aa5a96c 100644 --- a/rootston/xwayland.c +++ b/rootston/xwayland.c @@ -350,5 +350,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data) { } view_setup(view); + } else { + view_initial_focus(view); } } diff --git a/xwayland/xwayland.c b/xwayland/xwayland.c index 1d935180..8dffd040 100644 --- a/xwayland/xwayland.c +++ b/xwayland/xwayland.c @@ -405,3 +405,24 @@ void wlr_xwayland_set_seat(struct wlr_xwayland *xwayland, xwayland->seat_destroy.notify = wlr_xwayland_handle_seat_destroy; wl_signal_add(&seat->events.destroy, &xwayland->seat_destroy); } + + +bool wlr_xwayland_surface_is_unmanaged(const struct wlr_xwayland_surface *surface) { + static enum atom_name needles[] = { + NET_WM_WINDOW_TYPE_UTILITY, + NET_WM_WINDOW_TYPE_TOOLTIP, + NET_WM_WINDOW_TYPE_DND, + NET_WM_WINDOW_TYPE_DROPDOWN_MENU, + NET_WM_WINDOW_TYPE_POPUP_MENU, + NET_WM_WINDOW_TYPE_COMBO, + }; + + for (size_t i = 0; i < sizeof(needles) / sizeof(needles[0]); ++i) { + if (wlr_xwm_atoms_contains(surface->xwm, surface->window_type, + surface->window_type_len, needles[i])) { + return true; + } + } + + return false; +} diff --git a/xwayland/xwm.c b/xwayland/xwm.c index 0d957260..c41b8d47 100644 --- a/xwayland/xwm.c +++ b/xwayland/xwm.c @@ -54,6 +54,12 @@ const char *atom_map[ATOM_LAST] = { "INCR", "TEXT", "TIMESTAMP", + "_NET_WM_WINDOW_TYPE_UTILITY", + "_NET_WM_WINDOW_TYPE_TOOLTIP", + "_NET_WM_WINDOW_TYPE_DND", + "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", + "_NET_WM_WINDOW_TYPE_POPUP_MENU", + "_NET_WM_WINDOW_TYPE_COMBO", }; /* General helpers */ @@ -1446,3 +1452,17 @@ void wlr_xwayland_surface_set_fullscreen(struct wlr_xwayland_surface *surface, xsurface_set_net_wm_state(surface); xcb_flush(surface->xwm->xcb_conn); } + +bool wlr_xwm_atoms_contains(struct wlr_xwm *xwm, xcb_atom_t *atoms, + size_t num_atoms, enum atom_name needle) { + xcb_atom_t atom = xwm->atoms[needle]; + + for (size_t i = 0; i < num_atoms; ++i) { + if (atom == atoms[i]) { + return true; + } + } + + return false; +} +