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; 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 * Ring the system bell, will most likely emit a <beep> error sound or, if the
* audible bell is disabled, flash the screen * audible bell is disabled, flash the screen

View File

@ -36,7 +36,15 @@ namespace Gala
if (window.on_all_workspaces) if (window.on_all_workspaces)
instance.listen_on_window (window); 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 () public static WindowListener get_default ()
@ -47,11 +55,14 @@ namespace Gala
public signal void window_no_longer_on_all_workspaces (Window window); 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 () WindowListener ()
{ {
listened_windows = new Gee.LinkedList<Window> (); listened_windows_sticky = new Gee.LinkedList<Window> ();
} }
public void listen_on_window (Window 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.notify["on-all-workspaces"].connect (window_on_all_workspaces_changed);
window.unmanaged.connect (window_removed); window.unmanaged.connect (window_removed);
listened_windows.add (window); listened_windows_sticky.add (window);
} }
void window_on_all_workspaces_changed (Object object, ParamSpec param) void window_on_all_workspaces_changed (Object object, ParamSpec param)
@ -73,15 +84,46 @@ namespace Gala
return; return;
window.notify.disconnect (window_on_all_workspaces_changed); window.notify.disconnect (window_on_all_workspaces_changed);
window.unmanaged.disconnect (window_removed); window.unmanaged.disconnect (sticky_window_removed);
listened_windows.remove (window); listened_windows_sticky.remove (window);
window_no_longer_on_all_workspaces (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) 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) public override void maximize (WindowActor actor, int ex, int ey, int ew, int eh)
{ {
float x, y, width, height; var duration = AnimationSettings.get_default ().snap_duration;
actor.get_size (out width, out height);
actor.get_position (out x, out y);
if (!AnimationSettings.get_default ().enable_animations || if (!AnimationSettings.get_default ().enable_animations || duration == 0) {
AnimationSettings.get_default ().snap_duration == 0 ||
(x == ex && y == ey && ew == width && eh == height)) {
maximize_completed (actor); maximize_completed (actor);
return; return;
} }
if (actor.get_meta_window ().window_type == WindowType.NORMAL) { 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; old_actor.set_position (old_inner_rect.x, old_inner_rect.y);
float scale_y = (float)eh / height;
float anchor_x = (float)(x - ex) * width / (ew - width);
float anchor_y = (float)(y - ey) * height / (eh - height);
//reset the actor's anchors ui_group.add_child (old_actor);
actor.scale_gravity = actor.anchor_gravity = Clutter.Gravity.NORTH_WEST;
actor.move_anchor_point (anchor_x, anchor_y); var scale_x = (double) ew / old_inner_rect.width;
actor.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, AnimationSettings.get_default ().snap_duration, var scale_y = (double) eh / old_inner_rect.height;
scale_x:scale_x, scale_y:scale_y).get_timeline ().completed.connect ( () => {
actor.anchor_gravity = Clutter.Gravity.NORTH_WEST; old_actor.animate (Clutter.AnimationMode.EASE_IN_OUT_QUAD, duration,
actor.set_scale (1.0, 1.0); x: (float) ex,
y: (float) ey,
opacity: 0,
scale_x: scale_x,
scale_y: scale_y).completed.connect (() => {
old_actor.destroy ();
maximizing.remove (actor); actor.translation_x = 0;
maximize_completed (actor); 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; return;
} }
@ -974,34 +984,46 @@ namespace Gala
public override void unmaximize (Meta.WindowActor actor, int ex, int ey, int ew, int eh) 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); unmaximize_completed (actor);
return; return;
} }
if (actor.get_meta_window ().window_type == WindowType.NORMAL) { 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; old_actor.set_position (old_rect.x, old_rect.y);
actor.get_size (out width, out height);
actor.get_position (out x, out y);
float scale_x = (float)ew / width; ui_group.add_child (old_actor);
float scale_y = (float)eh / height;
float anchor_x = (float)(x - ex) * width / (ew - width);
float anchor_y = (float)(y - ey) * height / (eh - height);
actor.move_anchor_point (anchor_x, anchor_y); var scale_x = (double) ew / old_rect.width;
actor.animate (Clutter.AnimationMode.EASE_IN_OUT_SINE, AnimationSettings.get_default ().snap_duration, var scale_y = (double) eh / old_rect.height;
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..
unmaximizing.remove (actor); old_actor.animate (Clutter.AnimationMode.EASE_IN_OUT_QUAD, duration,
unmaximize_completed (actor); 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; return;
} }