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:
parent
68b671a4f4
commit
7bc1d57ad7
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user