shell: keyboard focus and restacking fixes for sub-surfaces

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.

- The workspace_manager.move_surface request can accept also
  sub-surfaces, and it will move the corresponding main 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()

Changes in v3:
- Renamed weston_surface_get_parent() to
  weston_surface_get_main_surface() to be more explicit that this is
  about sub-surfaces
- Fixed move_surface_to_workspace() to handle keyboard focus on a
  sub-surface.
- Used a temporary variable in several places to clarify code, instead
  of reassigning a variable.
- Fixed workspace_manager_move_surface() to deal with sub-surfaces.

Signed-off-by: Pekka Paalanen <ppaalanen@gmail.com>
dev
Pekka Paalanen 12 years ago committed by Kristian Høgsberg
parent e844bf2a58
commit 01388e253e
  1. 11
      src/compositor.c
  2. 3
      src/compositor.h
  3. 66
      src/shell.c

@ -1924,6 +1924,17 @@ weston_surface_to_subsurface(struct weston_surface *surface)
return NULL; return NULL;
} }
WL_EXPORT struct weston_surface *
weston_surface_get_main_surface(struct weston_surface *surface)
{
struct weston_subsurface *sub;
while (surface && (sub = weston_surface_to_subsurface(surface)))
surface = sub->parent;
return surface;
}
static void static void
subsurface_set_position(struct wl_client *client, subsurface_set_position(struct wl_client *client,
struct wl_resource *resource, int32_t x, int32_t y) struct wl_resource *resource, int32_t x, int32_t y)

