windowManager: Fix fullscreen animations of wayland clients

Wayland clients are in control of their window size so the existing
mutter plugin API, which assumes size changes are synchronous, doesn't
work for them since when our size-change handler runs the MetaWindow's
size isn't final yet.

To fix this, the mutter plugin API was extended with a size-changed
vfunc that lets us know when the MetaWindow size has actually
changed. This way we can make the window snapshot and get the old
window size on the existing size-change handler and later, on the new
size-changed handler, get the new size and start the animation.

https://bugzilla.gnome.org/show_bug.cgi?id=770345
This commit is contained in:
Rui Matos 2016-09-26 17:58:25 +02:00
parent 68b671a4f4
commit 7bc1d57ad7

View File

@ -706,6 +706,7 @@ const WindowManager = new Lang.Class({
this._shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow)); this._shellwm.connect('minimize', Lang.bind(this, this._minimizeWindow));
this._shellwm.connect('unminimize', Lang.bind(this, this._unminimizeWindow)); this._shellwm.connect('unminimize', Lang.bind(this, this._unminimizeWindow));
this._shellwm.connect('size-change', Lang.bind(this, this._sizeChangeWindow)); this._shellwm.connect('size-change', Lang.bind(this, this._sizeChangeWindow));
this._shellwm.connect('size-changed', Lang.bind(this, this._sizeChangedWindow));
this._shellwm.connect('map', Lang.bind(this, this._mapWindow)); this._shellwm.connect('map', Lang.bind(this, this._mapWindow));
this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow)); this._shellwm.connect('destroy', Lang.bind(this, this._destroyWindow));
this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding)); this._shellwm.connect('filter-keybinding', Lang.bind(this, this._filterKeybinding));
@ -1255,37 +1256,16 @@ const WindowManager = new Lang.Class({
return; return;
} }
if (whichChange == Meta.SizeChange.FULLSCREEN) if (whichChange == Meta.SizeChange.FULLSCREEN ||
this._fullscreenWindow(shellwm, actor, oldFrameRect, oldBufferRect); whichChange == Meta.SizeChange.UNFULLSCREEN)
else if (whichChange == Meta.SizeChange.UNFULLSCREEN) this._fullscreenAnimation(shellwm, actor, oldFrameRect, whichChange);
this._unfullscreenWindow(shellwm, actor, oldFrameRect, oldBufferRect);
else else
shellwm.completed_size_change(actor); shellwm.completed_size_change(actor);
}, },
_fullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) { _fullscreenAnimation: function(shellwm, actor, oldFrameRect, change) {
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
actor.translation_x = oldFrameRect.x - monitor.x;
actor.translation_y = oldFrameRect.y - monitor.y;
this._fullscreenAnimation(shellwm, actor, oldFrameRect);
},
_unfullscreenWindow: function(shellwm, actor, oldFrameRect, oldBufferRect) {
let targetRect = actor.meta_window.get_frame_rect();
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
actor.translation_x = -(targetRect.x - monitor.x);
actor.translation_y = -(targetRect.y - monitor.y);
this._fullscreenAnimation(shellwm, actor, oldFrameRect);
},
_fullscreenAnimation: function(shellwm, actor, oldFrameRect) {
this._resizing.push(actor);
// Position a clone of the window on top of the old position, // Position a clone of the window on top of the old position,
// while actor updates are frozen. // while actor updates are frozen.
// Note that the MetaWindow has up to date sizing information for
// the new geometry already.
let targetRect = actor.meta_window.get_frame_rect();
let actorContent = Shell.util_get_content_for_window_actor(actor, oldFrameRect); let actorContent = Shell.util_get_content_for_window_actor(actor, oldFrameRect);
let actorClone = new St.Widget({ content: actorContent }); let actorClone = new St.Widget({ content: actorContent });
actorClone.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS); actorClone.set_offscreen_redirect(Clutter.OffscreenRedirect.ALWAYS);
@ -1293,10 +1273,26 @@ const WindowManager = new Lang.Class({
actorClone.set_size(oldFrameRect.width, oldFrameRect.height); actorClone.set_size(oldFrameRect.width, oldFrameRect.height);
Main.uiGroup.add_actor(actorClone); Main.uiGroup.add_actor(actorClone);
actor.__fullscreenClone = actorClone; let rect = change == Meta.SizeChange.FULLSCREEN ? oldFrameRect : null;
let scaleX = targetRect.width / oldFrameRect.width; if (this._clearFullscreenInfo(actor))
let scaleY = targetRect.height / oldFrameRect.height; this._shellwm.completed_size_change(actor);
actor.__fullscreenInfo = { clone: actorClone,
oldRect: rect };
},
_sizeChangedWindow: function(shellwm, actor) {
if (!actor.__fullscreenInfo)
return;
let actorClone = actor.__fullscreenInfo.clone;
let targetRect = actor.meta_window.get_frame_rect();
let scaleX = targetRect.width / actorClone.width;
let scaleY = targetRect.height / actorClone.height;
this._resizing.push(actor);
// Now scale and fade out the clone // Now scale and fade out the clone
Tweener.addTween(actorClone, Tweener.addTween(actorClone,
@ -1309,9 +1305,17 @@ const WindowManager = new Lang.Class({
transition: 'easeOutQuad' transition: 'easeOutQuad'
}); });
let monitor = Main.layoutManager.monitors[actor.meta_window.get_monitor()];
let oldRect = actor.__fullscreenInfo.oldRect;
if (oldRect) {
actor.translation_x = oldRect.x - monitor.x;
actor.translation_y = oldRect.y - monitor.y;
} else {
actor.translation_x = -(targetRect.x - monitor.x);
actor.translation_y = -(targetRect.y - monitor.y);
}
// Now set scale the actor to size it as the clone. // Now set scale the actor to size it as the clone.
// Note that the caller of this function already set a translation
// on the actor.
actor.scale_x = 1 / scaleX; actor.scale_x = 1 / scaleX;
actor.scale_y = 1 / scaleY; actor.scale_y = 1 / scaleY;
@ -1337,6 +1341,15 @@ const WindowManager = new Lang.Class({
shellwm.completed_size_change(actor); shellwm.completed_size_change(actor);
}, },
_clearFullscreenInfo: function(actor) {
if (actor.__fullscreenInfo) {
actor.__fullscreenInfo.clone.destroy();
delete actor.__fullscreenInfo;
return true;
}
return false;
},
_sizeChangeWindowDone: function(shellwm, actor) { _sizeChangeWindowDone: function(shellwm, actor) {
if (this._removeEffect(this._resizing, actor)) { if (this._removeEffect(this._resizing, actor)) {
Tweener.removeTweens(actor); Tweener.removeTweens(actor);
@ -1344,23 +1357,13 @@ const WindowManager = new Lang.Class({
actor.scale_y = 1.0; actor.scale_y = 1.0;
actor.translation_x = 0; actor.translation_x = 0;
actor.translation_y = 0; actor.translation_y = 0;
this._clearFullscreenInfo(actor);
let actorClone = actor.__fullscreenClone;
if (actorClone) {
actorClone.destroy();
delete actor.__fullscreenClone;
}
} }
}, },
_sizeChangeWindowOverwritten: function(shellwm, actor) { _sizeChangeWindowOverwritten: function(shellwm, actor) {
if (this._removeEffect(this._resizing, actor)) { if (this._removeEffect(this._resizing, actor))
let actorClone = actor.__fullscreenClone; this._clearFullscreenInfo(actor);
if (actorClone) {
actorClone.destroy();
delete actor.__fullscreenClone;
}
}
}, },
_hasAttachedDialogs: function(window, ignoreWindow) { _hasAttachedDialogs: function(window, ignoreWindow) {