From 6865dbdd1bf4836fa8dd7de151c7206a97193eb4 Mon Sep 17 00:00:00 2001 From: Jakub Steiner Date: Thu, 30 Jul 2015 20:28:10 +0200 Subject: [PATCH] spinner: use a 60fps spinner - sync with gtk+ and provide a fluid spinner https://bugzilla.gnome.org/show_bug.cgi?id=753064 --- data/theme/gnome-shell-sass | 2 +- data/theme/process-working.svg | 2421 +++++++++++++++++++++++++++++++- js/gdm/authPrompt.js | 2 +- js/ui/animation.js | 2 +- js/ui/modalDialog.js | 69 +- js/ui/panel.js | 2 +- js/ui/status/network.js | 2 +- 7 files changed, 2408 insertions(+), 92 deletions(-) diff --git a/data/theme/gnome-shell-sass b/data/theme/gnome-shell-sass index 23e0bc1e7..e0e74382f 160000 --- a/data/theme/gnome-shell-sass +++ b/data/theme/gnome-shell-sass @@ -1 +1 @@ -Subproject commit 23e0bc1e71d0cd84d580916638ec5755f2f2d4e1 +Subproject commit e0e74382f166e596f1c8af4765404bfb65db76a2 diff --git a/data/theme/process-working.svg b/data/theme/process-working.svg index 43ffccad3..920a67d2d 100644 --- a/data/theme/process-working.svg +++ b/data/theme/process-working.svg @@ -12,9 +12,9 @@ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" id="svg5369" version="1.1" - inkscape:version="0.48.5 r10040" - width="96" - height="48" + inkscape:version="0.91 r13725" + width="512" + height="32" sodipodi:docname="process-working.svg" style="display:inline"> image/svg+xml - + @@ -596,7 +596,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + snapvisiblegridlinesonly="true" + empcolor="#0000ff" + empopacity="0.47843137" /> diff --git a/js/gdm/authPrompt.js b/js/gdm/authPrompt.js index b57b00bb7..2b79701fc 100644 --- a/js/gdm/authPrompt.js +++ b/js/gdm/authPrompt.js @@ -14,7 +14,7 @@ const ShellEntry = imports.ui.shellEntry; const Tweener = imports.ui.tweener; const UserWidget = imports.ui.userWidget; -const DEFAULT_BUTTON_WELL_ICON_SIZE = 24; +const DEFAULT_BUTTON_WELL_ICON_SIZE = 16; const DEFAULT_BUTTON_WELL_ANIMATION_DELAY = 1.0; const DEFAULT_BUTTON_WELL_ANIMATION_TIME = 0.3; diff --git a/js/ui/animation.js b/js/ui/animation.js index 736b3d72d..08f8f7e15 100644 --- a/js/ui/animation.js +++ b/js/ui/animation.js @@ -7,7 +7,7 @@ const St = imports.gi.St; const Signals = imports.signals; const Atk = imports.gi.Atk; -const ANIMATED_ICON_UPDATE_TIMEOUT = 100; +const ANIMATED_ICON_UPDATE_TIMEOUT = 14; const Animation = new Lang.Class({ Name: 'Animation', diff --git a/js/ui/modalDialog.js b/js/ui/modalDialog.js index 960e0dca3..4d461e607 100644 --- a/js/ui/modalDialog.js +++ b/js/ui/modalDialog.js @@ -14,6 +14,7 @@ const Atk = imports.gi.Atk; const Params = imports.misc.params; +const Animation = imports.ui.animation; const Layout = imports.ui.layout; const Lightbox = imports.ui.lightbox; const Main = imports.ui.main; @@ -22,6 +23,10 @@ const Tweener = imports.ui.tweener; const OPEN_AND_CLOSE_TIME = 0.1; const FADE_OUT_DIALOG_TIME = 1.0; +const WORK_SPINNER_ICON_SIZE = 16; +const WORK_SPINNER_ANIMATION_DELAY = 1.0; +const WORK_SPINNER_ANIMATION_TIME = 0.3; + const State = { OPENED: 0, CLOSED: 1, @@ -74,9 +79,7 @@ const ModalDialog = new Lang.Class({ this._group.add_actor(this._backgroundBin); this.dialogLayout = new St.BoxLayout({ style_class: 'modal-dialog', - x_align: Clutter.ActorAlign.CENTER, - y_align: Clutter.ActorAlign.CENTER, - vertical: true }); + vertical: true }); // modal dialogs are fixed width and grow vertically; set the request // mode accordingly so wrapped labels are handled correctly during // size requests. @@ -97,8 +100,7 @@ const ModalDialog = new Lang.Class({ this.backgroundStack.add_actor(this.dialogLayout); - this.contentLayout = new St.BoxLayout({ vertical: true, - style_class: "modal-dialog-content-box" }); + this.contentLayout = new St.BoxLayout({ vertical: true }); this.dialogLayout.add(this.contentLayout, { expand: true, x_fill: true, @@ -106,7 +108,8 @@ const ModalDialog = new Lang.Class({ x_align: St.Align.MIDDLE, y_align: St.Align.START }); - this.buttonLayout = new St.Widget ({ layout_manager: new Clutter.BoxLayout ({ homogeneous:true }) }); + this.buttonLayout = new St.BoxLayout({ style_class: 'modal-dialog-button-box', + vertical: false }); this.dialogLayout.add(this.buttonLayout, { x_align: St.Align.MIDDLE, y_align: St.Align.END }); @@ -115,6 +118,8 @@ const ModalDialog = new Lang.Class({ this._initialKeyFocus = this.dialogLayout; this._initialKeyFocusDestroyId = 0; this._savedKeyFocus = null; + + this._workSpinner = null; }, destroy: function() { @@ -142,12 +147,16 @@ const ModalDialog = new Lang.Class({ else x_alignment = St.Align.MIDDLE; - this.addButton(buttonInfo); + this.addButton(buttonInfo, { expand: true, + x_fill: false, + y_fill: false, + x_align: x_alignment, + y_align: St.Align.MIDDLE }); } }, - addButton: function(buttonInfo) { - let label = buttonInfo['label'] + addButton: function(buttonInfo, layoutInfo) { + let label = buttonInfo['label']; let action = buttonInfo['action']; let key = buttonInfo['key']; let isDefault = buttonInfo['default']; @@ -161,12 +170,10 @@ const ModalDialog = new Lang.Class({ else keys = []; - let button = new St.Button({ style_class: 'modal-dialog-linked-button', + let button = new St.Button({ style_class: 'modal-dialog-button button', button_mask: St.ButtonMask.ONE | St.ButtonMask.THREE, reactive: true, can_focus: true, - x_expand: true, - y_expand: true, label: label }); button.connect('clicked', action); @@ -181,11 +188,47 @@ const ModalDialog = new Lang.Class({ for (let i in keys) this._buttonKeys[keys[i]] = buttonInfo; - this.buttonLayout.add_actor(button); + this.buttonLayout.add(button, layoutInfo); return button; }, + placeSpinner: function(layoutInfo) { + let spinnerIcon = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg'); + this._workSpinner = new Animation.AnimatedIcon(spinnerIcon, WORK_SPINNER_ICON_SIZE); + this._workSpinner.actor.opacity = 0; + this._workSpinner.actor.show(); + + this.buttonLayout.add(this._workSpinner.actor, layoutInfo); + }, + + setWorking: function(working) { + if (!this._workSpinner) + return; + + Tweener.removeTweens(this._workSpinner.actor); + if (working) { + this._workSpinner.play(); + Tweener.addTween(this._workSpinner.actor, + { opacity: 255, + delay: WORK_SPINNER_ANIMATION_DELAY, + time: WORK_SPINNER_ANIMATION_TIME, + transition: 'linear' + }); + } else { + Tweener.addTween(this._workSpinner.actor, + { opacity: 0, + time: WORK_SPINNER_ANIMATION_TIME, + transition: 'linear', + onCompleteScope: this, + onComplete: function() { + if (this._workSpinner) + this._workSpinner.stop(); + } + }); + } + }, + _onKeyPressEvent: function(object, event) { this._pressedKey = event.get_key_symbol(); return Clutter.EVENT_PROPAGATE; diff --git a/js/ui/panel.js b/js/ui/panel.js index ec85fc651..5b9d308b2 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js @@ -30,7 +30,7 @@ const APP_MENU_ICON_MARGIN = 0; const BUTTON_DND_ACTIVATION_TIMEOUT = 250; -const SPINNER_ANIMATION_TIME = 0.2; +const SPINNER_ANIMATION_TIME = 1.0; // To make sure the panel corners blend nicely with the panel, // we draw background and borders the same way, e.g. drawing diff --git a/js/ui/status/network.js b/js/ui/status/network.js index bd369f23d..767656bdb 100644 --- a/js/ui/status/network.js +++ b/js/ui/status/network.js @@ -877,7 +877,7 @@ const NMWirelessDialog = new Lang.Class({ y_align: Clutter.ActorAlign.CENTER }); let file = Gio.File.new_for_uri('resource:///org/gnome/shell/theme/process-working.svg'); - this._noNetworksSpinner = new Animation.AnimatedIcon(file, 24, 24); + this._noNetworksSpinner = new Animation.AnimatedIcon(file, 16, 16); this._noNetworksBox.add_actor(this._noNetworksSpinner.actor); this._noNetworksBox.add_actor(new St.Label({ style_class: 'no-networks-label', text: _("No Networks") }));