diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js
index 78bf29dd9..b10c26788 100644
--- a/js/gdm/authPrompt.js
+++ b/js/gdm/authPrompt.js
@@ -15,7 +15,7 @@ const GdmUtil = imports.gdm.util;
const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
const UserWidget = imports.ui.userWidget;
-const Util = imports.misc.util;
+const {wiggle} = imports.misc.animationUtils;
var DEFAULT_BUTTON_WELL_ICON_SIZE = 16;
var DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1000;
@@ -391,7 +391,7 @@ var AuthPrompt = GObject.registerClass({
this.verificationStatus = AuthPromptStatus.VERIFICATION_FAILED;
if (wasQueryingService)
- Util.wiggle(this._entry);
+ wiggle(this._entry);
}
_onVerificationComplete() {
@@ -566,7 +566,7 @@ var AuthPrompt = GObject.registerClass({
this._message.opacity = 0;
}
- Util.wiggle(this._message, wiggleParameters);
+ wiggle(this._message, wiggleParameters);
}
updateSensitivity(sensitive) {
diff --git a/js/js-resources.gresource.xml b/js/js-resources.gresource.xml
index b1f537cc8..6aa88ce21 100644
--- a/js/js-resources.gresource.xml
+++ b/js/js-resources.gresource.xml
@@ -11,6 +11,7 @@
gdm/realmd.js
gdm/util.js
+ misc/animationUtils.js
misc/config.js
misc/extensionUtils.js
misc/fileUtils.js
diff --git a/js/misc/animationUtils.js b/js/misc/animationUtils.js
new file mode 100644
index 000000000..619d719bd
--- /dev/null
+++ b/js/misc/animationUtils.js
@@ -0,0 +1,117 @@
+/* exported adjustAnimationTime, ensureActorVisibleInScrollView, wiggle */
+
+const St = imports.gi.St;
+const Clutter = imports.gi.Clutter;
+
+const Params = imports.misc.params;
+
+var SCROLL_TIME = 100;
+
+const WIGGLE_OFFSET = 6;
+const WIGGLE_DURATION = 65;
+const N_WIGGLES = 3;
+
+/**
+ * adjustAnimationTime:
+ *
+ * @param {number} msecs - time in milliseconds
+ *
+ * Adjust `msecs` to account for St's enable-animations
+ * and slow-down-factor settings
+ */
+function adjustAnimationTime(msecs) {
+ const settings = St.Settings.get();
+
+ if (!settings.enable_animations)
+ return 0;
+ return settings.slow_down_factor * msecs;
+}
+
+/**
+ * Animate scrolling a scrollview until an actor is visible.
+ *
+ * @param {St.ScrollView} scrollView - the scroll view the actor is in
+ * @param {Clutter.Actor} actor - the actor
+ */
+function ensureActorVisibleInScrollView(scrollView, actor) {
+ const {adjustment} = scrollView.vscroll;
+ let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();
+
+ let offset = 0;
+ const vfade = scrollView.get_effect('fade');
+ if (vfade)
+ offset = vfade.fade_margins.top;
+
+ let box = actor.get_allocation_box();
+ let y1 = box.y1, y2 = box.y2;
+
+ let parent = actor.get_parent();
+ while (parent !== scrollView) {
+ if (!parent)
+ throw new Error('actor not in scroll view');
+
+ box = parent.get_allocation_box();
+ y1 += box.y1;
+ y2 += box.y1;
+ parent = parent.get_parent();
+ }
+
+ if (y1 < value + offset)
+ value = Math.max(0, y1 - offset);
+ else if (y2 > value + pageSize - offset)
+ value = Math.min(upper, y2 + offset - pageSize);
+ else
+ return;
+
+ adjustment.ease(value, {
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ duration: SCROLL_TIME,
+ });
+}
+
+/**
+ * "Wiggles" a clutter actor. A "wiggle" is an animation the moves an actor
+ * back and forth on the X axis a specified amount of times.
+ *
+ * @param {Clutter.Actor} actor - an actor to animate
+ * @param {object} params - options for the animation
+ * @param {number} params.offset - the offset to move the actor by per-wiggle
+ * @param {number} params.duration - the amount of time to move the actor per-wiggle
+ * @param {number} params.wiggleCount - the number of times to wiggle the actor
+ */
+function wiggle(actor, params) {
+ if (!St.Settings.get().enable_animations)
+ return;
+
+ params = Params.parse(params, {
+ offset: WIGGLE_OFFSET,
+ duration: WIGGLE_DURATION,
+ wiggleCount: N_WIGGLES,
+ });
+ actor.translation_x = 0;
+
+ // Accelerate before wiggling
+ actor.ease({
+ translation_x: -params.offset,
+ duration: params.duration,
+ mode: Clutter.AnimationMode.EASE_OUT_QUAD,
+ onComplete: () => {
+ // Wiggle
+ actor.ease({
+ translation_x: params.offset,
+ duration: params.duration,
+ mode: Clutter.AnimationMode.LINEAR,
+ repeatCount: params.wiggleCount,
+ autoReverse: true,
+ onComplete: () => {
+ // Decelerate and return to the original position
+ actor.ease({
+ translation_x: 0,
+ duration: params.duration,
+ mode: Clutter.AnimationMode.EASE_IN_QUAD,
+ });
+ },
+ });
+ },
+ });
+}
diff --git a/js/misc/util.js b/js/misc/util.js
index e4097acc1..8dc6b9905 100644
--- a/js/misc/util.js
+++ b/js/misc/util.js
@@ -1,9 +1,8 @@
// -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*-
/* exported findUrls, spawn, spawnCommandLine, spawnApp, trySpawnCommandLine,
- createTimeLabel, insertSorted, ensureActorVisibleInScrollView,
- wiggle, lerp, GNOMEversionCompare, DBusSenderChecker, Highlighter */
+ createTimeLabel, insertSorted, lerp, GNOMEversionCompare,
+ DBusSenderChecker, Highlighter */
-const Clutter = imports.gi.Clutter;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Shell = imports.gi.Shell;
@@ -11,15 +10,8 @@ const St = imports.gi.St;
const GnomeDesktop = imports.gi.GnomeDesktop;
const Main = imports.ui.main;
-const Params = imports.misc.params;
const {formatTime} = imports.misc.dateUtils;
-var SCROLL_TIME = 100;
-
-const WIGGLE_OFFSET = 6;
-const WIGGLE_DURATION = 65;
-const N_WIGGLES = 3;
-
// http://daringfireball.net/2010/07/improved_regex_for_matching_urls
const _balancedParens = '\\([^\\s()<>]+\\)';
const _leadingJunk = '[\\s`(\\[{\'\\"<\u00AB\u201C\u2018]';
@@ -241,79 +233,6 @@ function insertSorted(array, val, cmp) {
return pos;
}
-function ensureActorVisibleInScrollView(scrollView, actor) {
- let adjustment = scrollView.vscroll.adjustment;
- let [value, lower_, upper, stepIncrement_, pageIncrement_, pageSize] = adjustment.get_values();
-
- let offset = 0;
- let vfade = scrollView.get_effect("fade");
- if (vfade)
- offset = vfade.fade_margins.top;
-
- let box = actor.get_allocation_box();
- let y1 = box.y1, y2 = box.y2;
-
- let parent = actor.get_parent();
- while (parent != scrollView) {
- if (!parent)
- throw new Error("actor not in scroll view");
-
- box = parent.get_allocation_box();
- y1 += box.y1;
- y2 += box.y1;
- parent = parent.get_parent();
- }
-
- if (y1 < value + offset)
- value = Math.max(0, y1 - offset);
- else if (y2 > value + pageSize - offset)
- value = Math.min(upper, y2 + offset - pageSize);
- else
- return;
-
- adjustment.ease(value, {
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- duration: SCROLL_TIME,
- });
-}
-
-function wiggle(actor, params) {
- if (!St.Settings.get().enable_animations)
- return;
-
- params = Params.parse(params, {
- offset: WIGGLE_OFFSET,
- duration: WIGGLE_DURATION,
- wiggleCount: N_WIGGLES,
- });
- actor.translation_x = 0;
-
- // Accelerate before wiggling
- actor.ease({
- translation_x: -params.offset,
- duration: params.duration,
- mode: Clutter.AnimationMode.EASE_OUT_QUAD,
- onComplete: () => {
- // Wiggle
- actor.ease({
- translation_x: params.offset,
- duration: params.duration,
- mode: Clutter.AnimationMode.LINEAR,
- repeatCount: params.wiggleCount,
- autoReverse: true,
- onComplete: () => {
- // Decelerate and return to the original position
- actor.ease({
- translation_x: 0,
- duration: params.duration,
- mode: Clutter.AnimationMode.EASE_IN_QUAD,
- });
- },
- });
- },
- });
-}
-
function lerp(start, end, progress) {
return start + progress * (end - start);
}
diff --git a/js/ui/calendar.js b/js/ui/calendar.js
index aa597fc42..d87d5aff8 100644
--- a/js/ui/calendar.js
+++ b/js/ui/calendar.js
@@ -13,7 +13,7 @@ const MessageList = imports.ui.messageList;
const MessageTray = imports.ui.messageTray;
const Mpris = imports.ui.mpris;
const PopupMenu = imports.ui.popupMenu;
-const Util = imports.misc.util;
+const {ensureActorVisibleInScrollView} = imports.misc.animationUtils;
const {formatDateWithCFormatString, formatTimeSpan} = imports.misc.dateUtils;
const {loadInterfaceXML} = imports.misc.fileUtils;
@@ -1016,7 +1016,7 @@ class CalendarMessageList extends St.Widget {
'notify::can-clear', this._sync.bind(this),
'destroy', () => this._sectionList.remove_actor(section),
'message-focused', (_s, messageActor) => {
- Util.ensureActorVisibleInScrollView(this._scrollView, messageActor);
+ ensureActorVisibleInScrollView(this._scrollView, messageActor);
}, this);
this._sectionList.add_actor(section);
}
diff --git a/js/ui/components/keyring.js b/js/ui/components/keyring.js
index e4d0ad85f..fa96553bb 100644
--- a/js/ui/components/keyring.js
+++ b/js/ui/components/keyring.js
@@ -13,7 +13,7 @@ const Dialog = imports.ui.dialog;
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const CheckBox = imports.ui.checkBox;
-const Util = imports.misc.util;
+const {wiggle} = imports.misc.animationUtils;
var KeyringDialog = GObject.registerClass(
class KeyringDialog extends ModalDialog.ModalDialog {
@@ -83,7 +83,7 @@ class KeyringDialog extends ModalDialog.ModalDialog {
});
this.prompt.connect('notify::warning', () => {
if (this._passwordEntry && this.prompt.warning !== '')
- Util.wiggle(this._passwordEntry);
+ wiggle(this._passwordEntry);
});
warningBox.add_child(warning);
diff --git a/js/ui/components/polkitAgent.js b/js/ui/components/polkitAgent.js
index 65c4dff71..de2f86270 100644
--- a/js/ui/components/polkitAgent.js
+++ b/js/ui/components/polkitAgent.js
@@ -16,7 +16,7 @@ const Main = imports.ui.main;
const ModalDialog = imports.ui.modalDialog;
const ShellEntry = imports.ui.shellEntry;
const UserWidget = imports.ui.userWidget;
-const Util = imports.misc.util;
+const {wiggle} = imports.misc.animationUtils;
const DialogMode = {
AUTH: 0,
@@ -267,7 +267,7 @@ var AuthenticationDialog = GObject.registerClass({
this._infoMessageLabel.hide();
this._nullMessageLabel.hide();
- Util.wiggle(this._passwordEntry);
+ wiggle(this._passwordEntry);
}
/* Try and authenticate again */
diff --git a/js/ui/environment.js b/js/ui/environment.js
index 8f75871c3..aee0f8ae5 100644
--- a/js/ui/environment.js
+++ b/js/ui/environment.js
@@ -44,6 +44,7 @@ const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext;
const SignalTracker = imports.misc.signalTracker;
+const {adjustAnimationTime} = imports.misc.animationUtils;
Gio._promisify(Gio.DataInputStream.prototype, 'fill_async');
Gio._promisify(Gio.DataInputStream.prototype, 'read_line_async');
@@ -389,17 +390,3 @@ function init() {
// Prevent extensions from opening a display connection to ourselves
Gdk.set_allowed_backends('');
}
-
-// adjustAnimationTime:
-// @msecs: time in milliseconds
-//
-// Adjust @msecs to account for St's enable-animations
-// and slow-down-factor settings
-function adjustAnimationTime(msecs) {
- let settings = St.Settings.get();
-
- if (!settings.enable_animations)
- return 0;
- return settings.slow_down_factor * msecs;
-}
-
diff --git a/js/ui/screenShield.js b/js/ui/screenShield.js
index 8a10d7fe3..39ae22648 100644
--- a/js/ui/screenShield.js
+++ b/js/ui/screenShield.js
@@ -22,7 +22,7 @@ const MessageTray = imports.ui.messageTray;
const ShellDBus = imports.ui.shellDBus;
const SmartcardManager = imports.misc.smartcardManager;
-const { adjustAnimationTime } = imports.ui.environment;
+const {adjustAnimationTime} = imports.misc.animationUtils;
const SCREENSAVER_SCHEMA = 'org.gnome.desktop.screensaver';
const LOCK_ENABLED_KEY = 'lock-enabled';
diff --git a/js/ui/search.js b/js/ui/search.js
index 348f39799..9e42c9bce 100644
--- a/js/ui/search.js
+++ b/js/ui/search.js
@@ -14,7 +14,7 @@ const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const ParentalControlsManager = imports.misc.parentalControlsManager;
const RemoteSearch = imports.ui.remoteSearch;
-const Util = imports.misc.util;
+const {ensureActorVisibleInScrollView} = imports.misc.animationUtils;
const { Highlighter } = imports.misc.util;
@@ -746,7 +746,7 @@ var SearchResultsView = GObject.registerClass({
}
_focusChildChanged(provider) {
- Util.ensureActorVisibleInScrollView(this._scrollView, provider.focusChild);
+ ensureActorVisibleInScrollView(this._scrollView, provider.focusChild);
}
_ensureProviderDisplay(provider) {
@@ -877,7 +877,7 @@ var SearchResultsView = GObject.registerClass({
if (selected) {
result.add_style_pseudo_class('selected');
- Util.ensureActorVisibleInScrollView(this._scrollView, result);
+ ensureActorVisibleInScrollView(this._scrollView, result);
} else {
result.remove_style_pseudo_class('selected');
}
diff --git a/js/ui/shellMountOperation.js b/js/ui/shellMountOperation.js
index 86ec781fc..591d88b1a 100644
--- a/js/ui/shellMountOperation.js
+++ b/js/ui/shellMountOperation.js
@@ -19,7 +19,7 @@ const Params = imports.misc.params;
const ShellEntry = imports.ui.shellEntry;
const { loadInterfaceXML } = imports.misc.fileUtils;
-const Util = imports.misc.util;
+const {wiggle} = imports.misc.animationUtils;
var LIST_ITEM_ICON_SIZE = 48;
var WORK_SPINNER_ICON_SIZE = 16;
@@ -421,7 +421,7 @@ var ShellMountPasswordDialog = GObject.registerClass({
this._errorMessageLabel.text = _('Sorry, that didn’t work. Please try again.');
this._errorMessageLabel.opacity = 255;
- Util.wiggle(this._passwordEntry);
+ wiggle(this._passwordEntry);
}
_onCancelButton() {