[PATCH weston 3/3] shell: Animate workspace changes

Kristian Høgsberg hoegsberg at gmail.com
Thu Jun 7 12:46:24 PDT 2012


On Wed, Jun 06, 2012 at 11:36:10AM +0200, Jonas Ådahl wrote:
> Signed-off-by: Jonas Ådahl <jadahl at gmail.com>

I would like to see the animation use a spring instead, but I'm not
going to press that issue.

Kristian

> ---
>  src/shell.c |  252 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 243 insertions(+), 9 deletions(-)
> 
> diff --git a/src/shell.c b/src/shell.c
> index 56b271b..27f55b4 100644
> --- a/src/shell.c
> +++ b/src/shell.c
> @@ -38,6 +38,7 @@
>  #include "../shared/config-parser.h"
>  
>  #define DEFAULT_NUM_WORKSPACES 1
> +#define DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH 200
>  
>  enum animation_type {
>  	ANIMATION_NONE,
> @@ -88,6 +89,13 @@ struct desktop_shell {
>  		struct wl_array array;
>  		unsigned int current;
>  		unsigned int num;
> +
> +		struct weston_animation animation;
> +		int anim_dir;
> +		uint32_t anim_timestamp;
> +		double anim_current;
> +		struct workspace *anim_from;
> +		struct workspace *anim_to;
>  	} workspaces;
>  
>  	struct {
> @@ -166,6 +174,8 @@ struct shell_surface {
>  
>  	struct ping_timer *ping_timer;
>  
> +	struct weston_transform workspace_transform;
> +
>  	struct weston_output *fullscreen_output;
>  	struct weston_output *output;
>  	struct wl_list link;
> @@ -1365,6 +1375,8 @@ create_shell_surface(void *shell, struct weston_surface *surface,
>  	wl_list_init(&shsurf->rotation.transform.link);
>  	weston_matrix_init(&shsurf->rotation.rotation);
>  
> +	wl_list_init(&shsurf->workspace_transform.link);
> +
>  	shsurf->type = SHELL_SURFACE_NONE;
>  	shsurf->next_type = SHELL_SURFACE_NONE;
>  
> @@ -1620,6 +1632,99 @@ workspace_create(void)
>  	return ws;
>  }
>  
> +static int
> +workspace_is_empty(struct workspace *ws)
> +{
> +	return wl_list_empty(&ws->layer.surface_list);
> +}
> +
> +static unsigned int
> +get_output_height(struct weston_output *output)
> +{
> +	return abs(output->region.extents.y1 - output->region.extents.y2);
> +}
> +
> +static void
> +workspace_translate_out(struct workspace *ws, double fraction)
> +{
> +	struct weston_surface *surface;
> +	struct shell_surface *shsurf;
> +	unsigned int height;
> +	double d;
> +
> +	wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
> +		shsurf = get_shell_surface(surface);
> +		height = get_output_height(surface->output);
> +		d = height * fraction;
> +
> +		weston_matrix_init(&shsurf->workspace_transform.matrix);
> +		weston_matrix_translate(&shsurf->workspace_transform.matrix,
> +					0.0, d, 0.0);
> +		shsurf->surface->geometry.dirty = 1;
> +	}
> +}
> +
> +static void
> +workspace_translate_in(struct workspace *ws, double fraction)
> +{
> +	struct weston_surface *surface;
> +	struct shell_surface *shsurf;
> +	unsigned int height;
> +	double d;
> +
> +	wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
> +		shsurf = get_shell_surface(surface);
> +		height = get_output_height(surface->output);
> +
> +		if (fraction > 0)
> +			d = -(height - height * fraction);
> +		else
> +			d = height + height * fraction;
> +
> +		weston_matrix_init(&shsurf->workspace_transform.matrix);
> +		weston_matrix_translate(&shsurf->workspace_transform.matrix,
> +					0.0, d, 0.0);
> +		shsurf->surface->geometry.dirty = 1;
> +	}
> +}
> +
> +static void
> +workspace_activate_transforms(struct workspace *ws)
> +{
> +	struct weston_surface *surface;
> +	struct shell_surface *shsurf;
> +
> +	wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
> +		shsurf = get_shell_surface(surface);
> +		weston_matrix_init(&shsurf->workspace_transform.matrix);
> +		wl_list_insert(shsurf->surface->geometry.transformation_list.prev,
> +			       &shsurf->workspace_transform.link);
> +		shsurf->surface->geometry.dirty = 1;
> +	}
> +}
> +
> +static void
> +workspace_deactivate_transforms(struct workspace *ws)
> +{
> +	struct weston_surface *surface;
> +	struct shell_surface *shsurf;
> +
> +	wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
> +		shsurf = get_shell_surface(surface);
> +		wl_list_remove(&shsurf->workspace_transform.link);
> +		shsurf->surface->geometry.dirty = 1;
> +	}
> +}
> +
> +static void
> +workspace_damage_all_surfaces(struct workspace *ws)
> +{
> +	struct weston_surface *surface;
> +
> +	wl_list_for_each(surface, &ws->layer.surface_list, layer_link)
> +		weston_surface_damage(surface);
> +}
> +
>  static struct workspace *
>  get_workspace(struct desktop_shell *shell, unsigned int index)
>  {
> @@ -1646,12 +1751,130 @@ activate_workspace(struct desktop_shell *shell, unsigned int index)
>  }
>  
>  static void
> +reverse_workspace_change_animation(struct desktop_shell *shell,
> +				   unsigned int index,
> +				   struct workspace *from,
> +				   struct workspace *to)
> +{
> +	shell->workspaces.current = index;
> +
> +	shell->workspaces.anim_to = to;
> +	shell->workspaces.anim_from = from;
> +	shell->workspaces.anim_dir = -1 * shell->workspaces.anim_dir;
> +	shell->workspaces.anim_timestamp =
> +		weston_compositor_get_time() -
> +		/* Invers of movement function in
> +		 * `animate_workspace_change_frame()' */
> +		(asin(1.0 - shell->workspaces.anim_current) *
> +		 DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH *
> +		 M_2_PI);
> +
> +	workspace_damage_all_surfaces(from);
> +	workspace_damage_all_surfaces(to);
> +}
> +
> +
> +static void
> +finish_workspace_change_animation(struct desktop_shell *shell,
> +				  struct workspace *from,
> +				  struct workspace *to)
> +{
> +	struct weston_surface *surface;
> +
> +	wl_list_remove(&shell->workspaces.animation.link);
> +	workspace_deactivate_transforms(from);
> +	workspace_deactivate_transforms(to);
> +	shell->workspaces.anim_to = NULL;
> +
> +	wl_list_remove(&shell->workspaces.anim_from->layer.link);
> +	wl_list_for_each(surface, &from->layer.surface_list, layer_link)
> +		weston_surface_hide(surface);
> +}
> +
> +static void
> +animate_workspace_change_frame(struct weston_animation *animation,
> +			       struct weston_output *output, uint32_t msecs)
> +{
> +	struct desktop_shell *shell =
> +		container_of(animation, struct desktop_shell,
> +			     workspaces.animation);
> +	struct workspace *from = shell->workspaces.anim_from;
> +	struct workspace *to = shell->workspaces.anim_to;
> +	uint32_t t;
> +	double x, y;
> +
> +	if (workspace_is_empty(from) && workspace_is_empty(to)) {
> +		finish_workspace_change_animation(shell, from, to);
> +		return;
> +	}
> +
> +	if (msecs < shell->workspaces.anim_timestamp)
> +		t = 0;
> +	else
> +		t = msecs - shell->workspaces.anim_timestamp;
> +
> +	/*
> +	 * x = [0, π/2]
> +	 * y = sin(x)
> +	 */
> +	x = t * (1.0/DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) * M_PI_2;
> +	y = sin(x);
> +
> +	if (t < DEFAULT_WORKSPACE_CHANGE_ANIMATION_LENGTH) {
> +		workspace_translate_out(from, shell->workspaces.anim_dir * y);
> +		workspace_translate_in(to, shell->workspaces.anim_dir * y);
> +		shell->workspaces.anim_current = y;
> +	}
> +	else {
> +		finish_workspace_change_animation(shell, from, to);
> +	}
> +
> +	workspace_damage_all_surfaces(from);
> +	workspace_damage_all_surfaces(to);
> +}
> +
> +static void
> +animate_workspace_change(struct desktop_shell *shell,
> +			 unsigned int index,
> +			 struct workspace *from,
> +			 struct workspace *to)
> +{
> +	struct weston_surface *surface;
> +	int dir;
> +
> +	if (index > shell->workspaces.current)
> +		dir = -1;
> +	else
> +		dir = 1;
> +
> +	shell->workspaces.current = index;
> +
> +	shell->workspaces.anim_dir = dir;
> +	shell->workspaces.anim_from = from;
> +	shell->workspaces.anim_to = to;
> +	shell->workspaces.anim_current = 0.0;
> +	shell->workspaces.anim_timestamp = weston_compositor_get_time();
> +
> +	wl_list_insert(&shell->compositor->animation_list,
> +		       &shell->workspaces.animation.link);
> +
> +	wl_list_insert(&from->layer.link, &to->layer.link);
> +	workspace_activate_transforms(from);
> +	workspace_activate_transforms(to);
> +	workspace_translate_in(to, 0);
> +	wl_list_for_each(surface, &to->layer.surface_list, layer_link)
> +		weston_surface_show(surface);
> +
> +	workspace_damage_all_surfaces(from);
> +	workspace_damage_all_surfaces(to);
> +}
> +
> +static void
>  change_workspace(struct desktop_shell *shell, unsigned int index)
>  {
>  	struct workspace *from;
>  	struct workspace *to;
>  	struct weston_seat *seat;
> -	struct weston_surface *surface;
>  
>  	if (index == shell->workspaces.current)
>  		return;
> @@ -1668,16 +1891,24 @@ change_workspace(struct desktop_shell *shell, unsigned int index)
>  	from = get_current_workspace(shell);
>  	to = get_workspace(shell, index);
>  
> -	shell->workspaces.current = index;
> -	wl_list_insert(&from->layer.link, &to->layer.link);
> -	wl_list_remove(&from->layer.link);
> +	if (shell->workspaces.anim_from == to &&
> +	    shell->workspaces.anim_to == from) {
> +		reverse_workspace_change_animation(shell, index, from, to);
> +		return;
> +	}
>  
> -	wl_list_for_each(surface, &from->layer.surface_list, layer_link)
> -		weston_surface_hide(surface);
> -	wl_list_for_each(surface, &to->layer.surface_list, layer_link)
> -		weston_surface_show(surface);
> +	if (shell->workspaces.anim_to != NULL)
> +		finish_workspace_change_animation(shell,
> +						  shell->workspaces.anim_from,
> +						  shell->workspaces.anim_to);
>  
> -	weston_compositor_damage_all(shell->compositor);
> +	if (workspace_is_empty(to) && workspace_is_empty(from)) {
> +		shell->workspaces.current = index;
> +		wl_list_insert(&from->layer.link, &to->layer.link);
> +		wl_list_remove(&from->layer.link);
> +	}
> +	else
> +		animate_workspace_change(shell, index, from, to);
>  }
>  
>  static void
> @@ -2914,6 +3145,9 @@ shell_init(struct weston_compositor *ec)
>  	}
>  	activate_workspace(shell, 0);
>  
> +	wl_list_init(&shell->workspaces.animation.link);
> +	shell->workspaces.animation.frame = animate_workspace_change_frame;
> +
>  	if (wl_display_add_global(ec->wl_display, &wl_shell_interface,
>  				  shell, bind_shell) == NULL)
>  		return -1;
> -- 
> 1.7.9.5
> 
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel


More information about the wayland-devel mailing list