@ -976,6 +976,9 @@ weston_surface_move_to_plane(struct weston_surface *surface,
void void
weston_surface_unmap(struct weston_surface *surface); weston_surface_unmap(struct weston_surface *surface);
struct weston_surface *
weston_surface_get_main_surface(struct weston_surface *surface);
void void
weston_buffer_reference(struct weston_buffer_reference *ref, weston_buffer_reference(struct weston_buffer_reference *ref,
struct wl_buffer *buffer); struct wl_buffer *buffer);

@ -435,17 +435,24 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
struct focus_state, struct focus_state,
surface_destroy_listener); surface_destroy_listener);
struct desktop_shell *shell; struct desktop_shell *shell;
struct weston_surface *main_surface;
struct weston_surface *surface, *next; struct weston_surface *surface, *next;
main_surface = weston_surface_get_main_surface(state->keyboard_focus);
next = NULL; next = NULL;
wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) { wl_list_for_each(surface, &state->ws->layer.surface_list, layer_link) {
if (surface == state->keyboard_focus) if (surface == main_surface)
continue; continue;
next = surface; next = surface;
break; break;
} }
/* if the focus was a sub-surface, activate its main surface */
if (main_surface != state->keyboard_focus)
next = main_surface;
if (next) { if (next) {
shell = state->seat->compositor->shell_interface.shell; shell = state->seat->compositor->shell_interface.shell;
activate(shell, next, state->seat); activate(shell, next, state->seat);
@ -883,6 +890,9 @@ move_surface_to_workspace(struct desktop_shell *shell,
struct workspace *from; struct workspace *from;
struct workspace *to; struct workspace *to;
struct weston_seat *seat; struct weston_seat *seat;
struct weston_surface *focus;
assert(weston_surface_get_main_surface(surface) == surface);
if (workspace == shell->workspaces.current) if (workspace == shell->workspaces.current)
return; return;
@ -897,9 +907,14 @@ move_surface_to_workspace(struct desktop_shell *shell,
wl_list_insert(&to->layer.surface_list, &surface->layer_link); wl_list_insert(&to->layer.surface_list, &surface->layer_link);
drop_focus_state(shell, from, surface); drop_focus_state(shell, from, surface);
wl_list_for_each(seat, &shell->compositor->seat_list, link) wl_list_for_each(seat, &shell->compositor->seat_list, link) {
if (seat->keyboard && seat->keyboard->focus == surface) if (!seat->keyboard)
continue;
focus = weston_surface_get_main_surface(seat->keyboard->focus);
if (focus == surface)
weston_keyboard_set_focus(seat->keyboard, NULL); weston_keyboard_set_focus(seat->keyboard, NULL);
}
weston_surface_damage_below(surface); weston_surface_damage_below(surface);
} }
@ -909,13 +924,13 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell,
struct weston_seat *seat, struct weston_seat *seat,
unsigned int index) unsigned int index)
{ {
struct weston_surface *surface = struct weston_surface *surface;
(struct weston_surface *) seat->keyboard->focus;
struct shell_surface *shsurf; struct shell_surface *shsurf;
struct workspace *from; struct workspace *from;
struct workspace *to; struct workspace *to;
struct focus_state *state; struct focus_state *state;
surface = weston_surface_get_main_surface(seat->keyboard->focus);
if (surface == NULL || if (surface == NULL ||
index == shell->workspaces.current) index == shell->workspaces.current)
return; return;
@ -973,8 +988,10 @@ workspace_manager_move_surface(struct wl_client *client,
struct desktop_shell *shell = resource->data; struct desktop_shell *shell = resource->data;
struct weston_surface *surface = struct weston_surface *surface =
(struct weston_surface *) surface_resource; (struct weston_surface *) surface_resource;
struct weston_surface *main_surface;
move_surface_to_workspace(shell, surface, workspace); main_surface = weston_surface_get_main_surface(surface);
move_surface_to_workspace(shell, main_surface, workspace);
} }
static const struct workspace_manager_interface workspace_manager_implementation = { static const struct workspace_manager_interface workspace_manager_implementation = {
@ -2505,10 +2522,12 @@ get_shell_surface_type(struct weston_surface *surface)
static void static void
move_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data) move_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
{ {
struct weston_surface *surface = struct weston_surface *focus =
(struct weston_surface *) seat->pointer->focus; (struct weston_surface *) seat->pointer->focus;
struct weston_surface *surface;
struct shell_surface *shsurf; struct shell_surface *shsurf;
surface = weston_surface_get_main_surface(focus);
if (surface == NULL) if (surface == NULL)
return; return;
@ -2523,12 +2542,14 @@ move_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *dat
static void static void
resize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data) resize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
{ {
struct weston_surface *surface = struct weston_surface *focus =
(struct weston_surface *) seat->pointer->focus; (struct weston_surface *) seat->pointer->focus;
struct weston_surface *surface;
uint32_t edges = 0; uint32_t edges = 0;
int32_t x, y; int32_t x, y;
struct shell_surface *shsurf; struct shell_surface *shsurf;
surface = weston_surface_get_main_surface(focus);
if (surface == NULL) if (surface == NULL)
return; return;
@ -2565,9 +2586,12 @@ surface_opacity_binding(struct weston_seat *seat, uint32_t time, uint32_t axis,
{ {
float step = 0.005; float step = 0.005;
struct shell_surface *shsurf; struct shell_surface *shsurf;
struct weston_surface *surface = struct weston_surface *focus =
(struct weston_surface *) seat->pointer->focus; (struct weston_surface *) seat->pointer->focus;
struct weston_surface *surface;
/* XXX: broken for windows containing sub-surfaces */
surface = weston_surface_get_main_surface(focus);
if (surface == NULL) if (surface == NULL)
return; return;
@ -2784,10 +2808,12 @@ static void
rotate_binding(struct weston_seat *seat, uint32_t time, uint32_t button, rotate_binding(struct weston_seat *seat, uint32_t time, uint32_t button,
void *data) void *data)
{ {
struct weston_surface *base_surface = struct weston_surface *focus =
(struct weston_surface *) seat->pointer->focus; (struct weston_surface *) seat->pointer->focus;
struct weston_surface *base_surface;
struct shell_surface *surface; struct shell_surface *surface;
base_surface = weston_surface_get_main_surface(focus);
if (base_surface == NULL) if (base_surface == NULL)
return; return;
@ -2816,9 +2842,12 @@ static void
activate(struct desktop_shell *shell, struct weston_surface *es, activate(struct desktop_shell *shell, struct weston_surface *es,
struct weston_seat *seat) struct weston_seat *seat)
{ {
struct weston_surface *main_surface;
struct focus_state *state; struct focus_state *state;
struct workspace *ws; struct workspace *ws;
main_surface = weston_surface_get_main_surface(es);
weston_surface_activate(es, seat); weston_surface_activate(es, seat);
state = ensure_focus_state(shell, seat); state = ensure_focus_state(shell, seat);
@ -2830,15 +2859,15 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
wl_signal_add(&es->resource.destroy_signal, wl_signal_add(&es->resource.destroy_signal,
&state->surface_destroy_listener); &state->surface_destroy_listener);
switch (get_shell_surface_type(es)) { switch (get_shell_surface_type(main_surface)) {
case SHELL_SURFACE_FULLSCREEN: case SHELL_SURFACE_FULLSCREEN:
/* should on top of panels */ /* should on top of panels */
shell_stack_fullscreen(get_shell_surface(es)); shell_stack_fullscreen(get_shell_surface(main_surface));
shell_configure_fullscreen(get_shell_surface(es)); shell_configure_fullscreen(get_shell_surface(main_surface));
break; break;
default: default:
ws = get_current_workspace(shell); ws = get_current_workspace(shell);
weston_surface_restack(es, &ws->layer.surface_list); weston_surface_restack(main_surface, &ws->layer.surface_list);
break; break;
} }
} }
@ -2867,16 +2896,17 @@ click_to_activate_binding(struct weston_seat *seat, uint32_t time, uint32_t butt
struct weston_seat *ws = (struct weston_seat *) seat; struct weston_seat *ws = (struct weston_seat *) seat;
struct desktop_shell *shell = data; struct desktop_shell *shell = data;
struct weston_surface *focus; struct weston_surface *focus;
struct weston_surface *upper; struct weston_surface *main_surface;
focus = (struct weston_surface *) seat->pointer->focus; focus = (struct weston_surface *) seat->pointer->focus;
if (!focus) if (!focus)
return; return;
if (is_black_surface(focus, &upper)) if (is_black_surface(focus, &main_surface))
focus = upper; focus = main_surface;
if (get_shell_surface_type(focus) == SHELL_SURFACE_NONE) main_surface = weston_surface_get_main_surface(focus);
if (get_shell_surface_type(main_surface) == SHELL_SURFACE_NONE)
return; return;
if (seat->pointer->grab == &seat->pointer->default_grab) if (seat->pointer->grab == &seat->pointer->default_grab)

Loading…
Cancel
Save