diff --git a/js/ui/animation.js b/js/ui/animation.js index a1f257efcebee05ef4246f4e431c3861ac24938d..18c837e822ab6086f4208d122bb84104a34c9777 100644 --- a/js/ui/animation.js +++ b/js/ui/animation.js @@ -167,8 +167,8 @@ var Spinner = class extends AnimatedIcon { if (this._animate) { this.actor.ease({ opacity: 0, - time: SPINNER_ANIMATION_TIME, - transition: 'linear', + duration: SPINNER_ANIMATION_TIME, + mode: Clutter.AnimationMode.LINEAR, onComplete: () => super.stop() }); } else { diff --git a/js/ui/dnd.js b/js/ui/dnd.js index 786d6541992420b112f99d805160eec4feb19561..b62e6a3c8e1e3f967b846ec81a09bdceb28f3254 100644 --- a/js/ui/dnd.js +++ b/js/ui/dnd.js @@ -427,16 +427,15 @@ var _Draggable = class _Draggable { scale_x: scale * origScale, scale_y: scale * origScale, duration: SCALE_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD - }); - - this._dragActor.get_transition('scale-x').connect('new-frame', () => { - let currentScale = this._dragActor.scale_x / origScale; - this._dragOffsetX = currentScale * origDragOffsetX; - this._dragOffsetY = currentScale * origDragOffsetY; - this._dragActor.set_position( - this._dragX + this._dragOffsetX, - this._dragY + this._dragOffsetY); + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onNewFrame: () => { + let currentScale = this._dragActor.scale_x / origScale; + this._dragOffsetX = currentScale * origDragOffsetX; + this._dragOffsetY = currentScale * origDragOffsetY; + this._dragActor.set_position( + this._dragX + this._dragOffsetX, + this._dragY + this._dragOffsetY); + } }); } } diff --git a/js/ui/environment.js b/js/ui/environment.js index 38d1d281a61ab6e3ff10103d29bac655e6b29e56..ef13a721146fec1e3c2a16102ef65cec9c6cdbce 100644 --- a/js/ui/environment.js +++ b/js/ui/environment.js @@ -75,14 +75,25 @@ function _makeEaseCallback(params, cleanup) { }; } +function _makeFrameCallback(params) { + let onNewFrame = params.onNewFrame; + delete params.onNewFrame; + + if (onNewFrame) + return (progress) => onNewFrame(progress); + return null; +} + function _getPropertyTarget(actor, propName) { if (!propName.startsWith('@')) - return [actor, propName]; + return [actor, propName.split('-').join('_')]; let [type, name, prop] = propName.split('.'); + if (prop) + prop = prop.split('-').join('_'); switch (type) { case '@layout': - return [actor.layout_manager, name]; + return [actor.layout_manager, name.split('-').join('_')]; case '@actions': return [actor.get_action(name), prop]; case '@constraints': @@ -113,10 +124,21 @@ function _easeActor(actor, params) { let cleanup = () => Meta.enable_unredirect_for_display(global.display); let callback = _makeEaseCallback(params, cleanup); - - // cancel overwritten transitions - let animatedProps = Object.keys(params).map(p => p.replace('_', '-', 'g')); - animatedProps.forEach(p => actor.remove_transition(p)); + let frameCallback = _makeFrameCallback(params); + + // sanitize property names and cancel overwritten transitions + let animatedProps = []; + Object.keys(params).forEach(p => { + let pspecName = p.split('_').join('-'); + actor.remove_transition(pspecName); + animatedProps.push(pspecName); + + if (p.indexOf('-') !== -1) { + let prop = p.split('-').join('_'); + params[prop] = params[p]; + delete params[p]; + } + }); actor.set(params); actor.restore_easing_state(); @@ -124,10 +146,15 @@ function _easeActor(actor, params) { let transition = animatedProps.map(p => actor.get_transition(p)) .find(t => t !== null); - if (transition) + if (transition) { + if (frameCallback) + transition.connect('new-frame', (t) => frameCallback(t.get_progress())); transition.connect('stopped', (t, finished) => callback(finished)); - else + } else { + if (frameCallback) + frameCallback(1.0); callback(true); + } } function _easeActorProperty(actor, propName, target, params) { @@ -149,6 +176,7 @@ function _easeActorProperty(actor, propName, target, params) { let cleanup = () => Meta.enable_unredirect_for_display(global.display); let callback = _makeEaseCallback(params, cleanup); + let frameCallback = _makeFrameCallback(params); // cancel overwritten transition actor.remove_transition(propName); @@ -157,6 +185,9 @@ function _easeActorProperty(actor, propName, target, params) { let [obj, prop] = _getPropertyTarget(actor, propName); obj[prop] = target; + if (frameCallback) + frameCallback(1.0); + callback(true); return; @@ -172,6 +203,9 @@ function _easeActorProperty(actor, propName, target, params) { transition.set_to(target); + if (frameCallback) + transition.connect('new-frame', (t) => frameCallback(t.get_progress())); + transition.connect('stopped', (t, finished) => callback(finished)); } @@ -293,7 +327,7 @@ function adjustAnimationTime(msecs) { let settings = St.Settings.get(); if (!settings.enable_animations) - return 1; + return 0; return settings.slow_down_factor * msecs; } diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js index ffddd11bdfa91f489cf39043ae66dd8e53142004..d893fd4639efa7de4970f437f6508e4511a65702 100644 --- a/js/ui/iconGrid.js +++ b/js/ui/iconGrid.js @@ -436,6 +436,8 @@ var IconGrid = GObject.registerClass({ * set of items to be animated. */ _getChildrenToAnimate() { + if (!St.Settings.get().enable_animations) + return []; return this._getVisibleChildren().filter(child => child.opacity > 0); } diff --git a/js/ui/messageList.js b/js/ui/messageList.js index 4dcdb6d7fd6ffc7ea8c7b0f2ad8acccecafc0879..65d99800126699705627c6ec183f1a5b9a098577 100644 --- a/js/ui/messageList.js +++ b/js/ui/messageList.js @@ -438,47 +438,38 @@ var Message = class Message { this.setExpandedBody(this._expandedLabel.actor); } - if (animate) { - this._bodyStack.ease_property('@layout.expansion', 1, { - progress_mode: Clutter.AnimationMode.EASE_OUT_QUAD, - duration: MessageTray.ANIMATION_TIME, - }); + let duration = animate ? MessageTray.ANIMATION_TIME : 0; + this._bodyStack.ease_property('@layout.expansion', 1, { + progress_mode: Clutter.AnimationMode.EASE_OUT_QUAD, + duration, + }); - this._actionBin.scale_y = 0; - this._actionBin.ease({ - scale_y: 1, - duration: MessageTray.ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD - }); - } else { - this._bodyStack.layout_manager.expansion = 1; - this._actionBin.scale_y = 1; - } + this._actionBin.scale_y = 0; + this._actionBin.ease({ + scale_y: 1, + duration, + mode: Clutter.AnimationMode.EASE_OUT_QUAD + }); this.emit('expanded'); } unexpand(animate) { - if (animate) { - this._bodyStack.ease_property('@layout.expansion', 0, { - progress_mode: Clutter.AnimationMode.EASE_OUT_QUAD, - duration: MessageTray.ANIMATION_TIME, - }); + let duration = animate ? MessageTray.ANIMATION_TIME : 0; + this._bodyStack.ease_property('@layout.expansion', 0, { + progress_mode: Clutter.AnimationMode.EASE_OUT_QUAD, + duration, + }); - this._actionBin.ease({ - scale_y: 0, - duration: MessageTray.ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - this._actionBin.hide(); - this.expanded = false; - } - }); - } else { - this._bodyStack.layout_manager.expansion = 0; - this._actionBin.scale_y = 0; - this.expanded = false; - } + this._actionBin.ease({ + scale_y: 0, + duration, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => { + this._actionBin.hide(); + this.expanded = false; + } + }); this.emit('unexpanded'); } @@ -627,21 +618,16 @@ var MessageListSection = class MessageListSection { this._messages.delete(message); - if (animate) { - obj.container.ease({ - scale_x: 0, - scale_y: 0, - duration: MESSAGE_ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_QUAD, - onComplete: () => { - obj.container.destroy(); - global.sync_pointer(); - } - }); - } else { - obj.container.destroy(); - global.sync_pointer(); - } + obj.container.ease({ + scale_x: 0, + scale_y: 0, + duration: animate ? MESSAGE_ANIMATION_TIME : 0, + mode: Clutter.AnimationMode.EASE_OUT_QUAD, + onComplete: () => { + obj.container.destroy(); + global.sync_pointer(); + } + }); } clear() { diff --git a/js/ui/messageTray.js b/js/ui/messageTray.js index 560deda6ff35af2531644ebe820549779d3e5c24..cc0dade96306ea03f899901252b24aa55993e4af 100644 --- a/js/ui/messageTray.js +++ b/js/ui/messageTray.js @@ -1398,29 +1398,23 @@ var MessageTray = class MessageTray { this._resetNotificationLeftTimeout(); this._bannerBin.remove_all_transitions(); - if (animate) { - this._notificationState = State.HIDING; - this._bannerBin.ease({ - opacity: 0, - duration: ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_BACK - }); - this._bannerBin.ease({ - y: -this._bannerBin.height, - duration: ANIMATION_TIME, - mode: Clutter.AnimationMode.EASE_OUT_BACK, - onComplete: () => { - this._notificationState = State.HIDDEN; - this._hideNotificationCompleted(); - this._updateState(); - } - }); - } else { - this._bannerBin.y = -this._bannerBin.height; - this._bannerBin.opacity = 0; - this._notificationState = State.HIDDEN; - this._hideNotificationCompleted(); - } + let duration = animate ? ANIMATION_TIME : 0; + this._notificationState = State.HIDING; + this._bannerBin.ease({ + opacity: 0, + duration, + mode: Clutter.AnimationMode.EASE_OUT_BACK + }); + this._bannerBin.ease({ + y: -this._bannerBin.height, + duration, + mode: Clutter.AnimationMode.EASE_OUT_BACK, + onComplete: () => { + this._notificationState = State.HIDDEN; + this._hideNotificationCompleted(); + this._updateState(); + } + }); } _hideNotificationCompleted() { diff --git a/js/ui/overview.js b/js/ui/overview.js index e4837c8211beec68b5089a89575dde7984486bb1..00fb77a1bbfe537f4c16917c216b1684ce9c3f14 100644 --- a/js/ui/overview.js +++ b/js/ui/overview.js @@ -531,6 +531,10 @@ var Overview = class { Meta.disable_unredirect_for_display(global.display); this.viewSelector.show(); + Main.layoutManager.overviewGroup.set_child_above_sibling( + this._coverPane, null); + this._coverPane.show(); + this._overview.opacity = 0; this._overview.ease({ opacity: 255, @@ -540,8 +544,6 @@ var Overview = class { }); this._shadeBackgrounds(); - this._coverPane.raise_top(); - this._coverPane.show(); this.emit('showing'); } @@ -594,6 +596,10 @@ var Overview = class { this.viewSelector.animateFromOverview(); + Main.layoutManager.overviewGroup.set_child_above_sibling( + this._coverPane, null); + this._coverPane.show(); + // Make other elements fade out. this._overview.ease({ opacity: 0, @@ -603,8 +609,6 @@ var Overview = class { }); this._unshadeBackgrounds(); - this._coverPane.raise_top(); - this._coverPane.show(); this.emit('hiding'); } diff --git a/js/ui/popupMenu.js b/js/ui/popupMenu.js index 49ed823b127ea78476571cb4cd21dd9eda3fc463..aa17c3eb0dff95a9bbcde601dff1de8207a5a6a0 100644 --- a/js/ui/popupMenu.js +++ b/js/ui/popupMenu.js @@ -1023,14 +1023,12 @@ var PopupSubMenu = class extends PopupMenuBase { mode: Clutter.AnimationMode.EASE_OUT_EXPO, onComplete: () => this.actor.set_height(-1) }); - this._arrow.ease({ - rotation_angle_z: targetAngle, - duration: 250, - mode: Clutter.AnimationMode.EASE_OUT_EXPO - }); - } else { - this._arrow.rotation_angle_z = targetAngle; } + this._arrow.ease({ + rotation_angle_z: targetAngle, + duration: animate ? 250 : 0, + mode: Clutter.AnimationMode.EASE_OUT_EXPO + }); } close(animate) { @@ -1046,25 +1044,21 @@ var PopupSubMenu = class extends PopupMenuBase { if (animate && this._needsScrollbar()) animate = false; - if (animate) { - this.actor.ease({ - height: 0, - duration: 250, - mode: Clutter.AnimationMode.EASE_OUT_EXPO, - onComplete: () => { - this.actor.hide(); - this.actor.set_height(-1); - } - }); - this._arrow.ease({ - rotation_angle_z: 0, - duration: 250, - mode: Clutter.AnimationMode.EASE_OUT_EXPO - }); - } else { - this._arrow.rotation_angle_z = 0; - this.actor.hide(); - } + let duration = animate ? 250 : 0; + this.actor.ease({ + height: 0, + duration, + mode: Clutter.AnimationMode.EASE_OUT_EXPO, + onComplete: () => { + this.actor.hide(); + this.actor.set_height(-1); + } + }); + this._arrow.ease({ + rotation_angle_z: 0, + duration, + mode: Clutter.AnimationMode.EASE_OUT_EXPO + }); } _onKeyPressEvent(actor, event) { diff --git a/js/ui/tweener.js b/js/ui/tweener.js index 221438c1bd7a5fdf4910b41b7d37a5e93f2d10cf..56f430a6910d48fc77c4b72ca7eaa6ee2fb1d6dc 100644 --- a/js/ui/tweener.js +++ b/js/ui/tweener.js @@ -7,7 +7,7 @@ const { Clutter, GLib, Shell } = imports.gi; const Signals = imports.signals; const Tweener = imports.tweener.tweener; -const { adjustAnimationTime } = imports.ui.environment; +const Environment = imports.ui.environment; // This is a wrapper around imports.tweener.tweener that adds a bit of // Clutter integration. If the tweening target is a Clutter.Actor, then @@ -39,6 +39,11 @@ function addTween(target, tweeningParameters) { Tweener.addTween(target, tweeningParameters); } +function adjustAnimationTime(msecs) { + let time = Environment.adjustAnimationTime(1000 * msecs) / 1000; + return time ? time : 0.000001; +} + function _wrapTweening(target, tweeningParameters) { let state = _getTweenState(target); @@ -54,9 +59,9 @@ function _wrapTweening(target, tweeningParameters) { let { time, delay } = tweeningParameters; if (!isNaN(time)) - tweeningParameters['time'] = adjustAnimationTime(1000 * time) / 1000; + tweeningParameters['time'] = adjustAnimationTime(time); if (!isNaN(delay)) - tweeningParameters['delay'] = adjustAnimationTime(1000 * delay) / 1000; + tweeningParameters['delay'] = adjustAnimationTime(delay); _addHandler(target, tweeningParameters, 'onComplete', _tweenCompleted); } diff --git a/js/ui/workspace.js b/js/ui/workspace.js index a93b19add9f7b73b622e2620fefd9d8d721b2ae6..4d015ac61daf7f234c28fe94447737d07a9a0cbb 100644 --- a/js/ui/workspace.js +++ b/js/ui/workspace.js @@ -561,10 +561,8 @@ var WindowOverlay = class { else buttonX = cloneX + (cloneWidth - button._overlap); - if (animate) - this._animateOverlayActor(button, Math.floor(buttonX), Math.floor(buttonY), button.width); - else - button.set_position(Math.floor(buttonX), Math.floor(buttonY)); + this._resizeOverlayActor(button, animate, + Math.floor(buttonX), Math.floor(buttonY), button.width); // Clutter.Actor.get_preferred_width() will return the fixed width if // one is set, so we need to reset the width by calling set_width(-1), @@ -582,25 +580,16 @@ var WindowOverlay = class { let titleX = cloneX + (cloneWidth - titleWidth) / 2; let titleY = cloneY + cloneHeight - (title.height - this.borderSize) / 2; - if (animate) { - this._animateOverlayActor(title, Math.floor(titleX), Math.floor(titleY), titleWidth); - } else { - title.width = titleWidth; - title.set_position(Math.floor(titleX), Math.floor(titleY)); - } + this._resizeOverlayActor(title, animate, + Math.floor(titleX), Math.floor(titleY), titleWidth); let borderX = cloneX - this.borderSize; let borderY = cloneY - this.borderSize; let borderWidth = cloneWidth + 2 * this.borderSize; let borderHeight = cloneHeight + 2 * this.borderSize; - if (animate) { - this._animateOverlayActor(this.border, borderX, borderY, - borderWidth, borderHeight); - } else { - this.border.set_position(borderX, borderY); - this.border.set_size(borderWidth, borderHeight); - } + this._resizeOverlayActor(this.border, animate, + borderX, borderY, borderWidth, borderHeight); } _getCaption() { @@ -613,10 +602,10 @@ var WindowOverlay = class { return app.get_name(); } - _animateOverlayActor(actor, x, y, width, height) { + _resizeOverlayActor(actor, animate, x, y, width, height) { let params = { x, y, width, - duration: Overview.ANIMATION_TIME, + duration: animate ? Overview.ANIMATION_TIME : 0, mode: Clutter.AnimationMode.EASE_OUT_QUAD }; @@ -1349,7 +1338,9 @@ var Workspace = class { clone.positioned = true; } + let animateClone; if (animate && isOnCurrentWorkspace) { + animateClone = true; if (!clone.metaWindow.showing_on_its_workspace()) { /* Hidden windows should fade in and grow * therefore we need to resize them now so they @@ -1368,17 +1359,9 @@ var Workspace = class { duration: Overview.ANIMATION_TIME }); } - - this._animateClone(clone, clone.overlay, x, y, scale); - } else { - // cancel any active tweens (otherwise they might override our changes) - clone.remove_all_transitions(); - clone.set_position(x, y); - clone.set_scale(scale, scale); - clone.set_opacity(255); - clone.overlay.relayout(false); - this._showWindowOverlay(clone, clone.overlay); } + + this._moveClone(clone, clone.overlay, animateClone, x, y, scale); } } @@ -1401,18 +1384,18 @@ var Workspace = class { } } - _animateClone(clone, overlay, x, y, scale) { + _moveClone(clone, overlay, animate, x, y, scale) { + clone.overlay.relayout(true); clone.ease({ x, y, scale_x: scale, scale_y: scale, - duration: Overview.ANIMATION_TIME, + duration: animate ? Overview.ANIMATION_TIME : 0, mode: Clutter.AnimationMode.EASE_OUT_QUAD, onComplete: () => { this._showWindowOverlay(clone, overlay); } }); - clone.overlay.relayout(true); } _showWindowOverlay(clone, overlay) {