/* * The Nature of Maximize operation is such that it is difficult to do a visual * effect that would work well. Scaling, the obvious effect, does not work that * well, because at the end of the effect we end up with window content bigger * and differently laid out than in the real window; this is a proof concept. * * (Something like a sound would be more appropriate.) */ static void maximize (MetaPlugin *plugin, MetaWindowActor *window_actor, gint end_x, gint end_y, gint end_width, gint end_height) { MetaWindowType type; ClutterActor *actor = CLUTTER_ACTOR (window_actor); MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); gdouble scale_x = 1.0; gdouble scale_y = 1.0; gfloat anchor_x = 0; gfloat anchor_y = 0; type = meta_window_get_window_type (meta_window); if (type == META_WINDOW_NORMAL) { ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); gfloat width, height; gfloat x, y; apriv->is_maximized = TRUE; clutter_actor_get_size (actor, &width, &height); clutter_actor_get_position (actor, &x, &y); /* * Work out the scale and anchor point so that the window is expanding * smoothly into the target size. */ scale_x = (gdouble)end_width / (gdouble) width; scale_y = (gdouble)end_height / (gdouble) height; anchor_x = (gdouble)(x - end_x)*(gdouble)width / ((gdouble)(end_width - width)); anchor_y = (gdouble)(y - end_y)*(gdouble)height / ((gdouble)(end_height - height)); clutter_actor_move_anchor_point (actor, anchor_x, anchor_y); animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MAXIMIZE_TIMEOUT, "scale-x", scale_x, "scale-y", scale_y, NULL); apriv->tml_maximize = clutter_animation_get_timeline (animation); data->plugin = plugin; data->actor = actor; g_signal_connect (apriv->tml_maximize, "completed", G_CALLBACK (on_maximize_effect_complete), data); return; } meta_plugin_maximize_completed (plugin, window_actor); }
static void stepper_move_on (StScrollBarPrivate *priv, gint mode) { ClutterAnimation *a; ClutterTimeline *t; GValue v = { 0, }; double value, inc; a = g_object_new (CLUTTER_TYPE_ANIMATION, "object", priv->adjustment, "duration", (guint)(PAGING_SUBSEQUENT_REPEAT_TIMEOUT * st_slow_down_factor), "mode", mode, NULL); g_signal_connect (a, "completed", G_CALLBACK (stepper_animation_completed_cb), NULL); g_object_get (priv->adjustment, "step-increment", &inc, "value", &value, NULL); if (priv->stepper_forward) value = value + inc; else value = value - inc; g_value_init (&v, G_TYPE_DOUBLE); g_value_set_double (&v, value); clutter_animation_bind (a, "value", &v); t = clutter_animation_get_timeline (a); clutter_timeline_start (t); }
/* * Simple TV-out like effect. */ static void destroy (MetaPlugin *plugin, MetaWindowActor *window_actor) { MetaWindowType type; ClutterActor *actor = CLUTTER_ACTOR (window_actor); MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); type = meta_window_get_window_type (meta_window); if (type == META_WINDOW_NORMAL) { ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); animation = clutter_actor_animate (actor, CLUTTER_EASE_OUT_QUAD, DESTROY_TIMEOUT, "opacity", 0, "scale-x", 0.8, "scale-y", 0.8, NULL); apriv->tml_destroy = clutter_animation_get_timeline (animation); data->plugin = plugin; data->actor = actor; g_signal_connect (apriv->tml_destroy, "completed", G_CALLBACK (on_destroy_effect_complete), data); } else meta_plugin_destroy_completed (plugin, window_actor); }
/* * Simple minimize handler: it applies a scale effect (which must be reversed on * completion). */ static void minimize (MetaPlugin *plugin, MetaWindowActor *window_actor) { MetaWindowType type; MetaRectangle icon_geometry; MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); ClutterActor *actor = CLUTTER_ACTOR (window_actor); type = meta_window_get_window_type (meta_window); if (!meta_window_get_icon_geometry(meta_window, &icon_geometry)) { icon_geometry.x = 0; icon_geometry.y = 0; } if (type == META_WINDOW_NORMAL) { ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); apriv->is_minimized = TRUE; clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MINIMIZE_TIMEOUT, "scale-x", 0.0, "scale-y", 0.0, "x", (double)icon_geometry.x, "y", (double)icon_geometry.y, NULL); apriv->tml_minimize = clutter_animation_get_timeline (animation); data->plugin = plugin; data->actor = actor; g_signal_connect (apriv->tml_minimize, "completed", G_CALLBACK (on_minimize_effect_complete), data); } else meta_plugin_minimize_completed (plugin, window_actor); }
static void _expire_notification (MexNotificationArea *area, MexNotification *notification, ClutterActor *actor) { MexNotificationAreaPrivate *priv = GET_PRIVATE (area); ClutterAnimation *animation; ClutterActor *last_top_actor; g_hash_table_remove (priv->notification_to_timeout_id, notification); g_hash_table_remove (priv->notification_to_actor, notification); g_queue_remove_all (priv->stack, actor); animation = clutter_actor_animate (actor, CLUTTER_EASE_OUT_QUAD, 350, "opacity", 0x00, NULL); g_signal_connect_after (animation, "completed", (GCallback)_animation_completed_cb, actor); /* Check if there is already something else in the stack. If so fade that * back in ... */ last_top_actor = g_queue_peek_head (priv->stack); if (last_top_actor) { ClutterTimeline *timeline; animation = clutter_actor_animate (last_top_actor, CLUTTER_EASE_OUT_QUAD, 350, "opacity", 0xff, NULL); timeline = clutter_animation_get_timeline (animation); clutter_timeline_set_delay (timeline, 450); } }
/* * Simple map handler: it applies a scale effect which must be reversed on * completion). */ static void map (MetaPlugin *plugin, MetaWindowActor *window_actor) { MetaWindowType type; ClutterActor *actor = CLUTTER_ACTOR (window_actor); MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); type = meta_window_get_window_type (meta_window); if (type == META_WINDOW_NORMAL) { ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); clutter_actor_set_pivot_point (actor, 0.5, 0.5); clutter_actor_set_opacity (actor, 0); clutter_actor_set_scale (actor, 0.5, 0.5); clutter_actor_show (actor); animation = clutter_actor_animate (actor, CLUTTER_EASE_OUT_QUAD, MAP_TIMEOUT, "opacity", 255, "scale-x", 1.0, "scale-y", 1.0, NULL); apriv->tml_map = clutter_animation_get_timeline (animation); data->actor = actor; data->plugin = plugin; g_signal_connect (apriv->tml_map, "completed", G_CALLBACK (on_map_effect_complete), data); } else meta_plugin_map_completed (plugin, window_actor); }
/* * Simple TV-out like effect. */ static void destroy (MetaPlugin *plugin, MetaWindowActor *window_actor) { MetaWindowType type; ClutterActor *actor = CLUTTER_ACTOR (window_actor); MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); type = meta_window_get_window_type (meta_window); if (type == META_WINDOW_NORMAL || type == META_WINDOW_DIALOG || type == META_WINDOW_MODAL_DIALOG) { ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, DESTROY_TIMEOUT, "scale-x", DESTROY_SCALE, "scale-y", DESTROY_SCALE, "opacity", 0, NULL); apriv->tml_destroy = clutter_animation_get_timeline (animation); data->plugin = plugin; data->actor = actor; g_signal_connect (apriv->tml_destroy, "completed", G_CALLBACK (on_destroy_effect_complete), data); } else meta_plugin_destroy_completed (plugin, window_actor); }
static gboolean trough_paging_cb (StScrollBar *self) { gfloat handle_pos, event_pos, tx, ty; gdouble value; gdouble page_increment; gboolean ret; gulong mode; ClutterAnimation *a; GValue v = { 0, }; ClutterTimeline *t; if (self->priv->paging_event_no == 0) { /* Scroll on after initial timeout. */ mode = CLUTTER_EASE_OUT_CUBIC; ret = FALSE; self->priv->paging_event_no = 1; self->priv->paging_source_id = g_timeout_add ( PAGING_INITIAL_REPEAT_TIMEOUT, (GSourceFunc) trough_paging_cb, self); } else if (self->priv->paging_event_no == 1) { /* Scroll on after subsequent timeout. */ ret = FALSE; mode = CLUTTER_EASE_IN_CUBIC; self->priv->paging_event_no = 2; self->priv->paging_source_id = g_timeout_add ( PAGING_SUBSEQUENT_REPEAT_TIMEOUT, (GSourceFunc) trough_paging_cb, self); } else { /* Keep scrolling. */ ret = TRUE; mode = CLUTTER_LINEAR; self->priv->paging_event_no++; } /* Do the scrolling */ st_adjustment_get_values (self->priv->adjustment, &value, NULL, NULL, NULL, &page_increment, NULL); if (self->priv->vertical) handle_pos = clutter_actor_get_y (self->priv->handle); else handle_pos = clutter_actor_get_x (self->priv->handle); clutter_actor_transform_stage_point (CLUTTER_ACTOR (self->priv->trough), self->priv->move_x, self->priv->move_y, &tx, &ty); if (self->priv->vertical) event_pos = ty; else event_pos = tx; if (event_pos > handle_pos) { if (self->priv->paging_direction == NONE) { /* Remember direction. */ self->priv->paging_direction = DOWN; } if (self->priv->paging_direction == UP) { /* Scrolled far enough. */ return FALSE; } value += page_increment; } else { if (self->priv->paging_direction == NONE) { /* Remember direction. */ self->priv->paging_direction = UP; } if (self->priv->paging_direction == DOWN) { /* Scrolled far enough. */ return FALSE; } value -= page_increment; } if (self->priv->paging_animation) { clutter_animation_completed (self->priv->paging_animation); } /* FIXME: Creating a new animation for each scroll is probably not the best * idea, but it's a lot less involved than extenind the current animation */ a = self->priv->paging_animation = g_object_new (CLUTTER_TYPE_ANIMATION, "object", self->priv->adjustment, "duration", (guint)(PAGING_SUBSEQUENT_REPEAT_TIMEOUT * st_slow_down_factor), "mode", mode, NULL); g_value_init (&v, G_TYPE_DOUBLE); g_value_set_double (&v, value); clutter_animation_bind (self->priv->paging_animation, "value", &v); t = clutter_animation_get_timeline (self->priv->paging_animation); g_signal_connect (a, "completed", G_CALLBACK (animation_completed_cb), self->priv); clutter_timeline_start (t); return ret; }
/* * Simple map handler: it applies a scale effect which must be reversed on * completion). */ static void map (MetaPlugin *plugin, MetaWindowActor *window_actor) { MetaWindowType type; ClutterActor *actor = CLUTTER_ACTOR (window_actor); MetaWindow *meta_window = meta_window_actor_get_meta_window (window_actor); type = meta_window_get_window_type (meta_window); if (type == META_WINDOW_NORMAL || type == META_WINDOW_DIALOG || type == META_WINDOW_MODAL_DIALOG) { ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); clutter_actor_move_anchor_point_from_gravity (actor, CLUTTER_GRAVITY_CENTER); clutter_actor_set_scale (actor, MAP_SCALE, MAP_SCALE); clutter_actor_set_opacity (actor, 0); clutter_actor_show (actor); animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MAP_TIMEOUT, "scale-x", 1.0, "scale-y", 1.0, "opacity", 255, NULL); apriv->tml_map = clutter_animation_get_timeline (animation); data->actor = actor; data->plugin = plugin; g_signal_connect (apriv->tml_map, "completed", G_CALLBACK (on_map_effect_complete), data); apriv->is_minimized = FALSE; } else if (type == META_WINDOW_DOCK) { /* For context menus (popup/dropdown) we fade the menu in */ ClutterAnimation *animation; EffectCompleteData *data = g_new0 (EffectCompleteData, 1); ActorPrivate *apriv = get_actor_private (window_actor); clutter_actor_set_opacity (actor, 0); clutter_actor_show (actor); animation = clutter_actor_animate (actor, CLUTTER_EASE_IN_SINE, MAP_TIMEOUT, "opacity", 255, NULL); apriv->tml_map = clutter_animation_get_timeline (animation); data->actor = actor; data->plugin = plugin; g_signal_connect (apriv->tml_map, "completed", G_CALLBACK (on_map_effect_complete), data); apriv->is_minimized = FALSE; } else meta_plugin_map_completed (plugin, window_actor); }
static void switch_workspace (MetaPlugin *plugin, gint from, gint to, MetaMotionDirection direction) { MetaScreen *screen; MetaDefaultPluginPrivate *priv = META_DEFAULT_PLUGIN (plugin)->priv; GList *l; ClutterActor *workspace0 = clutter_group_new (); ClutterActor *workspace1 = clutter_group_new (); ClutterActor *stage; int screen_width, screen_height; ClutterAnimation *animation; screen = meta_plugin_get_screen (plugin); stage = meta_get_stage_for_screen (screen); meta_screen_get_size (screen, &screen_width, &screen_height); clutter_actor_set_anchor_point (workspace1, screen_width, screen_height); clutter_actor_set_position (workspace1, screen_width, screen_height); clutter_actor_set_scale (workspace1, 0.0, 0.0); clutter_container_add_actor (CLUTTER_CONTAINER (stage), workspace1); clutter_container_add_actor (CLUTTER_CONTAINER (stage), workspace0); if (from == to) { meta_plugin_switch_workspace_completed (plugin); return; } l = g_list_last (meta_get_window_actors (screen)); while (l) { MetaWindowActor *window_actor = l->data; MetaWindow *window = meta_window_actor_get_meta_window (window_actor); MetaWorkspace *workspace; ActorPrivate *apriv = get_actor_private (window_actor); ClutterActor *actor = CLUTTER_ACTOR (window_actor); gint win_workspace; workspace = meta_window_get_workspace (window); win_workspace = meta_workspace_index (workspace); if (win_workspace == to || win_workspace == from) { apriv->orig_parent = clutter_actor_get_parent (actor); clutter_actor_reparent (actor, win_workspace == to ? workspace1 : workspace0); clutter_actor_show_all (actor); clutter_actor_raise_top (actor); } else if (win_workspace < 0) { /* Sticky window */ apriv->orig_parent = NULL; } else { /* Window on some other desktop */ clutter_actor_hide (actor); apriv->orig_parent = NULL; } l = l->prev; } priv->desktop1 = workspace0; priv->desktop2 = workspace1; animation = clutter_actor_animate (workspace0, CLUTTER_EASE_IN_SINE, SWITCH_TIMEOUT, "scale-x", 1.0, "scale-y", 1.0, NULL); priv->tml_switch_workspace1 = clutter_animation_get_timeline (animation); g_signal_connect (priv->tml_switch_workspace1, "completed", G_CALLBACK (on_switch_workspace_effect_complete), plugin); animation = clutter_actor_animate (workspace1, CLUTTER_EASE_IN_SINE, SWITCH_TIMEOUT, "scale-x", 0.0, "scale-y", 0.0, NULL); priv->tml_switch_workspace2 = clutter_animation_get_timeline (animation); }
g_object_get (adjustment, "page-increment", &step, "value", &value, NULL); clutter_animation_set_object (priv->animation, G_OBJECT (adjustment)); if (event->direction % 2) /* up, left (1, 3) */ final = value + step; else /* down, right (2, 4) */ final = value - step; timeline = clutter_animation_get_timeline (priv->animation); interval = clutter_animation_get_interval (priv->animation, "value"); if (!interval) { interval = clutter_interval_new (G_TYPE_DOUBLE, value, final); clutter_animation_bind_interval (priv->animation, "value", interval); clutter_timeline_start (timeline); } else { GValue *end, *start; end = clutter_interval_peek_final_value (interval);
static void _source_notification_added_cb (MexNotificationSource *source, MexNotification *notification, MexNotificationArea *area) { MexNotificationAreaPrivate *priv = GET_PRIVATE (area); ClutterActor *actor; ClutterActor *last_top_actor; ClutterAnimation *animation; actor = _make_notification_actor (notification); g_hash_table_insert (priv->notification_to_actor, notification, actor); clutter_container_add_actor (CLUTTER_CONTAINER (area), actor); mx_stack_child_set_x_fill (MX_STACK (area), actor, FALSE); mx_stack_child_set_y_fill (MX_STACK (area), actor, FALSE); mx_stack_child_set_x_align (MX_STACK (area), actor, MX_ALIGN_MIDDLE); mx_stack_child_set_y_align (MX_STACK (area), actor, MX_ALIGN_MIDDLE); /* Get the last notification since we want to fade that out */ last_top_actor = g_queue_peek_head (priv->stack); g_queue_push_head (priv->stack, actor); clutter_container_raise_child (CLUTTER_CONTAINER (area), actor, last_top_actor); /* Fade out old notification */ if (last_top_actor) { clutter_actor_animate (last_top_actor, CLUTTER_EASE_OUT_QUAD, 350, "opacity", 0x00, NULL); } clutter_actor_set_opacity (actor, 0); animation = clutter_actor_animate (actor, CLUTTER_EASE_OUT_QUAD, 350, "opacity", 0xff, NULL); /* Delay new notification fade in if we had an old one */ if (last_top_actor) { ClutterTimeline *timeline; timeline = clutter_animation_get_timeline (animation); clutter_timeline_set_delay (timeline, 450); } g_object_set_data (G_OBJECT (actor), "notification-area", area); g_object_set_data (G_OBJECT (actor), "notification", notification); if (notification->duration > 0) { guint timeout_id = g_timeout_add_seconds (notification->duration, (GSourceFunc)_notification_timeout_cb, actor); g_hash_table_insert (priv->notification_to_timeout_id, notification, GINT_TO_POINTER (timeout_id)); } }