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>
This commit is contained in:
committed by
Kristian Høgsberg
parent
e844bf2a58
commit
01388e253e
@@ -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);
|
||||||
|
|||||||
+48
-18
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user