implement smooth (un)maximize, may have some small offsets currently

This commit is contained in:
Tom Beckmann 2015-01-05 16:46:27 +01:00 committed by Rico Tzschichholz
parent 5fa4764c98
commit 481da2cc71
3 changed files with 140 additions and 44 deletions

View File

@ -224,6 +224,38 @@ namespace Gala
return n;
}
/**
* Creates an actor showing the current contents of the given WindowActor.
*
* @param actor The actor from which to create a shnapshot
* @param inner_rect The inner (actually visible) rectangle of the window
* @param outer_rect The outer (input region) rectangle of the window
*/
public static Clutter.Actor get_window_actor_snapshot (Meta.WindowActor actor, Meta.Rectangle inner_rect, Meta.Rectangle outer_rect)
{
var surface = ((Meta.ShapedTexture) actor.get_texture ()).get_image ({
inner_rect.x - outer_rect.x,
inner_rect.y - outer_rect.y,
inner_rect.width,
inner_rect.height
});
var canvas = new Clutter.Canvas ();
var handler = canvas.draw.connect ((cr) => {
cr.set_source_surface (surface, 0, 0);
cr.paint ();
return false;
});
canvas.set_size (inner_rect.width, inner_rect.height);
SignalHandler.disconnect (canvas, handler);
var container = new Clutter.Actor ();
container.set_size (inner_rect.width, inner_rect.height);
container.content = canvas;
return container;
}
/**
* Ring the system bell, will most likely emit a <beep> error sound or, if the
* audible bell is disabled, flash the screen

View File

@ -36,7 +36,15 @@ namespace Gala
if (window.on_all_workspaces)
instance.listen_on_window (window);
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
}
screen.get_display ().window_created.connect ((window) => {
if (window.window_type == WindowType.NORMAL)
instance.monitor_window (window);
});
}
public static WindowListener get_default ()
@ -47,11 +55,14 @@ namespace Gala
public signal void window_no_longer_on_all_workspaces (Window window);
Gee.List<Window> listened_windows;
public Meta.Rectangle last_maximized_window_frame_rect;
public Meta.Rectangle last_maximized_window_buffer_rect;
Gee.List<Window> listened_windows_sticky;
WindowListener ()
{
listened_windows = new Gee.LinkedList<Window> ();
listened_windows_sticky = new Gee.LinkedList<Window> ();
}
public void listen_on_window (Window window)
@ -62,7 +73,7 @@ namespace Gala
window.notify["on-all-workspaces"].connect (window_on_all_workspaces_changed);
window.unmanaged.connect (window_removed);
listened_windows.add (window);
listened_windows_sticky.add (window);
}
void window_on_all_workspaces_changed (Object object, ParamSpec param)
@ -73,15 +84,46 @@ namespace Gala
return;
window.notify.disconnect (window_on_all_workspaces_changed);
window.unmanaged.disconnect (window_removed);
listened_windows.remove (window);
window.unmanaged.disconnect (sticky_window_removed);
listened_windows_sticky.remove (window);
window_no_longer_on_all_workspaces (window);
}
void monitor_window (Window window)
{
window.notify["maximized-horizontally"].connect (window_maximized_changed);
window.notify["maximized-vertically"].connect (window_maximized_changed);
window.unmanaged.connect (window_removed);
}
void window_maximized_changed (Object object, ParamSpec pspec)
{
var window = (Window) object;
#if HAS_MUTTER312
last_maximized_window_frame_rect = window.get_frame_rect ();
#else
last_maximized_window_frame_rect = window.get_outer_rect ();
#endif
#if HAS_MUTTER314
last_maximized_window_buffer_rect = window.get_buffer_rect ();
#else
last_maximized_window_buffer_rect = window.get_input_rect ();
#endif
}
void window_removed (Window window)
{
listened_windows.remove (window);
window.notify["maximized-horizontally"].disconnect (window_maximized_changed);
window.notify["maximized-vertically"].disconnect (window_maximized_changed);
window.unmanaged.disconnect (window_removed);
}
void sticky_window_removed (Window window)
{
listened_windows_sticky.remove (window);
}
}
}

View File

@ -727,42 +727,52 @@ namespace Gala
}
}
//stolen from original mutter plugin
public override void maximize (WindowActor actor, int ex, int ey, int ew, int eh)
{
float x, y, width, height;
actor.get_size (out width, out height);
actor.get_position (out x, out y);
var duration = AnimationSettings.get_default ().snap_duration;
if (!AnimationSettings.get_default ().enable_animations ||
AnimationSettings.get_default ().snap_duration == 0 ||
(x == ex && y == ey && ew == width && eh == height)) {
if (!AnimationSettings.get_default ().enable_animations || duration == 0) {
maximize_completed (actor);
return;
}
if (actor.get_meta_window ().window_type == WindowType.NORMAL) {
maximizing.add (actor);
var old_inner_rect = WindowListener.get_default ().last_maximized_window_frame_rect;
var old_outer_rect = WindowListener.get_default ().last_maximized_window_buffer_rect;
var old_actor = Utils.get_window_actor_snapshot (actor, old_inner_rect, old_outer_rect);
float scale_x = (float)ew / width;
float scale_y = (float)eh / height;
float anchor_x = (float)(x - ex) * width / (ew - width);
float anchor_y = (float)(y - ey) * height / (eh - height);
old_actor.set_position (old_inner_rect.x, old_inner_rect.y);
//reset the actor's anchors
actor.scale_gravity = actor.anchor_gravity = Clutter.Gravity.NORTH_WEST;
ui_group.add_child (old_actor);
actor.move_anchor_point (anchor_x, anchor_y);
actor.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, AnimationSettings.get_default ().snap_duration,
scale_x:scale_x, scale_y:scale_y).get_timeline ().completed.connect ( () => {
var scale_x = (double) ew / old_inner_rect.width;
var scale_y = (double) eh / old_inner_rect.height;
actor.anchor_gravity = Clutter.Gravity.NORTH_WEST;
actor.set_scale (1.0, 1.0);
old_actor.animate (Clutter.AnimationMode.EASE_IN_OUT_QUAD, duration,
x: (float) ex,
y: (float) ey,
opacity: 0,
scale_x: scale_x,
scale_y: scale_y).completed.connect (() => {
old_actor.destroy ();
maximizing.remove (actor);
maximize_completed (actor);
actor.translation_x = 0;
actor.translation_y = 0;
});
maximize_completed (actor);
actor.scale_gravity = Clutter.Gravity.NORTH_WEST;
actor.translation_x = old_inner_rect.x - ex;
actor.translation_y = old_inner_rect.y - ey;
actor.scale_x = 1.0 / scale_x;
actor.scale_y = 1.0 / scale_y;
actor.animate (Clutter.AnimationMode.EASE_IN_OUT_QUAD, duration,
scale_x: 1.0,
scale_y: 1.0,
translation_x: 0.0f,
translation_y: 0.0f);
return;
}
@ -974,34 +984,46 @@ namespace Gala
public override void unmaximize (Meta.WindowActor actor, int ex, int ey, int ew, int eh)
{
if (!AnimationSettings.get_default ().enable_animations || AnimationSettings.get_default ().snap_duration == 0) {
var duration = AnimationSettings.get_default ().snap_duration;
if (!AnimationSettings.get_default ().enable_animations || duration == 0) {
unmaximize_completed (actor);
return;
}
if (actor.get_meta_window ().window_type == WindowType.NORMAL) {
unmaximizing.add (actor);
Meta.Rectangle old_rect = { (int) actor.x, (int) actor.y, (int) actor.width, (int) actor.height };
var old_actor = Utils.get_window_actor_snapshot (actor, old_rect, old_rect);
float x, y, width, height;
actor.get_size (out width, out height);
actor.get_position (out x, out y);
old_actor.set_position (old_rect.x, old_rect.y);
float scale_x = (float)ew / width;
float scale_y = (float)eh / height;
float anchor_x = (float)(x - ex) * width / (ew - width);
float anchor_y = (float)(y - ey) * height / (eh - height);
ui_group.add_child (old_actor);
actor.move_anchor_point (anchor_x, anchor_y);
actor.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, AnimationSettings.get_default ().snap_duration,
scale_x:scale_x, scale_y:scale_y).completed.connect ( () => {
actor.move_anchor_point_from_gravity (Clutter.Gravity.NORTH_WEST);
actor.animate (Clutter.AnimationMode.LINEAR, 1, scale_x:1.0f,
scale_y:1.0f);//just scaling didnt want to work..
var scale_x = (double) ew / old_rect.width;
var scale_y = (double) eh / old_rect.height;
unmaximizing.remove (actor);
unmaximize_completed (actor);
old_actor.animate (Clutter.AnimationMode.EASE_IN_OUT_QUAD, duration,
x: (float) ex,
y: (float) ey,
opacity: 0,
scale_x: scale_x,
scale_y: scale_y).completed.connect (() => {
old_actor.destroy ();
});
unmaximize_completed (actor);
actor.scale_gravity = Clutter.Gravity.NORTH_WEST;
actor.translation_x = -actor.x;
actor.translation_y = -actor.y;
actor.scale_x = 1.0 / scale_x;
actor.scale_y = 1.0 / scale_y;
actor.animate (Clutter.AnimationMode.EASE_IN_OUT_QUAD, duration,
scale_x: 1.0,
scale_y: 1.0,
translation_x: 0.0,
translation_y: 0.0);
return;
}