Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix window maximize and unmaximize animations #1557

Merged
merged 13 commits into from
Feb 21, 2023
2 changes: 2 additions & 0 deletions data/gala.appdata.xml.in
Expand Up @@ -30,6 +30,8 @@
<issue url="https://github.com/elementary/gala/issues/1482">Duplicate "Plus" workspaces</issue>
<issue url="https://github.com/elementary/gala/issues/1203">Artifact around non native apps in the overview mode</issue>
<issue url="https://github.com/elementary/gala/issues/1505">"Not responding" dialog and not responding app close after inactivity</issue>
<issue url="https://github.com/elementary/gala/issues/1185">Unmaximize effect not working with mutter >= 3.38</issue>
<issue url="https://github.com/elementary/gala/issues/1536">Several (un-)maximize animations are not played</issue>
</issues>
</release>

Expand Down
34 changes: 9 additions & 25 deletions lib/Utils.vala
Expand Up @@ -271,44 +271,28 @@ namespace Gala {
/**
* Creates an actor showing the current contents of the given WindowActor.
*
* @param actor The actor from which to create a shnapshot
* @param actor The actor from which to create a snapshot
* @param inner_rect The inner (actually visible) rectangle of the window
* @param outer_rect The outer (input region) rectangle of the window
*
* @return A copy of the actor at that time or %NULL
*/
public static Clutter.Actor? get_window_actor_snapshot (
Meta.WindowActor actor,
Meta.Rectangle inner_rect,
Meta.Rectangle outer_rect
Meta.Rectangle inner_rect
) {
var texture = actor.get_texture () as Meta.ShapedTexture;
Clutter.Content content;

if (texture == null)
return null;

var surface = texture.get_image ({
inner_rect.x - outer_rect.x,
inner_rect.y - outer_rect.y,
inner_rect.width,
inner_rect.height
});

if (surface == null)
try {
content = actor.paint_to_content (inner_rect);
} catch (Error e) {
warning ("Could not create window snapshot: %s", e.message);
return null;

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;
container.content = content;

return container;
}
Expand Down
46 changes: 24 additions & 22 deletions src/WindowManager.vala
Expand Up @@ -104,6 +104,7 @@ namespace Gala {
private GLib.HashTable<Meta.Window, int> ws_assoc = new GLib.HashTable<Meta.Window, int> (direct_hash, direct_equal);
private Meta.SizeChange? which_change = null;
private Meta.Rectangle old_rect_size_change;
private Clutter.Actor latest_window_snapshot;

private GLib.Settings animations_settings;
private GLib.Settings behavior_settings;
Expand Down Expand Up @@ -1062,6 +1063,8 @@ namespace Gala {
public override void size_change (Meta.WindowActor actor, Meta.SizeChange which_change_local, Meta.Rectangle old_frame_rect, Meta.Rectangle old_buffer_rect) {
which_change = which_change_local;
old_rect_size_change = old_frame_rect;

latest_window_snapshot = Utils.get_window_actor_snapshot (actor, old_frame_rect);
}

// size_changed gets called after frame_rect has updated
Expand Down Expand Up @@ -1193,7 +1196,7 @@ namespace Gala {
var old_inner_rect = window_geometry != null ? window_geometry.inner : fallback;
var old_outer_rect = window_geometry != null ? window_geometry.outer : fallback;

var old_actor = Utils.get_window_actor_snapshot (actor, old_inner_rect, old_outer_rect);
var old_actor = Utils.get_window_actor_snapshot (actor, old_inner_rect);
if (old_actor == null) {
return;
}
Expand Down Expand Up @@ -1586,41 +1589,40 @@ namespace Gala {
offset_height = 0;
}

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);

if (old_actor == null) {
if (latest_window_snapshot == null) {
return;
}

unmaximizing.add (actor);

old_actor.set_position (old_rect.x, old_rect.y);
// FIXME: Gtk windows don't want to go out of bounds of screen when unmaximizing, so place them manually
// This is OS 7 (Mutter 42) specific, this was not needed in OS 6
window.move_frame (true, ex, ey);

ui_group.add_child (old_actor);
latest_window_snapshot.set_position (old_rect_size_change.x, old_rect_size_change.y);

var scale_x = (float) ew / old_rect.width;
var scale_y = (float) eh / old_rect.height;
ui_group.add_child (latest_window_snapshot);

old_actor.save_easing_state ();
old_actor.set_easing_mode (Clutter.AnimationMode.EASE_IN_OUT_QUAD);
old_actor.set_easing_duration (duration);
old_actor.set_position (ex, ey);
old_actor.set_scale (scale_x, scale_y);
old_actor.opacity = 0U;
old_actor.restore_easing_state ();
var scale_x = (float) ew / old_rect_size_change.width;
var scale_y = (float) eh / old_rect_size_change.height;

latest_window_snapshot.save_easing_state ();
latest_window_snapshot.set_easing_mode (Clutter.AnimationMode.EASE_IN_OUT_QUAD);
latest_window_snapshot.set_easing_duration (duration);
latest_window_snapshot.set_position (ex, ey);
latest_window_snapshot.set_scale (scale_x, scale_y);
latest_window_snapshot.opacity = 0U;
latest_window_snapshot.restore_easing_state ();

ulong unmaximize_old_handler_id = 0UL;
unmaximize_old_handler_id = old_actor.transitions_completed.connect (() => {
old_actor.disconnect (unmaximize_old_handler_id);
old_actor.destroy ();
unmaximize_old_handler_id = latest_window_snapshot.transitions_completed.connect (() => {
latest_window_snapshot.disconnect (unmaximize_old_handler_id);
latest_window_snapshot.destroy ();
});

var maximized_x = actor.x;
var maximized_y = actor.y;
actor.set_pivot_point (0.0f, 0.0f);
actor.set_position (ex, ey);
actor.set_translation (-ex + offset_x * (1.0f / scale_x - 1.0f) + maximized_x, -ey + offset_y * (1.0f / scale_y - 1.0f) + maximized_y, 0.0f);
actor.set_translation (-ex + offset_x * (1.0f / scale_x - 1.0f) + old_rect_size_change.x, -ey + offset_y * (1.0f / scale_y - 1.0f) + old_rect_size_change.y, 0.0f);
actor.set_scale (1.0f / scale_x, 1.0f / scale_y);

actor.save_easing_state ();
Expand Down