Improves the multitasking view

It fixes the issue when the view was exited while it was animating a workspaceswitch where the windows would "get stuck" mid-animation and jump into place after the animation is finished.

It slides out dock windows that are found at the top and bottom of the screen to provide a smoother open experience.
This commit is contained in:
Tom Beckmann 2015-04-11 15:40:30 +00:00 committed by RabbitBot
commit a1eac874a8
5 changed files with 148 additions and 46 deletions

View File

@ -55,7 +55,7 @@ namespace Gala
#else
background = new Background (screen, monitor, BackgroundSettings.get_default ().schema);
#endif
background.set_easing_duration (300);
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
window_container = new WindowCloneContainer ();
window_container.window_selected.connect ((w) => { window_selected (w); });

View File

@ -27,7 +27,8 @@ namespace Gala
*/
public class MultitaskingView : Actor, ActivatableComponent
{
const int HIDING_DURATION = 300;
public const int ANIMATION_DURATION = 250;
public const AnimationMode ANIMATION_MODE = AnimationMode.EASE_OUT_QUAD;
const int SMOOTH_SCROLL_DELAY = 500;
public WindowManager wm { get; construct; }
@ -43,6 +44,7 @@ namespace Gala
IconGroupContainer icon_groups;
Actor workspaces;
Actor dock_clones;
public MultitaskingView (WindowManager wm)
{
@ -64,8 +66,11 @@ namespace Gala
icon_groups = new IconGroupContainer (screen);
icon_groups.request_reposition.connect (() => reposition_icon_groups (true));
dock_clones = new Actor ();
add_child (icon_groups);
add_child (workspaces);
add_child (dock_clones);
foreach (var workspace in screen.get_workspaces ())
add_workspace (workspace.index ());
@ -226,11 +231,14 @@ namespace Gala
workspace_clone.active = false;
}
workspace_clone.save_easing_state ();
workspace_clone.set_easing_duration (animate ? 200 : 0);
workspace_clone.x = dest_x;
workspace_clone.restore_easing_state ();
}
workspaces.set_easing_duration (animate ? 300 : 0);
workspaces.set_easing_duration (animate ?
AnimationSettings.get_default ().workspace_switch_duration : 0);
workspaces.x = -active_x;
reposition_icon_groups (animate);
@ -473,6 +481,11 @@ namespace Gala
if (active_workspace != null)
workspaces.set_child_above_sibling (active_workspace, null);
workspaces.remove_all_transitions ();
foreach (var child in workspaces.get_children ()) {
child.remove_all_transitions ();
}
update_positions (false);
foreach (var child in workspaces.get_children ()) {
@ -483,8 +496,54 @@ namespace Gala
workspace.close ();
}
float clone_offset_x, clone_offset_y;
dock_clones.get_transformed_position (out clone_offset_x, out clone_offset_y);
if (opening) {
unowned List<WindowActor> actors = Compositor.get_window_actors (screen);
foreach (var actor in actors) {
const int MAX_OFFSET = 100;
var window = actor.get_meta_window ();
if (window.window_type != WindowType.DOCK)
continue;
var monitor_geom = screen.get_monitor_geometry (window.get_monitor ());
#if HAS_MUTTER312
var window_geom = window.get_frame_rect ();
#else
var window_geom = window.get_outer_rect ();
#endif
var top = monitor_geom.y + MAX_OFFSET > window_geom.y;
var bottom = monitor_geom.y + monitor_geom.height - MAX_OFFSET > window_geom.y;
if (!top && !bottom)
continue;
var clone = new SafeWindowClone (window, true);
clone.set_position (actor.x - clone_offset_x, actor.y - clone_offset_y);
clone.set_easing_duration (ANIMATION_DURATION);
clone.set_easing_mode (ANIMATION_MODE);
dock_clones.add_child (clone);
if (top)
clone.y = actor.y - actor.height - clone_offset_y;
else if (bottom)
clone.y = actor.y + actor.height - clone_offset_y;
}
} else {
foreach (var child in dock_clones.get_children ()) {
var dock = (Clone) child;
dock.y = dock.source.y - clone_offset_y;
}
}
if (!opening) {
Timeout.add (290, () => {
Timeout.add (ANIMATION_DURATION, () => {
foreach (var container in window_containers_monitors) {
container.visible = false;
}
@ -495,6 +554,8 @@ namespace Gala
wm.window_group.show ();
wm.top_window_group.show ();
dock_clones.destroy_all_children ();
wm.pop_modal (modal_proxy);
animating = false;
@ -502,7 +563,7 @@ namespace Gala
return false;
});
} else {
Timeout.add (200, () => {
Timeout.add (ANIMATION_DURATION, () => {
animating = false;
return false;
});

View File

@ -73,8 +73,22 @@ namespace Gala
public bool overview_mode { get; construct; }
[CCode (notify = false)]
public uint8 shadow_opacity {
get {
return shadow_effect != null ? shadow_effect.shadow_opacity : 255;
}
set {
if (shadow_effect != null) {
shadow_effect.shadow_opacity = value;
queue_redraw ();
}
}
}
DragDropAction? drag_action = null;
Clone? clone = null;
ShadowEffect? shadow_effect = null;
Actor prev_parent = null;
int prev_index = -1;
@ -195,7 +209,8 @@ namespace Gala
#else
var outer_rect = window.get_outer_rect ();
#endif
add_effect_with_name ("shadow", new ShadowEffect (outer_rect.width, outer_rect.height, 40, 5));
shadow_effect = new ShadowEffect (outer_rect.width, outer_rect.height, 40, 5);
add_effect_with_name ("shadow", shadow_effect);
#if HAS_MUTTER312
window.size_changed.connect (update_shadow_size);
#else
@ -276,24 +291,20 @@ namespace Gala
var outer_rect = window.get_outer_rect ();
#endif
float offset_x = 0, offset_y = 0;
var monitor_geom = window.get_screen ().get_monitor_geometry (window.get_monitor ());
var offset_x = monitor_geom.x;
var offset_y = monitor_geom.y;
var parent = get_parent ();
if (parent != null) {
// in overview_mode the parent has just been added to the stage, so the
// transforme position is not set yet. However, the set position is correct
// for overview anyway, so we can just use that.
if (overview_mode)
parent.get_position (out offset_x, out offset_y);
else
parent.get_transformed_position (out offset_x, out offset_y);
}
set_easing_mode (AnimationMode.EASE_IN_OUT_CUBIC);
set_easing_duration (animate ? 300 : 0);
save_easing_state ();
set_easing_mode (MultitaskingView.ANIMATION_MODE);
set_easing_duration (animate ? MultitaskingView.ANIMATION_DURATION : 0);
set_position (outer_rect.x - offset_x, outer_rect.y - offset_y);
set_size (outer_rect.width, outer_rect.height);
restore_easing_state ();
if (animate)
toggle_shadow (false);
window_icon.opacity = 0;
@ -308,13 +319,17 @@ namespace Gala
{
slot = rect;
set_easing_duration (250);
set_easing_mode (AnimationMode.EASE_OUT_QUAD);
save_easing_state ();
set_easing_duration (MultitaskingView.ANIMATION_DURATION);
set_easing_mode (MultitaskingView.ANIMATION_MODE);
set_size (rect.width, rect.height);
set_position (rect.x, rect.y);
window_icon.opacity = 255;
restore_easing_state ();
toggle_shadow (true);
// for overview mode, windows may be faded out initially. Make sure
// to fade those in.
@ -430,6 +445,21 @@ namespace Gala
}
}
void toggle_shadow (bool show)
{
var shadow_transition = new PropertyTransition ("shadow-opacity");
shadow_transition.duration = MultitaskingView.ANIMATION_DURATION;
shadow_transition.remove_on_complete = true;
shadow_transition.progress_mode = MultitaskingView.ANIMATION_MODE;
if (show)
shadow_transition.interval = new Clutter.Interval (typeof (uint8), 0, 255);
else
shadow_transition.interval = new Clutter.Interval (typeof (uint8), 255, 0);
add_transition ("shadow-opacity", shadow_transition);
}
/**
* Send the window the delete signal and listen for new windows to be added
* to the window's workspace, in which case we check if the new window is a

View File

@ -298,8 +298,8 @@ namespace Gala
background.set_pivot_point (0.5f, pivotY);
background.save_easing_state ();
background.set_easing_duration (250);
background.set_easing_mode (AnimationMode.EASE_OUT_QUAD);
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
background.set_easing_mode (MultitaskingView.ANIMATION_MODE);
background.set_scale (scale, scale);
background.restore_easing_state ();
@ -333,8 +333,8 @@ namespace Gala
opened = false;
background.save_easing_state ();
background.set_easing_duration (300);
background.set_easing_mode (AnimationMode.EASE_IN_OUT_CUBIC);
background.set_easing_duration (MultitaskingView.ANIMATION_DURATION);
background.set_easing_mode (MultitaskingView.ANIMATION_MODE);
background.set_scale (1, 1);
background.restore_easing_state ();

View File

@ -1241,6 +1241,8 @@ namespace Gala
var primary = screen.get_primary_monitor ();
var move_primary_only = InternalUtils.workspaces_only_on_primary ();
var monitor_geom = screen.get_monitor_geometry (primary);
var clone_offset_x = move_primary_only ? monitor_geom.x : 0;
var clone_offset_y = move_primary_only ? monitor_geom.y : 0;
screen.get_size (out screen_width, out screen_height);
@ -1255,10 +1257,10 @@ namespace Gala
parents = new List<Clutter.Actor> ();
tmp_actors = new List<Clutter.Clone> ();
tmp_actors.append (main_container);
tmp_actors.append (in_group);
tmp_actors.append (out_group);
tmp_actors.append (static_windows);
tmp_actors.prepend (main_container);
tmp_actors.prepend (in_group);
tmp_actors.prepend (out_group);
tmp_actors.prepend (static_windows);
window_group.add_child (main_container);
@ -1270,24 +1272,27 @@ namespace Gala
} else
wallpaper = background_group;
windows.append (wallpaper);
parents.append (wallpaper.get_parent ());
windows.prepend (wallpaper);
parents.prepend (wallpaper.get_parent ());
var wallpaper_clone = new Clutter.Clone (wallpaper);
tmp_actors.append (wallpaper_clone);
tmp_actors.prepend (wallpaper_clone);
// pack all containers
clutter_actor_reparent (wallpaper, main_container);
main_container.add_child (wallpaper_clone);
main_container.add_child (out_group);
main_container.add_child (in_group);
main_container.add_child (static_windows);
// if we have a move action, pack that window to the static ones
if (moving != null) {
var moving_actor = (WindowActor) moving.get_compositor_private ();
windows.append (moving_actor);
parents.append (moving_actor.get_parent ());
windows.prepend (moving_actor);
parents.prepend (moving_actor.get_parent ());
moving_actor.set_translation (-clone_offset_x, -clone_offset_y, 0);
clutter_actor_reparent (moving_actor, static_windows);
}
@ -1295,6 +1300,7 @@ namespace Gala
var from_has_fullscreened = false;
var docks = new List<WindowActor> ();
// collect all windows and put them in the appropriate containers
foreach (var actor in Compositor.get_window_actors (screen)) {
if (actor.is_destroyed ())
continue;
@ -1310,13 +1316,14 @@ namespace Gala
// only collect docks here that need to be displayed on both workspaces
// all other windows will be collected below
if (window.window_type == WindowType.DOCK) {
docks.append (actor);
docks.prepend (actor);
} else {
// windows that are on all workspaces will be faded out and back in
windows.append (actor);
parents.append (actor.get_parent ());
windows.prepend (actor);
parents.prepend (actor.get_parent ());
clutter_actor_reparent (actor, static_windows);
actor.set_translation (-clone_offset_x, -clone_offset_y, 0);
actor.save_easing_state ();
actor.set_easing_duration (300);
actor.opacity = 0;
@ -1329,6 +1336,7 @@ namespace Gala
if (window.get_workspace () == workspace_from) {
windows.append (actor);
parents.append (actor.get_parent ());
actor.set_translation (-clone_offset_x, -clone_offset_y, 0);
clutter_actor_reparent (actor, out_group);
if (window.fullscreen)
@ -1337,6 +1345,7 @@ namespace Gala
} else if (window.get_workspace () == workspace_to) {
windows.append (actor);
parents.append (actor.get_parent ());
actor.set_translation (-clone_offset_x, -clone_offset_y, 0);
clutter_actor_reparent (actor, in_group);
if (window.fullscreen)
@ -1352,16 +1361,17 @@ namespace Gala
foreach (var window in docks) {
if (!to_has_fullscreened) {
var clone = new SafeWindowClone (window.get_meta_window ());
clone.x = window.x;
clone.y = window.y;
clone.x = window.x - clone_offset_x;
clone.y = window.y - clone_offset_y;
in_group.add_child (clone);
tmp_actors.append (clone);
tmp_actors.prepend (clone);
}
if (!from_has_fullscreened) {
windows.append (window);
parents.append (window.get_parent ());
windows.prepend (window);
parents.prepend (window.get_parent ());
window.set_translation (-clone_offset_x, -clone_offset_y, 0);
clutter_actor_reparent (window, out_group);
}
@ -1369,7 +1379,7 @@ namespace Gala
main_container.clip_to_allocation = true;
main_container.x = move_primary_only ? monitor_geom.x : 0;
main_container.y = move_primary_only ? monitor_geom.x : 0;
main_container.y = move_primary_only ? monitor_geom.y : 0;
main_container.width = move_primary_only ? monitor_geom.width : screen_width;
main_container.height = move_primary_only ? monitor_geom.height : screen_height;
@ -1400,10 +1410,10 @@ namespace Gala
wallpaper.set_easing_duration (animation_duration);
out_group.x = x2;
in_group.x = move_primary_only ? monitor_geom.x : 0;
in_group.x = 0;
wallpaper.x = x2;
wallpaper_clone.x = move_primary_only ? monitor_geom.x : 0;
wallpaper_clone.x = 0;
wallpaper.restore_easing_state ();
var transition = in_group.get_transition ("x");
@ -1423,6 +1433,7 @@ namespace Gala
for (var i = 0; i < windows.length (); i++) {
var actor = windows.nth_data (i);
actor.set_translation (0, 0, 0);
// to maintain the correct order of monitor, we need to insert the Background
// back manually