[PATCH weston v2 4/5] shell: Animate workspace changes
Jonas Ådahl
jadahl at gmail.com
Mon Jun 11 13:03:05 PDT 2012
Signed-off-by: Jonas Ådahl <jadahl at gmail.com>
---
src/shell.c | 258 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 250 insertions(+), 8 deletions(-)
diff --git a/src/shell.c b/src/shell.c
index a323b0c..993b104 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -39,6 +39,7 @@
#include "log.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;
@@ -337,6 +347,12 @@ workspace_create(void)
return ws;
}
+static int
+workspace_is_empty(struct workspace *ws)
+{
+ return wl_list_empty(&ws->layer.surface_list);
+}
+
static struct workspace *
get_workspace(struct desktop_shell *shell, unsigned int index)
{
@@ -362,6 +378,214 @@ activate_workspace(struct desktop_shell *shell, unsigned int index)
shell->workspaces.current = index;
}
+static unsigned int
+get_output_height(struct weston_output *output)
+{
+ return abs(output->region.extents.y1 - output->region.extents.y2);
+}
+
+static void
+surface_translate(struct weston_surface *surface, double d)
+{
+ struct shell_surface *shsurf = get_shell_surface(surface);
+ struct weston_transform *transform;
+
+ transform = &shsurf->workspace_transform;
+ if (wl_list_empty(&transform->link))
+ wl_list_insert(surface->geometry.transformation_list.prev,
+ &shsurf->workspace_transform.link);
+
+ weston_matrix_init(&shsurf->workspace_transform.matrix);
+ weston_matrix_translate(&shsurf->workspace_transform.matrix,
+ 0.0, d, 0.0);
+ surface->geometry.dirty = 1;
+}
+
+static void
+workspace_translate_out(struct workspace *ws, double fraction)
+{
+ struct weston_surface *surface;
+ unsigned int height;
+ double d;
+
+ wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
+ height = get_output_height(surface->output);
+ d = height * fraction;
+
+ surface_translate(surface, d);
+ }
+}
+
+static void
+workspace_translate_in(struct workspace *ws, double fraction)
+{
+ struct weston_surface *surface;
+ unsigned int height;
+ double d;
+
+ wl_list_for_each(surface, &ws->layer.surface_list, layer_link) {
+ height = get_output_height(surface->output);
+
+ if (fraction > 0)
+ d = -(height - height * fraction);
+ else
+ d = height + height * fraction;
+
+ surface_translate(surface, d);
+ }
+}
+
+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 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
+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);
+ wl_list_init(&shsurf->workspace_transform.link);
+ shsurf->surface->geometry.dirty = 1;
+ }
+}
+
+static void
+finish_workspace_change_animation(struct desktop_shell *shell,
+ struct workspace *from,
+ struct workspace *to)
+{
+ struct weston_surface *surface;
+
+ workspace_damage_all_surfaces(from);
+ workspace_damage_all_surfaces(to);
+
+ 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)
+ surface->output = NULL;
+}
+
+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_damage_all_surfaces(from);
+ workspace_damage_all_surfaces(to);
+
+ workspace_translate_out(from, shell->workspaces.anim_dir * y);
+ workspace_translate_in(to, shell->workspaces.anim_dir * y);
+ shell->workspaces.anim_current = y;
+
+ workspace_damage_all_surfaces(from);
+ workspace_damage_all_surfaces(to);
+ }
+ else {
+ finish_workspace_change_animation(shell, from, to);
+ }
+}
+
+static void
+animate_workspace_change(struct desktop_shell *shell,
+ unsigned int index,
+ struct workspace *from,
+ struct workspace *to)
+{
+ struct weston_surface *surface;
+ struct weston_output *output;
+
+ 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();
+
+ output = container_of(shell->compositor->output_list.next,
+ struct weston_output, link);
+ wl_list_insert(&output->animation_list,
+ &shell->workspaces.animation.link);
+
+ wl_list_for_each(surface, &to->layer.surface_list, layer_link)
+ weston_surface_assign_output(surface);
+
+ wl_list_insert(&from->layer.link, &to->layer.link);
+
+ workspace_translate_in(to, 0);
+
+ workspace_damage_all_surfaces(from);
+ workspace_damage_all_surfaces(to);
+}
+
static void
change_workspace(struct desktop_shell *shell, unsigned int index)
{
@@ -385,16 +609,29 @@ 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)
- surface->output = NULL;
- wl_list_for_each(surface, &to->layer.surface_list, layer_link)
- weston_surface_assign_output(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);
+
+ wl_list_for_each(surface, &to->layer.surface_list, layer_link)
+ weston_surface_assign_output(surface);
+ wl_list_for_each(surface, &from->layer.surface_list, layer_link)
+ surface->output = NULL;
+ }
+ else
+ animate_workspace_change(shell, index, from, to);
}
static void
@@ -1446,6 +1683,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;
@@ -2935,6 +3174,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
More information about the wayland-devel
mailing list