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); +}