From cc3d30c28bb645a1a4e48814346e052115a74210 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Tue, 19 Feb 2019 17:45:26 +0100 Subject: [PATCH] shell: Keep window 'activated' state if child has focus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Popups should have keyboard focus when active, but the toplevel window should still appear "active". Make sure this is the case by changing the "active" tracking to see whether any child surface has keyboard focus. Signed-off-by: Jonas Ã…dahl --- desktop-shell/shell.c | 61 ++++++++++++++++++++++++++++++++++-- include/libweston/desktop.h | 8 +++++ libweston/desktop/internal.h | 2 -- libweston/desktop/surface.c | 14 ++++++++- 4 files changed, 80 insertions(+), 5 deletions(-) diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 9140bed2..c7ab2256 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -1386,18 +1386,75 @@ handle_pointer_focus(struct wl_listener *listener, void *data) weston_desktop_client_ping(client); } +static void +has_keyboard_focused_child_callback(struct weston_desktop_surface *surface, + void *user_data); + +static void +has_keyboard_focused_child_callback(struct weston_desktop_surface *surface, + void *user_data) +{ + struct weston_surface *es = weston_desktop_surface_get_surface(surface); + struct shell_surface *shsurf = get_shell_surface(es); + bool *has_keyboard_focus = user_data; + + if (shsurf->focus_count > 0) { + *has_keyboard_focus = true; + return; + } + + weston_desktop_surface_foreach_child(shsurf->desktop_surface, + has_keyboard_focused_child_callback, + &has_keyboard_focus); +} + +static bool +has_keyboard_focused_child(struct shell_surface *shsurf) +{ + bool has_keyboard_focus = false; + + if (shsurf->focus_count > 0) + return true; + + weston_desktop_surface_foreach_child(shsurf->desktop_surface, + has_keyboard_focused_child_callback, + &has_keyboard_focus); + + return has_keyboard_focus; +} + +static void +sync_surface_activated_state(struct shell_surface *shsurf) +{ + struct weston_desktop_surface *surface = shsurf->desktop_surface; + struct weston_desktop_surface *parent; + struct weston_surface *parent_surface; + + parent = weston_desktop_surface_get_parent(surface); + if (parent) { + parent_surface = weston_desktop_surface_get_surface(parent); + sync_surface_activated_state(get_shell_surface(parent_surface)); + return; + } + + if (has_keyboard_focused_child(shsurf)) + weston_desktop_surface_set_activated(surface, true); + else + weston_desktop_surface_set_activated(surface, false); +} + static void shell_surface_deactivate(struct shell_surface *shsurf) { if (--shsurf->focus_count == 0) - weston_desktop_surface_set_activated(shsurf->desktop_surface, false); + sync_surface_activated_state(shsurf); } static void shell_surface_activate(struct shell_surface *shsurf) { if (shsurf->focus_count++ == 0) - weston_desktop_surface_set_activated(shsurf->desktop_surface, true); + sync_surface_activated_state(shsurf); } /* The surface will be inserted into the list immediately after the link diff --git a/include/libweston/desktop.h b/include/libweston/desktop.h index dd09c887..465c9f8f 100644 --- a/include/libweston/desktop.h +++ b/include/libweston/desktop.h @@ -216,6 +216,14 @@ struct weston_size weston_desktop_surface_get_max_size(struct weston_desktop_surface *surface); struct weston_size weston_desktop_surface_get_min_size(struct weston_desktop_surface *surface); +struct weston_desktop_surface * +weston_desktop_surface_get_parent(struct weston_desktop_surface *surface); +void +weston_desktop_surface_foreach_child(struct weston_desktop_surface *surface, + void (* callback)(struct weston_desktop_surface *child, + void *user_data), + void *user_data); + bool weston_desktop_window_menu_supported(struct weston_desktop *desktop); diff --git a/libweston/desktop/internal.h b/libweston/desktop/internal.h index c6c93d4a..95023f47 100644 --- a/libweston/desktop/internal.h +++ b/libweston/desktop/internal.h @@ -195,8 +195,6 @@ const struct weston_desktop_surface_implementation * weston_desktop_surface_get_implementation(struct weston_desktop_surface *surface); void * weston_desktop_surface_get_implementation_data(struct weston_desktop_surface *surface); -struct weston_desktop_surface * -weston_desktop_surface_get_parent(struct weston_desktop_surface *surface); bool weston_desktop_surface_get_grab(struct weston_desktop_surface *surface); diff --git a/libweston/desktop/surface.c b/libweston/desktop/surface.c index 4f1398c7..52e467fd 100644 --- a/libweston/desktop/surface.c +++ b/libweston/desktop/surface.c @@ -569,7 +569,7 @@ weston_desktop_surface_get_implementation_data(struct weston_desktop_surface *su return surface->implementation_data; } -struct weston_desktop_surface * +WL_EXPORT struct weston_desktop_surface * weston_desktop_surface_get_parent(struct weston_desktop_surface *surface) { return surface->parent; @@ -878,3 +878,15 @@ weston_desktop_surface_popup_dismiss(struct weston_desktop_surface *surface) wl_list_init(&surface->grab_link); weston_desktop_surface_close(surface); } + +WL_EXPORT void +weston_desktop_surface_foreach_child(struct weston_desktop_surface *surface, + void (* callback)(struct weston_desktop_surface *child, + void *user_data), + void *user_data) +{ + struct weston_desktop_surface *child; + + wl_list_for_each(child, &surface->children_list, children_link) + callback(child, user_data); +}