[RFC Weston 05/10] shell: keyboard focus and restacking fixes for sub-surfaces
Pekka Paalanen
ppaalanen at gmail.com
Fri Feb 22 07:07:49 PST 2013
The shell needs to redirect some actions to the parent surface, when
they originally target a sub-surface. This patch implements the
following:
- Move, resize, and rotate bindings always target the parent surface.
- Opacity (full-surface alpha) binding targets the parent surface. This
is broken, because it should change the opacity of the whole compound
window, which is difficult to implement in the renderer.
- click_to_activate_binding() needs to check the shell surface type from
the main surface, because sub-surface would produce SHELL_SURFACE_NONE
and prevent activation.
- Also activate() needs to check the type from the main surface, and
restack the main surface. Keyboard focus is assigned to the original
(sub-)surface.
- focus_state_surface_destroy() needs to handle sub-surfaces: only the
main surface will be in a layer list. If the destroyed surface is
indeed a sub-surface, activate the main surface next. This way a
client that destroys a focused sub-surface still retains focus in the
same window.
workspace_manager_move_surface(): is it expected and legal for this to
be called for sub-surfaces?
take_surface_to_workspace_by_seat(): I guess this really doesn't need
the weston_surface_get_parent call, since keyboard focus is supposed to
never be on a sub-surface.
move_surface_to_workspace(): like above, should be ok, as keyboard focus
is not a sub-surface.
Changes in v2:
- do not special-case keyboard focus for sub-surfaces
- fix surface type checks for sub-surfaces in shell, fix restacking of
sub-surfaces in shell, fix focus_state_surface_destroy()
---
src/compositor.c | 11 +++++++++++
src/compositor.h | 3 +++
src/shell.c | 37 ++++++++++++++++++++++++++++---------
3 files changed, 42 insertions(+), 9 deletions(-)
diff --git a/src/compositor.c b/src/compositor.c
index 5db255a..cadab92 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -1854,6 +1854,17 @@ weston_surface_to_subsurface(struct weston_surface *surface)
return NULL;
}
+WL_EXPORT struct weston_surface *
+weston_surface_get_parent(struct weston_surface *surface)
+{
+ struct weston_subsurface *sub;
+
+ while (surface && (sub = weston_surface_to_subsurface(surface)))
+ surface = sub->parent;
+
+ return surface;
+}
+
static void
subsurface_set_position(struct wl_client *client,
struct wl_resource *resource, int32_t x, int32_t y)
diff --git a/src/compositor.h b/src/compositor.h
index d3c4f2d..861b7c3 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -774,6 +774,9 @@ weston_surface_move_to_plane(struct weston_surface *surface,
void
weston_surface_unmap(struct weston_surface *surface);
+struct weston_surface *
+weston_surface_get_parent(struct weston_surface *surface);
+
void
weston_buffer_post_release(struct wl_buffer *buffer);
diff --git a/src/shell.c b/src/shell.c
index 74b4ab6..c8f20ec 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -419,17 +419,24 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
struct focus_state,
surface_destroy_listener);
struct desktop_shell *shell;
+ struct weston_surface *main_surface;
struct weston_surface *surface, *next;
+ main_surface = weston_surface_get_parent(state->keyboard_focus);
+
next = NULL;
wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
- if (surface == state->keyboard_focus)
+ if (surface == main_surface)
continue;
next = surface;
break;
}
+ /* if the focus was a sub-surface, activate its main surface */
+ if (main_surface != state->keyboard_focus)
+ next = main_surface;
+
if (next) {
shell = state->seat->compositor->shell_interface.shell;
activate(shell, next, state->seat);
@@ -882,6 +889,7 @@ move_surface_to_workspace(struct desktop_shell *shell,
wl_list_insert(&to->layer.surface_list, &surface->layer_link);
drop_focus_state(shell, from, surface);
+ /* XXX: what about foci on sub-surfaces? */
wl_list_for_each(seat, &shell->compositor->seat_list, link)
if (seat->has_keyboard &&
seat->keyboard.keyboard.focus == &surface->surface)
@@ -903,6 +911,7 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell,
struct workspace *to;
struct focus_state *state;
+ surface = weston_surface_get_parent(surface);
if (surface == NULL ||
index == shell->workspaces.current)
return;
@@ -961,6 +970,7 @@ workspace_manager_move_surface(struct wl_client *client,
struct weston_surface *surface =
(struct weston_surface *) surface_resource;
+ /* XXX: for a sub-surface, move the parent surface or fail? */
move_surface_to_workspace(shell, surface, workspace);
}
@@ -2417,6 +2427,7 @@ move_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
(struct weston_surface *) seat->pointer->focus;
struct shell_surface *shsurf;
+ surface = weston_surface_get_parent(surface);
if (surface == NULL)
return;
@@ -2436,6 +2447,7 @@ resize_binding(struct wl_seat *seat, uint32_t time, uint32_t button, void *data)
int32_t x, y;
struct shell_surface *shsurf;
+ surface = weston_surface_get_parent(surface);
if (surface == NULL)
return;
@@ -2474,6 +2486,8 @@ surface_opacity_binding(struct wl_seat *seat, uint32_t time, uint32_t axis,
struct weston_surface *surface =
(struct weston_surface *) seat->pointer->focus;
+ /* XXX: broken for windows containing sub-surfaces */
+ surface = weston_surface_get_parent(surface);
if (surface == NULL)
return;
@@ -2695,6 +2709,7 @@ rotate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
(struct weston_surface *) seat->pointer->focus;
struct shell_surface *surface;
+ base_surface = weston_surface_get_parent(base_surface);
if (base_surface == NULL)
return;
@@ -2722,9 +2737,12 @@ static void
activate(struct desktop_shell *shell, struct weston_surface *es,
struct weston_seat *seat)
{
+ struct weston_surface *main_surface;
struct focus_state *state;
struct workspace *ws;
+ main_surface = weston_surface_get_parent(es);
+
weston_surface_activate(es, seat);
state = ensure_focus_state(shell, seat);
@@ -2736,15 +2754,15 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
wl_signal_add(&es->surface.resource.destroy_signal,
&state->surface_destroy_listener);
- switch (get_shell_surface_type(es)) {
+ switch (get_shell_surface_type(main_surface)) {
case SHELL_SURFACE_FULLSCREEN:
/* should on top of panels */
- shell_stack_fullscreen(get_shell_surface(es));
- shell_configure_fullscreen(get_shell_surface(es));
+ shell_stack_fullscreen(get_shell_surface(main_surface));
+ shell_configure_fullscreen(get_shell_surface(main_surface));
break;
default:
ws = get_current_workspace(shell);
- weston_surface_restack(es, &ws->layer.surface_list);
+ weston_surface_restack(main_surface, &ws->layer.surface_list);
break;
}
}
@@ -2773,16 +2791,17 @@ click_to_activate_binding(struct wl_seat *seat, uint32_t time, uint32_t button,
struct weston_seat *ws = (struct weston_seat *) seat;
struct desktop_shell *shell = data;
struct weston_surface *focus;
- struct weston_surface *upper;
+ struct weston_surface *main_surface;
focus = (struct weston_surface *) seat->pointer->focus;
if (!focus)
return;
- if (is_black_surface(focus, &upper))
- focus = upper;
+ if (is_black_surface(focus, &main_surface))
+ focus = main_surface;
- if (get_shell_surface_type(focus) == SHELL_SURFACE_NONE)
+ main_surface = weston_surface_get_parent(focus);
+ if (get_shell_surface_type(main_surface) == SHELL_SURFACE_NONE)
return;
if (seat->pointer->grab == &seat->pointer->default_grab)
--
1.7.12.4
More information about the wayland-devel
mailing list