animation, shell: add kbd focus change animation

When enabled, this will make all but the keyboard-focused window dim.
Also the background gets dimmed, if there are any windows open. The
panel is not dimmed.

When the keyboard focus changes, the change in dimming is animated.

The dimming is implemented with transparent solid-color surfaces, two at
most. The net effect of two overlapping dim surfaces is kept constant
during animations (stable fade animation).

There is a new weston.ini option "focus-animation", that defaults to
none, and can be set to "dim-layer" to enable the focus change
animation.

[pq: Sliced, squashed, and rebased the patch series. Fixed surface alpha
interaction with the switcher. Wrote the commit message.]

[pochu: rebased, ported to weston_view]
dev
Louis-Francis Ratté-Boulianne 11 years ago committed by Kristian Høgsberg
parent dd8b88d102
commit b482dbd7eb
  1. 53
      src/animation.c
  2. 8
      src/compositor.h
  3. 262
      src/shell.c

@ -127,9 +127,10 @@ struct weston_view_animation {
weston_view_animation_frame_func_t reset; weston_view_animation_frame_func_t reset;
weston_view_animation_done_func_t done; weston_view_animation_done_func_t done;
void *data; void *data;
void *private;
}; };
static void WL_EXPORT void
weston_view_animation_destroy(struct weston_view_animation *animation) weston_view_animation_destroy(struct weston_view_animation *animation)
{ {
wl_list_remove(&animation->animation.link); wl_list_remove(&animation->animation.link);
@ -185,7 +186,8 @@ weston_view_animation_run(struct weston_view *view,
weston_view_animation_frame_func_t frame, weston_view_animation_frame_func_t frame,
weston_view_animation_frame_func_t reset, weston_view_animation_frame_func_t reset,
weston_view_animation_done_func_t done, weston_view_animation_done_func_t done,
void *data) void *data,
void *private)
{ {
struct weston_view_animation *animation; struct weston_view_animation *animation;
@ -200,6 +202,7 @@ weston_view_animation_run(struct weston_view *view,
animation->data = data; animation->data = data;
animation->start = start; animation->start = start;
animation->stop = stop; animation->stop = stop;
animation->private = private;
weston_matrix_init(&animation->transform.matrix); weston_matrix_init(&animation->transform.matrix);
wl_list_insert(&view->geometry.transformation_list, wl_list_insert(&view->geometry.transformation_list,
&animation->transform.link); &animation->transform.link);
@ -257,7 +260,7 @@ weston_zoom_run(struct weston_view *view, float start, float stop,
zoom = weston_view_animation_run(view, start, stop, zoom = weston_view_animation_run(view, start, stop,
zoom_frame, reset_alpha, zoom_frame, reset_alpha,
done, data); done, data, NULL);
weston_spring_init(&zoom->spring, 300.0, start, stop); weston_spring_init(&zoom->spring, 300.0, start, stop);
zoom->spring.friction = 1400; zoom->spring.friction = 1400;
@ -286,7 +289,7 @@ weston_fade_run(struct weston_view *view,
fade = weston_view_animation_run(view, 0, end, fade = weston_view_animation_run(view, 0, end,
fade_frame, reset_alpha, fade_frame, reset_alpha,
done, data); done, data, NULL);
weston_spring_init(&fade->spring, k, start, end); weston_spring_init(&fade->spring, k, start, end);
@ -304,6 +307,46 @@ weston_fade_update(struct weston_view_animation *fade, float target)
fade->spring.target = target; fade->spring.target = target;
} }
static void
stable_fade_frame(struct weston_view_animation *animation)
{
struct weston_view *back_view;
if (animation->spring.current > 0.999)
animation->view->alpha = 1;
else if (animation->spring.current < 0.001 )
animation->view->alpha = 0;
else
animation->view->alpha = animation->spring.current;
back_view = (struct weston_view *) animation->private;
back_view->alpha =
(animation->spring.target - animation->view->alpha) /
(1.0 - animation->view->alpha);
weston_view_geometry_dirty(back_view);
}
WL_EXPORT struct weston_view_animation *
weston_stable_fade_run(struct weston_view *front_view, float start,
struct weston_view *back_view, float end,
weston_view_animation_done_func_t done, void *data)
{
struct weston_view_animation *fade;
fade = weston_view_animation_run(front_view, 0, 0,
stable_fade_frame, NULL,
done, data, back_view);
weston_spring_init(&fade->spring, 400, start, end);
fade->spring.friction = 1150;
front_view->alpha = start;
back_view->alpha = end;
return fade;
}
static void static void
slide_frame(struct weston_view_animation *animation) slide_frame(struct weston_view_animation *animation)
{ {
@ -324,7 +367,7 @@ weston_slide_run(struct weston_view *view, float start, float stop,
animation = weston_view_animation_run(view, start, stop, animation = weston_view_animation_run(view, start, stop,
slide_frame, NULL, done, slide_frame, NULL, done,
data); data, NULL);
if (!animation) if (!animation)
return NULL; return NULL;

@ -1271,6 +1271,9 @@ weston_watch_process(struct weston_process *process);
struct weston_view_animation; struct weston_view_animation;
typedef void (*weston_view_animation_done_func_t)(struct weston_view_animation *animation, void *data); typedef void (*weston_view_animation_done_func_t)(struct weston_view_animation *animation, void *data);
void
weston_view_animation_destroy(struct weston_view_animation *animation);
struct weston_view_animation * struct weston_view_animation *
weston_zoom_run(struct weston_view *view, float start, float stop, weston_zoom_run(struct weston_view *view, float start, float stop,
weston_view_animation_done_func_t done, void *data); weston_view_animation_done_func_t done, void *data);
@ -1282,6 +1285,11 @@ weston_fade_run(struct weston_view *view,
void void
weston_fade_update(struct weston_view_animation *fade, float target); weston_fade_update(struct weston_view_animation *fade, float target);
struct weston_view_animation *
weston_stable_fade_run(struct weston_view *front_view, float start,
struct weston_view *back_view, float end,
weston_view_animation_done_func_t done, void *data);
struct weston_view_animation * struct weston_view_animation *
weston_slide_run(struct weston_view *view, float start, float stop, weston_slide_run(struct weston_view *view, float start, float stop,
weston_view_animation_done_func_t done, void *data); weston_view_animation_done_func_t done, void *data);

@ -47,7 +47,8 @@ enum animation_type {
ANIMATION_NONE, ANIMATION_NONE,
ANIMATION_ZOOM, ANIMATION_ZOOM,
ANIMATION_FADE ANIMATION_FADE,
ANIMATION_DIM_LAYER,
}; };
enum fade_type { enum fade_type {
@ -64,11 +65,21 @@ struct focus_state {
struct wl_listener surface_destroy_listener; struct wl_listener surface_destroy_listener;
}; };
struct focus_surface {
struct weston_surface *surface;
struct weston_view *view;
struct weston_transform workspace_transform;
};
struct workspace { struct workspace {
struct weston_layer layer; struct weston_layer layer;
struct wl_list focus_list; struct wl_list focus_list;
struct wl_listener seat_destroyed_listener; struct wl_listener seat_destroyed_listener;
struct focus_surface *fsurf_front;
struct focus_surface *fsurf_back;
struct weston_view_animation *focus_animation;
}; };
struct input_panel_surface { struct input_panel_surface {
@ -172,6 +183,7 @@ struct desktop_shell {
uint32_t binding_modifier; uint32_t binding_modifier;
enum animation_type win_animation_type; enum animation_type win_animation_type;
enum animation_type startup_animation_type; enum animation_type startup_animation_type;
enum animation_type focus_animation_type;
struct wl_listener output_create_listener; struct wl_listener output_create_listener;
struct wl_list output_list; struct wl_list output_list;
@ -459,6 +471,8 @@ get_animation_type(char *animation)
return ANIMATION_ZOOM; return ANIMATION_ZOOM;
else if (!strcmp("fade", animation)) else if (!strcmp("fade", animation))
return ANIMATION_FADE; return ANIMATION_FADE;
else if (!strcmp("dim-layer", animation))
return ANIMATION_DIM_LAYER;
else else
return ANIMATION_NONE; return ANIMATION_NONE;
} }
@ -492,12 +506,103 @@ shell_configuration(struct desktop_shell *shell)
free(s); free(s);
if (shell->startup_animation_type == ANIMATION_ZOOM) if (shell->startup_animation_type == ANIMATION_ZOOM)
shell->startup_animation_type = ANIMATION_NONE; shell->startup_animation_type = ANIMATION_NONE;
weston_config_section_get_string(section, "focus-animation", &s, "none");
shell->focus_animation_type = get_animation_type(s);
free(s);
weston_config_section_get_uint(section, "num-workspaces", weston_config_section_get_uint(section, "num-workspaces",
&shell->workspaces.num, &shell->workspaces.num,
DEFAULT_NUM_WORKSPACES); DEFAULT_NUM_WORKSPACES);
} }
static struct weston_output *
get_default_output(struct weston_compositor *compositor)
{
return container_of(compositor->output_list.next,
struct weston_output, link);
}
/* no-op func for checking focus surface */
static void
focus_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy,
int32_t width, int32_t height)
{
}
static struct focus_surface *
get_focus_surface(struct weston_surface *surface)
{
if (surface->configure == focus_surface_configure)
return surface->configure_private;
else
return NULL;
}
static bool
is_focus_surface (struct weston_surface *es)
{
return (es->configure == focus_surface_configure);
}
static bool
is_focus_view (struct weston_view *view)
{
return is_focus_surface (view->surface);
}
static struct focus_surface *
create_focus_surface(struct weston_compositor *ec,
struct weston_output *output)
{
struct focus_surface *fsurf = NULL;
struct weston_surface *surface = NULL;
fsurf = malloc(sizeof *fsurf);
if (!fsurf)
return NULL;
fsurf->surface = weston_surface_create(ec);
surface = fsurf->surface;
if (surface == NULL) {
free(fsurf);
return NULL;
}
surface->configure = focus_surface_configure;
surface->output = output;
surface->configure_private = fsurf;
fsurf->view = weston_view_create (surface);
weston_view_configure(fsurf->view, output->x, output->y,
output->width, output->height);
weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1.0);
pixman_region32_fini(&surface->opaque);
pixman_region32_init_rect(&surface->opaque, output->x, output->y,
output->width, output->height);
pixman_region32_fini(&surface->input);
pixman_region32_init(&surface->input);
wl_list_init(&fsurf->workspace_transform.link);
return fsurf;
}
static void
focus_surface_destroy(struct focus_surface *fsurf)
{
weston_surface_destroy(fsurf->surface);
free(fsurf);
}
static void
focus_animation_done(struct weston_view_animation *animation, void *data)
{
struct workspace *ws = data;
ws->focus_animation = NULL;
}
static void static void
focus_state_destroy(struct focus_state *state) focus_state_destroy(struct focus_state *state)
{ {
@ -533,6 +638,8 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
wl_list_for_each(view, &state->ws->layer.view_list, layer_link) { wl_list_for_each(view, &state->ws->layer.view_list, layer_link) {
if (view->surface == main_surface) if (view->surface == main_surface)
continue; continue;
if (is_focus_view(view))
continue;
next = view->surface; next = view->surface;
break; break;
@ -542,10 +649,21 @@ focus_state_surface_destroy(struct wl_listener *listener, void *data)
if (main_surface != state->keyboard_focus) if (main_surface != state->keyboard_focus)
next = main_surface; next = main_surface;
shell = state->seat->compositor->shell_interface.shell;
if (next) { if (next) {
shell = state->seat->compositor->shell_interface.shell; state->keyboard_focus = NULL;
activate(shell, next, state->seat); activate(shell, next, state->seat);
} else { } else {
if (shell->focus_animation_type == ANIMATION_DIM_LAYER) {
if (state->ws->focus_animation)
weston_view_animation_destroy(state->ws->focus_animation);
state->ws->focus_animation = weston_fade_run(
state->ws->fsurf_front->view,
state->ws->fsurf_front->view->alpha, 0.0, 300,
focus_animation_done, state->ws);
}
wl_list_remove(&state->link); wl_list_remove(&state->link);
focus_state_destroy(state); focus_state_destroy(state);
} }
@ -560,6 +678,7 @@ focus_state_create(struct weston_seat *seat, struct workspace *ws)
if (state == NULL) if (state == NULL)
return NULL; return NULL;
state->keyboard_focus = NULL;
state->ws = ws; state->ws = ws;
state->seat = seat; state->seat = seat;
wl_list_insert(&ws->focus_list, &state->link); wl_list_insert(&ws->focus_list, &state->link);
@ -629,6 +748,63 @@ drop_focus_state(struct desktop_shell *shell, struct workspace *ws,
state->keyboard_focus = NULL; state->keyboard_focus = NULL;
} }
static void
animate_focus_change(struct desktop_shell *shell, struct workspace *ws,
struct weston_view *from, struct weston_view *to)
{
struct weston_output *output;
bool focus_surface_created = false;
/* FIXME: Only support dim animation using two layers */
if (from == to || shell->focus_animation_type != ANIMATION_DIM_LAYER)
return;
output = get_default_output(shell->compositor);
if (ws->fsurf_front == NULL && (from || to)) {
ws->fsurf_front = create_focus_surface(shell->compositor, output);
ws->fsurf_back = create_focus_surface(shell->compositor, output);
ws->fsurf_front->view->alpha = 0.0;
ws->fsurf_back->view->alpha = 0.0;
focus_surface_created = true;
} else {
wl_list_remove(&ws->fsurf_front->view->layer_link);
wl_list_remove(&ws->fsurf_back->view->layer_link);
}
if (ws->focus_animation) {
weston_view_animation_destroy(ws->focus_animation);
ws->focus_animation = NULL;
}
if (to)
wl_list_insert(&to->layer_link,
&ws->fsurf_front->view->layer_link);
else if (from)
wl_list_insert(&ws->layer.view_list,
&ws->fsurf_front->view->layer_link);
if (focus_surface_created) {
ws->focus_animation = weston_fade_run(
ws->fsurf_front->view,
ws->fsurf_front->view->alpha, 0.6, 300,
focus_animation_done, ws);
} else if (from) {
wl_list_insert(&from->layer_link,
&ws->fsurf_back->view->layer_link);
ws->focus_animation = weston_stable_fade_run(
ws->fsurf_front->view, 0.0,
ws->fsurf_back->view, 0.6,
focus_animation_done, ws);
} else if (to) {
wl_list_insert(&ws->layer.view_list,
&ws->fsurf_back->view->layer_link);
ws->focus_animation = weston_stable_fade_run(
ws->fsurf_front->view, 0.0,
ws->fsurf_back->view, 0.6,
focus_animation_done, ws);
}
}
static void static void
workspace_destroy(struct workspace *ws) workspace_destroy(struct workspace *ws)
{ {
@ -637,6 +813,11 @@ workspace_destroy(struct workspace *ws)
wl_list_for_each_safe(state, next, &ws->focus_list, link) wl_list_for_each_safe(state, next, &ws->focus_list, link)
focus_state_destroy(state); focus_state_destroy(state);
if (ws->fsurf_front)
focus_surface_destroy(ws->fsurf_front);
if (ws->fsurf_back)
focus_surface_destroy(ws->fsurf_back);
free(ws); free(ws);
} }
@ -666,6 +847,9 @@ workspace_create(void)
wl_list_init(&ws->focus_list); wl_list_init(&ws->focus_list);
wl_list_init(&ws->seat_destroyed_listener.link); wl_list_init(&ws->seat_destroyed_listener.link);
ws->seat_destroyed_listener.notify = seat_destroyed; ws->seat_destroyed_listener.notify = seat_destroyed;
ws->fsurf_front = NULL;
ws->fsurf_back = NULL;
ws->focus_animation = NULL;
return ws; return ws;
} }
@ -709,18 +893,24 @@ get_output_height(struct weston_output *output)
} }
static void static void
view_translate(struct weston_view *view, double d) view_translate(struct workspace *ws, struct weston_view *view, double d)
{ {
struct shell_surface *shsurf = get_shell_surface(view->surface);
struct weston_transform *transform; struct weston_transform *transform;
transform = &shsurf->workspace_transform; if (is_focus_view(view)) {
struct focus_surface *fsurf = get_focus_surface(view->surface);
transform = &fsurf->workspace_transform;
} else {
struct shell_surface *shsurf = get_shell_surface(view->surface);
transform = &shsurf->workspace_transform;
}
if (wl_list_empty(&transform->link)) if (wl_list_empty(&transform->link))
wl_list_insert(view->geometry.transformation_list.prev, wl_list_insert(view->geometry.transformation_list.prev,
&shsurf->workspace_transform.link); &transform->link);
weston_matrix_init(&shsurf->workspace_transform.matrix); weston_matrix_init(&transform->matrix);
weston_matrix_translate(&shsurf->workspace_transform.matrix, weston_matrix_translate(&transform->matrix,
0.0, d, 0.0); 0.0, d, 0.0);
weston_view_geometry_dirty(view); weston_view_geometry_dirty(view);
} }
@ -736,7 +926,7 @@ workspace_translate_out(struct workspace *ws, double fraction)
height = get_output_height(view->surface->output); height = get_output_height(view->surface->output);
d = height * fraction; d = height * fraction;
view_translate(view, d); view_translate(ws, view, d);
} }
} }
@ -755,7 +945,7 @@ workspace_translate_in(struct workspace *ws, double fraction)
else else
d = height + height * fraction; d = height + height * fraction;
view_translate(view, d); view_translate(ws, view, d);
} }
} }
@ -790,13 +980,20 @@ static void
workspace_deactivate_transforms(struct workspace *ws) workspace_deactivate_transforms(struct workspace *ws)
{ {
struct weston_view *view; struct weston_view *view;
struct shell_surface *shsurf; struct weston_transform *transform;
wl_list_for_each(view, &ws->layer.view_list, layer_link) { wl_list_for_each(view, &ws->layer.view_list, layer_link) {
shsurf = get_shell_surface(view->surface); if (is_focus_view(view)) {
if (!wl_list_empty(&shsurf->workspace_transform.link)) { struct focus_surface *fsurf = get_focus_surface(view->surface);
wl_list_remove(&shsurf->workspace_transform.link); transform = &fsurf->workspace_transform;
wl_list_init(&shsurf->workspace_transform.link); } else {
struct shell_surface *shsurf = get_shell_surface(view->surface);
transform = &shsurf->workspace_transform;
}
if (!wl_list_empty(&transform->link)) {
wl_list_remove(&transform->link);
wl_list_init(&transform->link);
} }
weston_view_geometry_dirty(view); weston_view_geometry_dirty(view);
} }
@ -919,6 +1116,7 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
{ {
struct workspace *from; struct workspace *from;
struct workspace *to; struct workspace *to;
struct focus_state *state;
if (index == shell->workspaces.current) if (index == shell->workspaces.current)
return; return;
@ -945,6 +1143,18 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
restore_focus_state(shell, to); restore_focus_state(shell, to);
if (shell->focus_animation_type != ANIMATION_NONE) {
wl_list_for_each(state, &from->focus_list, link)
if (state->keyboard_focus)
animate_focus_change(shell, from,
get_default_view(state->keyboard_focus), NULL);
wl_list_for_each(state, &to->focus_list, link)
if (state->keyboard_focus)
animate_focus_change(shell, to,
NULL, get_default_view(state->keyboard_focus));
}
if (workspace_is_empty(to) && workspace_is_empty(from)) if (workspace_is_empty(to) && workspace_is_empty(from))
update_workspace(shell, index, from, to); update_workspace(shell, index, from, to);
else else
@ -1022,7 +1232,8 @@ take_surface_to_workspace_by_seat(struct desktop_shell *shell,
surface = weston_surface_get_main_surface(seat->keyboard->focus); surface = weston_surface_get_main_surface(seat->keyboard->focus);
view = get_default_view(surface); view = get_default_view(surface);
if (view == NULL || if (view == NULL ||
index == shell->workspaces.current) index == shell->workspaces.current ||
is_focus_view(view))
return; return;
from = get_current_workspace(shell); from = get_current_workspace(shell);
@ -1727,13 +1938,6 @@ shell_surface_set_class(struct wl_client *client,
shsurf->class = strdup(class); shsurf->class = strdup(class);
} }
static struct weston_output *
get_default_output(struct weston_compositor *compositor)
{
return container_of(compositor->output_list.next,
struct weston_output, link);
}
static void static void
restore_output_mode(struct weston_output *output) restore_output_mode(struct weston_output *output)
{ {
@ -3277,6 +3481,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
struct weston_view *main_view; struct weston_view *main_view;
struct focus_state *state; struct focus_state *state;
struct workspace *ws; struct workspace *ws;
struct weston_surface *old_es;
main_surface = weston_surface_get_main_surface(es); main_surface = weston_surface_get_main_surface(es);
@ -3286,6 +3491,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
if (state == NULL) if (state == NULL)
return; return;
old_es = state->keyboard_focus;
state->keyboard_focus = es; state->keyboard_focus = es;
wl_list_remove(&state->surface_destroy_listener.link); wl_list_remove(&state->surface_destroy_listener.link);
wl_signal_add(&es->destroy_signal, &state->surface_destroy_listener); wl_signal_add(&es->destroy_signal, &state->surface_destroy_listener);
@ -3295,7 +3501,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
/* should on top of panels */ /* should on top of panels */
shell_stack_fullscreen(get_shell_surface(main_surface)); shell_stack_fullscreen(get_shell_surface(main_surface));
shell_configure_fullscreen(get_shell_surface(main_surface)); shell_configure_fullscreen(get_shell_surface(main_surface));
break; return;
default: default:
restore_all_output_modes(shell->compositor); restore_all_output_modes(shell->compositor);
ws = get_current_workspace(shell); ws = get_current_workspace(shell);
@ -3304,6 +3510,9 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
weston_view_restack(main_view, &ws->layer.view_list); weston_view_restack(main_view, &ws->layer.view_list);
break; break;
} }
if (shell->focus_animation_type != ANIMATION_NONE)
animate_focus_change(shell, ws, get_default_view(old_es), get_default_view(es));
} }
/* no-op func for checking black surface */ /* no-op func for checking black surface */
@ -4391,6 +4600,9 @@ switcher_destroy(struct switcher *switcher)
struct workspace *ws = get_current_workspace(switcher->shell); struct workspace *ws = get_current_workspace(switcher->shell);
wl_list_for_each(view, &ws->layer.view_list, layer_link) { wl_list_for_each(view, &ws->layer.view_list, layer_link) {
if (is_focus_view(view))
continue;
view->alpha = 1.0; view->alpha = 1.0;
weston_surface_damage(view->surface); weston_surface_damage(view->surface);
} }

Loading…
Cancel
Save