From e94ef7f5bc7943a301128c590f9e79c26939f0de Mon Sep 17 00:00:00 2001 From: Zener Date: Tue, 9 Apr 2019 12:52:38 +0200 Subject: [PATCH] combatiblity for gnome-shell 3.32 (maybe break for earlier versions) --- src/extension.js | 481 +++++++++++++++++++++++---------------------- src/icon.js | 122 ++++++------ src/metadata.json | 2 +- src/prefs.js | 487 +++++++++++++++++++++++----------------------- src/utils.js | 5 +- 5 files changed, 552 insertions(+), 545 deletions(-) diff --git a/src/extension.js b/src/extension.js index 18708d9..09e0349 100644 --- a/src/extension.js +++ b/src/extension.js @@ -4,7 +4,6 @@ */ const Gio = imports.gi.Gio; -const Lang = imports.lang; const Mainloop = imports.mainloop; // timer const Shell = imports.gi.Shell; const St = imports.gi.St; @@ -29,10 +28,8 @@ const N_ = function (e) { -const TeaTimeFullscreenNotification = new Lang.Class({ - Name: 'TeaTimeFullscreenNotification', - - _init: function () { +class TeaTimeFullscreenNotification { + constructor() { // this spans the whole monitor and contains // the actual layout, which it displays in // the center of itself @@ -80,7 +77,7 @@ const TeaTimeFullscreenNotification = new Lang.Class({ reactive: true, keep_aspect_ratio: true }); - this._texture.connect("button-release-event", Lang.bind(this, this.hide)); + this._texture.connect("button-release-event", this.hide.bind(this)); this._layout.add_child(this._texture); this._timeline = new Clutter.Timeline({ @@ -88,7 +85,7 @@ const TeaTimeFullscreenNotification = new Lang.Class({ repeat_count: -1, progress_mode: Clutter.AnimationMode.LINEAR }); - this._timeline.connect("new-frame", Lang.bind(this, this._newFrame)); + this._timeline.connect("new-frame", this._newFrame.bind(this)); this._label = new St.Label({ text: _("Your tea is ready!"), @@ -98,19 +95,19 @@ const TeaTimeFullscreenNotification = new Lang.Class({ this._lightbox = new imports.ui.lightbox.Lightbox(Main.uiGroup); // Seems not to work on Gnome 3.10 { fadeInTime: 0.5, fadeOutTime: 0.5 } this._lightbox.highlight(this._bin); - }, - destroy: function () { + } + destroy() { this.hide(); Main.popModal(this._bin); this._bin.destroy(); this._lightbox.hide(); - }, - _newFrame: function (timeline, msecs, user) { + } + _newFrame(timeline, msecs, user) { let progress = timeline.get_progress(); let idx = Math.round(progress * this._textureFiles.length) % this._textureFiles.length; this._texture.set_from_file(this._textureFiles[idx]); - }, - show: function () { + } + show() { if (typeof Layout.MonitorConstraint != 'undefined') { this._monitorConstraint.index = global.screen.get_current_monitor() } @@ -118,22 +115,19 @@ const TeaTimeFullscreenNotification = new Lang.Class({ this._timeline.start(); this._lightbox.show(); this._bin.show_all(); - }, - hide: function () { + } + hide() { Main.popModal(this._bin); this._bin.hide(); this._lightbox.hide(); this._timeline.stop(); } -}) +}; -const PopupTeaMenuItem = new Lang.Class({ - Name: 'PopupTeaMenuItem', - Extends: PopupMenu.PopupBaseMenuItem, - - _init: function (sTeaname, nBrewtime, params) { - this.parent(params); +class PopupTeaMenuItem extends PopupMenu.PopupBaseMenuItem { + constructor(sTeaname, nBrewtime, params) { + super(params); this.tealabel = new St.Label({ text: sTeaname @@ -163,259 +157,270 @@ const PopupTeaMenuItem = new Lang.Class({ } } } -}); +}; +var TeaTime = class extends PanelMenu.Button { -const TeaTime = new Lang.Class({ - Name: 'TeaTime', - Extends: PanelMenu.Button, + constructor() { + super(null, "TeaTime"); - _init: function () { - this.parent(null, "TeaTime"); + this.myinit = function () { - this._settings = Utils.getSettings(); + this._settings = Utils.getSettings(); - this._logo = new Icon.TwoColorIcon(24, Icon.TeaPot); + this._logo = new Icon.TwoColorIcon(24, Icon.TeaPot); - // set timer widget - this._textualTimer = new St.Label({ - text: "", - x_align: Clutter.ActorAlign.END, - y_align: Clutter.ActorAlign.CENTER - }); - this._graphicalTimer = new Icon.TwoColorIcon(24, Icon.Pie); + // set timer widget + this._textualTimer = new St.Label({ + text: "", + x_align: Clutter.ActorAlign.END, + y_align: Clutter.ActorAlign.CENTER + }); + this._graphicalTimer = new Icon.TwoColorIcon(24, Icon.Pie); - this.actor.add_actor(this._logo); - this.actor.add_style_class_name('panel-status-button'); - this.actor.connect('style-changed', Lang.bind(this, this._onStyleChanged)); + this.actor.add_actor(this._logo); + this.actor.add_style_class_name('panel-status-button'); + this.actor.connect('style-changed', this._onStyleChanged.bind(this)); - this._idleTimeout = null; + this._idleTimeout = null; - this._createMenu(); - }, - _createMenu: function () { - this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - this._settings.connect("changed::" + this.config_keys.steep_times, - Lang.bind(this, this._updateTeaList)); - this._settings.connect("changed::" + this.config_keys.graphical_countdown, - Lang.bind(this, this._updateCountdownType)); + this._createMenu(); + }; - this.teaItemCont = new PopupMenu.PopupMenuSection(); + this._createMenu = function () { + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this._settings.connect("changed::" + this.config_keys.steep_times, + this._updateTeaList.bind(this)); + this._settings.connect("changed::" + this.config_keys.graphical_countdown, + this._updateCountdownType.bind(this)); - /*******************/ - // maybe one day the PopupImageMenuItem works^^ - let head = new PopupMenu.PopupMenuSection(); - let item = new PopupMenu.PopupMenuItem(_("Show settings")); //, 'gtk-preferences'); - // item._icon.icon_size = 15; - item.connect('activate', Lang.bind(this, this._showPreferences)); - head.addMenuItem(item); + this.teaItemCont = new PopupMenu.PopupMenuSection(); - /*******************/ - let bottom = new PopupMenu.PopupMenuSection(); - this._customEntry = new St.Entry({ - style_class: 'teatime-custom-entry', - track_hover: true, - hint_text: _("min:sec") - }); - this._customEntry.get_clutter_text().set_max_length(10); - this._customEntry.get_clutter_text().connect("key-press-event", Lang.bind(this, this._createCustomTimer)); - bottom.box.add(this._customEntry); - bottom.actor.set_style("padding: 0px 18px;") + /*******************/ + // maybe one day the PopupImageMenuItem works^^ + let head = new PopupMenu.PopupMenuSection(); + let item = new PopupMenu.PopupMenuItem(_("Show settings")); //, 'gtk-preferences'); + // item._icon.icon_size = 15; + item.connect('activate', this._showPreferences.bind(this)); + head.addMenuItem(item); - /*******************/ + /*******************/ + let bottom = new PopupMenu.PopupMenuSection(); + this._customEntry = new St.Entry({ + style_class: 'teatime-custom-entry', + track_hover: true, + hint_text: _("min:sec") + }); + this._customEntry.get_clutter_text().set_max_length(10); + this._customEntry.get_clutter_text().connect("key-press-event", this._createCustomTimer.bind(this)); + bottom.box.add(this._customEntry); + bottom.actor.set_style("padding: 0px 18px;") - this.menu.addMenuItem(head); - this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - this.menu.addMenuItem(this.teaItemCont); - this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); - this.menu.addMenuItem(bottom); + /*******************/ - this._updateTeaList(); - }, - _updateTeaList: function (config, output) { - // make sure the menu is empty - this.teaItemCont.removeAll(); + this.menu.addMenuItem(head); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(this.teaItemCont); + this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem()); + this.menu.addMenuItem(bottom); - // fill with new teas - let list = this._settings.get_value(this.config_keys.steep_times).unpack(); - let menuItem = new PopupTeaMenuItem("Stop Timer", 0); - menuItem.connect('activate', Lang.bind(this, function () { - this._stopCountdown(); - })); - this.teaItemCont.addMenuItem(menuItem); - for (let teaname in list) { - let time = list[teaname].get_uint32(); + this._updateTeaList(); + }; + this._updateTeaList = function (config, output) { + // make sure the menu is empty + this.teaItemCont.removeAll(); - let menuItem = new PopupTeaMenuItem(_(teaname), time); - menuItem.connect('activate', Lang.bind(this, function () { - this._initCountdown(time); - })); + // fill with new teas + let list = this._settings.get_value(this.config_keys.steep_times).unpack(); + let menuItem = new PopupTeaMenuItem("Stop Timer", 0); + menuItem.connect('activate', function () { + this._stopCountdown(); + }.bind(this)); this.teaItemCont.addMenuItem(menuItem); - } - }, - _updateCountdownType: function (config, output) { - let bWantGraphicalCountdown = this._settings.get_boolean(this.config_keys.graphical_countdown); + for (let teaname in list) { + let time = list[teaname].get_uint32(); - if (bWantGraphicalCountdown != this._bGraphicalCountdown) { - if (this._idleTimeout != null) { - // we have a running countdown, replace the display - this.actor.remove_actor(this._bGraphicalCountdown ? - this._graphicalTimer : this._textualTimer); - this._bGraphicalCountdown = bWantGraphicalCountdown; - this.actor.add_actor(this._bGraphicalCountdown ? - this._graphicalTimer : this._textualTimer); - - this._updateTimerDisplay(this._getRemainingSec()); - } // if timeout active - } // value changed - }, - _createCustomTimer: function (text, event) { - if (event.get_key_symbol() == Clutter.KEY_Enter || - event.get_key_symbol() == Clutter.KEY_Return) { - - let customTime = text.get_text(); - let seconds = 0; - let match = customTime.match(/^(?:(\d+)(?::(\d{0,2}))?|:(\d+))$/) - if (match) { - let factor = 1; - for (var i = match.length - 2; i > 0; i--) { - let s = match[i].replace(/^0/, ''); // fix for elder GNOME <= 3.10 which don't like leading zeros - seconds += factor * parseInt(s); - factor *= 60; - } - if (seconds > 0) { - this._initCountdown(seconds); - this.menu.close(); - } + let menuItem = new PopupTeaMenuItem(_(teaname), time); + menuItem.connect('activate', function () { + this._initCountdown(time); + }.bind(this)); + this.teaItemCont.addMenuItem(menuItem); } - this._customEntry.set_text(""); - } - }, - _showNotification: function (subject, text) { - let source = (Utils.isGnome34()) ? - new MessageTray.Source(_("TeaTime applet")) : - new MessageTray.Source(_("TeaTime applet"), 'utilities-teatime'); + }; + this._updateCountdownType = function (config, output) { + let bWantGraphicalCountdown = this._settings.get_boolean(this.config_keys.graphical_countdown); - if (Utils.isGnome34()) { - source.createNotificationIcon = - function () { - let iconBox = new St.Bin(); - iconBox._size = this.ICON_SIZE; - iconBox.child = new St.Icon({ - icon_name: 'utilities-teatime', - icon_type: St.IconType.FULLCOLOR, - icon_size: iconBox._size - }); - return iconBox; - } // createNotificationIcon - } + if (bWantGraphicalCountdown != this._bGraphicalCountdown) { + if (this._idleTimeout != null) { + // we have a running countdown, replace the display + this.actor.remove_actor(this._bGraphicalCountdown ? + this._graphicalTimer : this._textualTimer); + this._bGraphicalCountdown = bWantGraphicalCountdown; + this.actor.add_actor(this._bGraphicalCountdown ? + this._graphicalTimer : this._textualTimer); - Main.messageTray.add(source); + this._updateTimerDisplay(this._getRemainingSec()); + } // if timeout active + } // value changed + }; + this._createCustomTimer = function (text, event) { + if (event.get_key_symbol() == Clutter.KEY_Enter || + event.get_key_symbol() == Clutter.KEY_Return || + event.get_key_symbol() == Clutter.KEY_KP_Enter) { - let notification = new MessageTray.Notification(source, subject, text); - notification.setTransient(true); - source.notify(notification); - }, - _initCountdown: function (time) { - this._startTime = new Date(); - this._stopTime = new Date(); - this._cntdownStart = time; + let customTime = text.get_text(); + let seconds = 0; + let match = customTime.match(/^(?:(\d+)(?::(\d{0,2}))?|:(\d+))$/) + if (match) { + let factor = 1; + if (match[3] === undefined) { // minutes and seconds? + for (var i = match.length - 2; i > 0; i--) { + let s = match[i] === undefined ? "" : match[i].replace(/^0/, ''); // fix for elder GNOME <= 3.10 which don't like leading zeros + if (s.match(/^\d+$/)) { // only if something left + seconds += factor * parseInt(s); + } + factor *= 60; + } + } else { // only seconds? + let s = match[3].replace(/^0/, ''); + seconds = parseInt(s); + } + if (seconds > 0) { + this._initCountdown(seconds); + this.menu.close(); + } + } + this._customEntry.set_text(""); + } + }; + this._showNotification = function (subject, text) { + let source = (Utils.isGnome34()) ? + new MessageTray.Source(_("TeaTime applet")) : + new MessageTray.Source(_("TeaTime applet"), 'utilities-teatime'); - this._bGraphicalCountdown = this._settings.get_boolean(this.config_keys.graphical_countdown); + if (Utils.isGnome34()) { + source.createNotificationIcon = + function () { + let iconBox = new St.Bin(); + iconBox._size = this.ICON_SIZE; + iconBox.child = new St.Icon({ + icon_name: 'utilities-teatime', + icon_type: St.IconType.FULLCOLOR, + icon_size: iconBox._size + }); + return iconBox; + } // createNotificationIcon + } - let dt = this._bGraphicalCountdown ? - Math.max(1.0, time / 90) // set time step to fit animation - : - 1.0; // show every second for the textual countdown + Main.messageTray.add(source); - this._stopTime.setTime(this._startTime.getTime() + time * 1000); // in msec + let notification = new MessageTray.Notification(source, subject, text); + notification.setTransient(true); + source.notify(notification); + }; + this._initCountdown = function (time) { + this._startTime = new Date(); + this._stopTime = new Date(); + this._cntdownStart = time; - this.actor.remove_actor(this._logo); // show timer instead of default icon + this._bGraphicalCountdown = this._settings.get_boolean(this.config_keys.graphical_countdown); - this._updateTimerDisplay(time); + let dt = this._bGraphicalCountdown ? + Math.max(1.0, time / 90) // set time step to fit animation + : + 1.0; // show every second for the textual countdown - this.actor.add_actor(this._bGraphicalCountdown ? - this._graphicalTimer : this._textualTimer); + this._stopTime.setTime(this._startTime.getTime() + time * 1000); // in msec - if (this._idleTimeout != null) Mainloop.source_remove(this._idleTimeout); - this._idleTimeout = Mainloop.timeout_add_seconds(dt, Lang.bind(this, this._doCountdown)); - }, - _stopCountdown: function () { - if (this._idleTimeout != null) Mainloop.source_remove(this._idleTimeout); - this.actor.remove_actor(this._bGraphicalCountdown ? - this._graphicalTimer : this._textualTimer); - this.actor.add_actor(this._logo); - this._idleTimeout = null; - }, - _getRemainingSec: function () { - let a = new Date(); - return (this._stopTime.getTime() - a.getTime()) * 1e-3; - }, - _updateTimerDisplay: function (remainingTime) { - if (this._bGraphicalCountdown) { - this._graphicalTimer.setStatus((this._cntdownStart - remainingTime) / this._cntdownStart); - } else { - this._textualTimer.text = Utils.formatTime(remainingTime); - } - }, - _doCountdown: function () { - let remainingTime = this._getRemainingSec(); + this.actor.remove_actor(this._logo); // show timer instead of default icon - if (remainingTime <= 0) { - // count down finished, switch display again - this._stopCountdown(); - this._playSound(); + this._updateTimerDisplay(time); - if (!Utils.isGnome34() && this._settings.get_boolean(this.config_keys.fullscreen_notification)) { - this.dialog = new TeaTimeFullscreenNotification(); - this.dialog.show(); + this.actor.add_actor(this._bGraphicalCountdown ? + this._graphicalTimer : this._textualTimer); + + if (this._idleTimeout != null) Mainloop.source_remove(this._idleTimeout); + this._idleTimeout = Mainloop.timeout_add_seconds(dt, this._doCountdown.bind(this)); + }; + this._stopCountdown = function () { + if (this._idleTimeout != null) Mainloop.source_remove(this._idleTimeout); + this.actor.remove_actor(this._bGraphicalCountdown ? + this._graphicalTimer : this._textualTimer); + this.actor.add_actor(this._logo); + this._idleTimeout = null; + }; + this._getRemainingSec = function () { + let a = new Date(); + return (this._stopTime.getTime() - a.getTime()) * 1e-3; + }; + this._updateTimerDisplay = function (remainingTime) { + if (this._bGraphicalCountdown) { + this._graphicalTimer.setStatus((this._cntdownStart - remainingTime) / this._cntdownStart); } else { - this._showNotification(_("Your tea is ready!"), - _("Drink it, while it is hot!")); + this._textualTimer.text = Utils.formatTime(remainingTime); } - return false; - } else { - this._updateTimerDisplay(remainingTime); - return true; // continue timer - } - }, - _playSound: function () { - let bPlayAlarmSound = this._settings.get_boolean(this.config_keys.use_alarm_sound); - if (bPlayAlarmSound) { - Utils.playSound(this._settings.get_string(this.config_keys.alarm_sound)); - } - }, - _showPreferences: function () { - imports.misc.util.spawn(["gnome-shell-extension-prefs", ExtensionUtils.getCurrentExtension().metadata['uuid']]); - return 0; - }, - _onStyleChanged: function (actor) { - let themeNode = actor.get_theme_node(); - let color = themeNode.get_foreground_color() - let [bHasPadding, padding] = themeNode.lookup_length("-natural-hpadding", false); + }; + this._doCountdown = function () { + let remainingTime = this._getRemainingSec(); - this._primaryColor = color; - this._secondaryColor = new Clutter.Color({ - red: color.red, - green: color.green, - blue: color.blue, - alpha: color.alpha * 0.3 - }); - this._logo.setPadding(bHasPadding * padding); - this._graphicalTimer.setPadding(bHasPadding * padding); - this._textualTimer.margin_right = bHasPadding * padding; - this._textualTimer.margin_left = bHasPadding * padding; + if (remainingTime <= 0) { + // count down finished, switch display again + this._stopCountdown(); + this._playSound(); - this._logo.setColor(this._primaryColor, this._secondaryColor); - this._graphicalTimer.setColor(this._primaryColor, this._secondaryColor); + if (!Utils.isGnome34() && this._settings.get_boolean(this.config_keys.fullscreen_notification)) { + this.dialog = new TeaTimeFullscreenNotification(); + this.dialog.show(); + } else { + this._showNotification(_("Your tea is ready!"), + _("Drink it, while it is hot!")); + } + return false; + } else { + this._updateTimerDisplay(remainingTime); + return true; // continue timer + } + }; + this._playSound = function () { + let bPlayAlarmSound = this._settings.get_boolean(this.config_keys.use_alarm_sound); + if (bPlayAlarmSound) { + Utils.playSound(this._settings.get_string(this.config_keys.alarm_sound)); + } + }; + this._showPreferences = function () { + const currExt = ExtensionUtils.getCurrentExtension(); + imports.misc.util.spawn(["gnome-shell-extension-prefs", currExt.metadata['uuid']]); + return 0; + }; + this._onStyleChanged = function (actor) { + let themeNode = actor.get_theme_node(); + let color = themeNode.get_foreground_color() + let [bHasPadding, padding] = themeNode.lookup_length("-natural-hpadding", false); - // forward (possible) scaling style change to child - let scaling = Utils.getGlobalDisplayScaleFactor(); - this._logo.setScaling(scaling); - this._graphicalTimer.setScaling(scaling); - }, - config_keys: Utils.GetConfigKeys() -}); + this._primaryColor = color; + this._secondaryColor = new Clutter.Color({ + red: color.red, + green: color.green, + blue: color.blue, + alpha: color.alpha * 0.3 + }); + this._logo.setPadding(bHasPadding * padding); + this._graphicalTimer.setPadding(bHasPadding * padding); + this._textualTimer.margin_right = bHasPadding * padding; + this._textualTimer.margin_left = bHasPadding * padding; + + this._logo.setColor(this._primaryColor, this._secondaryColor); + this._graphicalTimer.setColor(this._primaryColor, this._secondaryColor); + + // forward (possible) scaling style change to child + let scaling = Utils.getGlobalDisplayScaleFactor(); + this._logo.setScaling(scaling); + this._graphicalTimer.setScaling(scaling); + }; + this.config_keys = Utils.GetConfigKeys(); + this.myinit(); + } +}; function init(metadata) { let theme = imports.gi.Gtk.IconTheme.get_default(); diff --git a/src/icon.js b/src/icon.js index 0f3f277..4490234 100644 --- a/src/icon.js +++ b/src/icon.js @@ -10,86 +10,90 @@ * If there is a better way for that stuff, please let me know ;) ********************************************************************/ -const Lang = imports.lang; const St = imports.gi.St; const Clutter = imports.gi.Clutter; const ExUt = imports.misc.extensionUtils; const Me = ExUt.getCurrentExtension(); const Utils = Me.imports.utils; -var TwoColorIcon = new Lang.Class({ - Name: 'TwoColorIcon', - Extends: St.DrawingArea, - - _init: function (size, drawingObject) { - this.parent({ +var TwoColorIcon = class extends St.DrawingArea { + constructor(size, drawingObject) { + super({ reactive: true, style: 'padding: 0px 2px' }); - this._base_size = size; - this.setScaling(Utils.getGlobalDisplayScaleFactor()); + this.myinit = function () { + this._base_size = size; + //this.setScaling(Utils.getGlobalDisplayScaleFactor()); - this._drawingObject = drawingObject; + this._drawingObject = drawingObject; - this.connect('repaint', Lang.bind(this, this._drawIcon)); + this.connect('repaint', function () { + this._drawIcon(); + }.bind(this)); - // some fallback color - this._primaryColor = new Clutter.Color({ - red: 150, - green: 150, - blue: 150, - alpha: 255 - }); - this._secundaryColor = this._primaryColor; - this._customStatus = null; - }, - setPadding: function (padding) { - this.margin_left = padding; - this.margin_right = padding; - }, - setColor: function (primary, secundary) { - this._primaryColor = primary; - this._secundaryColor = secundary; - this.queue_repaint(); - }, - setScaling: function (newScale) { - this._default_scale = newScale; - this.set_width(this._base_size * this._default_scale); - this.set_height(this._base_size * this._default_scale); - this.queue_repaint(); - }, - setStatus: function (newStatus) { - this._customStatus = newStatus; - this.queue_repaint(); - }, - _drawIcon: function () { - let cr = this.get_context(); - let orWdt = this._drawingObject.width; - let orHgt = this._drawingObject.height; - let [width, height] = this.get_surface_size(); + // some fallback color + this._primaryColor = new Clutter.Color({ + red: 150, + green: 150, + blue: 150, + alpha: 255 + }); + this._secundaryColor = this._primaryColor; + this._customStatus = null; + }; + this.setPadding = function (padding) { + this.margin_left = padding; + this.margin_right = padding; + }; + this.setColor = function (primary, secundary) { + this._primaryColor = primary; + this._secundaryColor = secundary; + this.queue_repaint(); + }; + this.setScaling = function (newScale) { + this._default_scale = newScale; + this.set_width(this._base_size * this._default_scale); + this.set_height(this._base_size * this._default_scale); + this.queue_repaint(); + }; + this.setStatus = function (newStatus) { + this._customStatus = newStatus; + this.queue_repaint(); + }; + this._drawIcon = function () { + let cr = this.get_context(); + let orWdt = this._drawingObject.width; + let orHgt = this._drawingObject.height; + let [width, height] = this.get_surface_size(); - cr.save(); + cr.save(); - let object_longest_edge = Math.max(orWdt, orHgt); - let surface_shortest_edge = Math.min(width, height); - let scaling = surface_shortest_edge / object_longest_edge; - let padding_x = (width - orWdt * scaling) * 0.5; - let padding_y = (height - orHgt * scaling) * 0.5; + let object_longest_edge = Math.max(orWdt, orHgt); + let surface_shortest_edge = Math.min(width, height); + let scaling = surface_shortest_edge / object_longest_edge; + let padding_x = (width - orWdt * scaling) * 0.5; + let padding_y = (height - orHgt * scaling) * 0.5; - cr.translate(padding_x, padding_y); - cr.scale(scaling, scaling); + cr.translate(padding_x, padding_y); + try { + cr.scale(scaling, scaling); - this._drawingObject.draw(cr, this._customStatus, this._primaryColor, this._secundaryColor); + this._drawingObject.draw(cr, this._customStatus, this._primaryColor, this._secundaryColor); - cr.restore(); + cr.restore(); + } catch (e) { + // ignore + } + }; + this.myinit(); } - -}); +}; var TeaPot = { width: 484, height: 295, - draw: function (cr, stat, primary, secundary) { + draw(cr, stat, primary, secundary) { // draw TeaPot // cairo commands generated from svg2cairo // https://github.com/akrinke/svg2cairo @@ -133,7 +137,7 @@ var TeaPot = { var Pie = { width: 1, height: 1, - draw: function (cr, stat, primary, secundary) { + draw(cr, stat, primary, secundary) { const pi = Math.PI; const r = 0.5; diff --git a/src/metadata.json b/src/metadata.json index 71ecc8f..6fca53b 100644 --- a/src/metadata.json +++ b/src/metadata.json @@ -1 +1 @@ -{"shell-version": ["3.4", "3.6", "3.8", "3.10", "3.12", "3.14", "3.16", "3.18", "3.20", "3.22", "3.24", "3.26"], "uuid": "TeaTime@oleid.mescharet.de", "name": "TeaTime", "settings-schema": "org.gnome.shell.extensions.teatime", "gettext-domain": "TeaTime", "description": "A tea steeping timer"} +{"shell-version": ["3.32"], "uuid": "TeaTime@oleid.mescharet.de", "name": "TeaTime", "settings-schema": "org.gnome.shell.extensions.teatime", "gettext-domain": "TeaTime", "description": "A tea steeping timer"} diff --git a/src/prefs.js b/src/prefs.js index c3ffa57..9916017 100644 --- a/src/prefs.js +++ b/src/prefs.js @@ -3,7 +3,6 @@ Thomas Liebetraut */ -const Lang = imports.lang; const Gtk = imports.gi.Gtk; const GObject = imports.gi.GObject; @@ -23,12 +22,9 @@ const Columns = { ADJUSTMENT: 2 } -const TeaTimePrefsWidget = new Lang.Class({ - Name: 'TeaTimePrefsWidget', - Extends: Gtk.Grid, - - _init: function () { - this.parent({ +var TeaTimePrefsWidget = class extends Gtk.Grid { + constructor() { + super({ orientation: Gtk.Orientation.VERTICAL, column_homogeneous: false, vexpand: true, @@ -36,278 +32,281 @@ const TeaTimePrefsWidget = new Lang.Class({ row_spacing: 5 }); - this._tealist = new Gtk.ListStore(); - this._tealist.set_column_types([ - GObject.TYPE_STRING, - GObject.TYPE_INT, - Gtk.Adjustment - ]); + this.myinit = function () { + this._tealist = new Gtk.ListStore(); + this._tealist.set_column_types([ + GObject.TYPE_STRING, + GObject.TYPE_INT, + Gtk.Adjustment + ]); - this.set_column_spacing(3); + this.set_column_spacing(3); - this._settings = Utils.getSettings(); - this._inhibitUpdate = true; - this._settings.connect("changed", Lang.bind(this, this._refresh)); + this._settings = Utils.getSettings(); + this._inhibitUpdate = true; + this._settings.connect("changed", this._refresh.bind(this)); - this._initWindow(); - this._inhibitUpdate = false; - this._refresh(); - this._tealist.connect("row-changed", Lang.bind(this, this._save)); - this._tealist.connect("row-deleted", Lang.bind(this, this._save)); - }, - _initWindow: function () { - let curRow = 0; - let labelFN = new Gtk.Label({ - label: _("Fullscreen Notifications"), - hexpand: true, - halign: Gtk.Align.START - }); - let labelGC = new Gtk.Label({ - label: _("Graphical Countdown"), - hexpand: true, - halign: Gtk.Align.START - }); + this._initWindow(); + this._inhibitUpdate = false; + this._refresh(); + this._tealist.connect("row-changed", this._save.bind(this)); + this._tealist.connect("row-deleted", this._save.bind(this)); + }; + this._initWindow = function () { + let curRow = 0; + let labelFN = new Gtk.Label({ + label: _("Fullscreen Notifications"), + hexpand: true, + halign: Gtk.Align.START + }); + let labelGC = new Gtk.Label({ + label: _("Graphical Countdown"), + hexpand: true, + halign: Gtk.Align.START + }); - let labelAS = new Gtk.Label({ - label: _("Alarm sound"), - hexpand: true, - halign: Gtk.Align.START - }); + let labelAS = new Gtk.Label({ + label: _("Alarm sound"), + hexpand: true, + halign: Gtk.Align.START + }); - this.fullscreenNotificationSwitch = new Gtk.Switch(); - this.fullscreenNotificationSwitch.connect("notify::active", Lang.bind(this, this._saveFullscreenNotifications)); + this.fullscreenNotificationSwitch = new Gtk.Switch(); + this.fullscreenNotificationSwitch.connect("notify::active", this._saveFullscreenNotifications.bind(this)); - this.graphicalCountdownSwitch = new Gtk.Switch(); - this.graphicalCountdownSwitch.connect("notify::active", Lang.bind(this, this._saveGraphicalCountdown)); + this.graphicalCountdownSwitch = new Gtk.Switch(); + this.graphicalCountdownSwitch.connect("notify::active", this._saveGraphicalCountdown.bind(this)); - // alarm sound file chooser - this.alarmSoundSwitch = new Gtk.Switch(); - this.alarmSoundSwitch.connect("notify::active", Lang.bind(this, this._saveUseAlarm)); + // alarm sound file chooser + this.alarmSoundSwitch = new Gtk.Switch(); + this.alarmSoundSwitch.connect("notify::active", this._saveUseAlarm.bind(this)); - this.alarmSoundFile = new Gtk.FileChooserButton({ - title: _("Select alarm sound file"), - action: Gtk.FileChooserAction.OPEN - }); - this.alarmSoundFileFilter = new Gtk.FileFilter(); - this.alarmSoundFile.set_filter(this.alarmSoundFileFilter); - this.alarmSoundFileFilter.add_mime_type("audio/*"); - this.alarmSoundFile.connect("selection_changed", Lang.bind(this, this._saveSoundFile)); + this.alarmSoundFile = new Gtk.FileChooserButton({ + title: _("Select alarm sound file"), + action: Gtk.FileChooserAction.OPEN + }); + this.alarmSoundFileFilter = new Gtk.FileFilter(); + this.alarmSoundFile.set_filter(this.alarmSoundFileFilter); + this.alarmSoundFileFilter.add_mime_type("audio/*"); + this.alarmSoundFile.connect("selection_changed", this._saveSoundFile.bind(this)); - if (!Utils.isGnome34()) { - // Full screen notifications currently not working on GNOME 3.4, thus don't show the switch - this.attach(labelFN, 0 /*col*/ , curRow /*row*/ , 2 /*col span*/ , 1 /*row span*/ ); - this.attach(this.fullscreenNotificationSwitch, 2, curRow, 1, 1); + if (!Utils.isGnome34()) { + // Full screen notifications currently not working on GNOME 3.4, thus don't show the switch + this.attach(labelFN, 0 /*col*/ , curRow /*row*/ , 2 /*col span*/ , 1 /*row span*/ ); + this.attach(this.fullscreenNotificationSwitch, 2, curRow, 1, 1); + curRow += 1; + } + + this.attach(labelGC, 0 /*col*/ , curRow /*row*/ , 2 /*col span*/ , 1 /*row span*/ ); + this.attach(this.graphicalCountdownSwitch, 2, curRow, 1, 1); curRow += 1; - } - this.attach(labelGC, 0 /*col*/ , curRow /*row*/ , 2 /*col span*/ , 1 /*row span*/ ); - this.attach(this.graphicalCountdownSwitch, 2, curRow, 1, 1); - curRow += 1; + this.attach(labelAS, 0 /*col*/ , curRow /*row*/ , 1 /*col span*/ , 1 /*row span*/ ); + this.attach(this.alarmSoundFile, 1, curRow, 1, 1); + this.attach(this.alarmSoundSwitch, 2, curRow, 1, 1); + curRow += 1; - this.attach(labelAS, 0 /*col*/ , curRow /*row*/ , 1 /*col span*/ , 1 /*row span*/ ); - this.attach(this.alarmSoundFile, 1, curRow, 1, 1); - this.attach(this.alarmSoundSwitch, 2, curRow, 1, 1); - curRow += 1; + this.treeview = new Gtk.TreeView({ + model: this._tealist, + expand: true + }); + this.treeview.set_reorderable(true); + this.treeview.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE); + this.attach(this.treeview, 0, curRow, 3, 1); + curRow += 1; - this.treeview = new Gtk.TreeView({ - model: this._tealist, - expand: true - }); - this.treeview.set_reorderable(true); - this.treeview.get_selection().set_mode(Gtk.SelectionMode.MULTIPLE); - this.attach(this.treeview, 0, curRow, 3, 1); - curRow += 1; + let teaname = new Gtk.TreeViewColumn({ + title: _("Tea"), + expand: true + }); + let renderer = new Gtk.CellRendererText({ + editable: true + }); + // When the renderer is done editing it's value, we first write + // the new value to the view's model, i.e. this._tealist. + // This makes life a little harder due to chaining of callbacks + // and the need for this._inhibitUpdate, but it feels a lot cleaner + // when the UI does not know about the config storage backend. + renderer.connect("edited", function (renderer, pathString, newValue) { + let [store, iter] = this._tealist.get_iter(Gtk.TreePath.new_from_string(pathString)); + this._tealist.set(iter, [Columns.TEA_NAME], [newValue]); + }.bind(this)); + teaname.pack_start(renderer, true); + teaname.add_attribute(renderer, "text", Columns.TEA_NAME); + this.treeview.append_column(teaname); - let teaname = new Gtk.TreeViewColumn({ - title: _("Tea"), - expand: true - }); - let renderer = new Gtk.CellRendererText({ - editable: true - }); - // When the renderer is done editing it's value, we first write - // the new value to the view's model, i.e. this._tealist. - // This makes life a little harder due to chaining of callbacks - // and the need for this._inhibitUpdate, but it feels a lot cleaner - // when the UI does not know about the config storage backend. - renderer.connect("edited", Lang.bind(this, function (renderer, pathString, newValue) { - let [store, iter] = this._tealist.get_iter(Gtk.TreePath.new_from_string(pathString)); - this._tealist.set(iter, [Columns.TEA_NAME], [newValue]); - })); - teaname.pack_start(renderer, true); - teaname.add_attribute(renderer, "text", Columns.TEA_NAME); - this.treeview.append_column(teaname); + let steeptime = new Gtk.TreeViewColumn({ + title: _("Steep time"), + min_width: 150 + }); + let spinrenderer = new Gtk.CellRendererSpin({ + editable: true + }); + // See comment above. + spinrenderer.connect("edited", function (renderer, pathString, newValue) { + let [store, iter] = this._tealist.get_iter(Gtk.TreePath.new_from_string(pathString)); + this._tealist.set(iter, [Columns.STEEP_TIME], [parseInt(newValue)]); + }.bind(this)); - let steeptime = new Gtk.TreeViewColumn({ - title: _("Steep time"), - min_width: 150 - }); - let spinrenderer = new Gtk.CellRendererSpin({ - editable: true - }); - // See comment above. - spinrenderer.connect("edited", Lang.bind(this, function (renderer, pathString, newValue) { - let [store, iter] = this._tealist.get_iter(Gtk.TreePath.new_from_string(pathString)); - this._tealist.set(iter, [Columns.STEEP_TIME], [parseInt(newValue)]); - })); - - steeptime.pack_start(spinrenderer, true); - steeptime.add_attribute(spinrenderer, "adjustment", Columns.ADJUSTMENT); - steeptime.add_attribute(spinrenderer, "text", Columns.STEEP_TIME); - this.treeview.append_column(steeptime); + steeptime.pack_start(spinrenderer, true); + steeptime.add_attribute(spinrenderer, "adjustment", Columns.ADJUSTMENT); + steeptime.add_attribute(spinrenderer, "text", Columns.STEEP_TIME); + this.treeview.append_column(steeptime); - this.toolbar = new Gtk.Toolbar({ - icon_size: 1 - }); - this.toolbar.get_style_context().add_class("inline-toolbar"); - this.attach(this.toolbar, 0 /*col*/ , curRow /*row*/ , 3 /*col span*/ , 1 /*row span*/ ); - this.addButton = new Gtk.ToolButton({ - icon_name: "list-add-symbolic", - use_action_appearance: false - }); - this.addButton.connect("clicked", Lang.bind(this, this._addTea)); - this.toolbar.insert(this.addButton, -1); - this.removeButton = new Gtk.ToolButton({ - icon_name: "list-remove-symbolic", - use_action_appearance: false - }); - this.removeButton.connect("clicked", Lang.bind(this, this._removeSelectedTea)); - this.toolbar.insert(this.removeButton, -1); - }, - _refresh: function () { - // don't update the model if someone else is messing with the backend - if (this._inhibitUpdate) - return; + this.toolbar = new Gtk.Toolbar({ + icon_size: 1 + }); + this.toolbar.get_style_context().add_class("inline-toolbar"); + this.attach(this.toolbar, 0 /*col*/ , curRow /*row*/ , 3 /*col span*/ , 1 /*row span*/ ); + this.addButton = new Gtk.ToolButton({ + icon_name: "list-add-symbolic", + use_action_appearance: false + }); + this.addButton.connect("clicked", this._addTea.bind(this)); + this.toolbar.insert(this.addButton, -1); + this.removeButton = new Gtk.ToolButton({ + icon_name: "list-remove-symbolic", + use_action_appearance: false + }); + this.removeButton.connect("clicked", this._removeSelectedTea.bind(this)); + this.toolbar.insert(this.removeButton, -1); + }; + this._refresh = function () { + // don't update the model if someone else is messing with the backend + if (this._inhibitUpdate) + return; - this.fullscreenNotificationSwitch.active = this._settings.get_boolean(this.config_keys.fullscreen_notification) + this.fullscreenNotificationSwitch.active = this._settings.get_boolean(this.config_keys.fullscreen_notification) - this.graphicalCountdownSwitch.active = this._settings.get_boolean(this.config_keys.graphical_countdown) - this.alarmSoundSwitch.active = this._settings.get_boolean(this.config_keys.use_alarm_sound) - let list = this._settings.get_value(this.config_keys.steep_times).unpack(); - let file_name = this._settings.get_string(this.config_keys.alarm_sound); - this.alarmSoundFile.set_uri(file_name); + this.graphicalCountdownSwitch.active = this._settings.get_boolean(this.config_keys.graphical_countdown) + this.alarmSoundSwitch.active = this._settings.get_boolean(this.config_keys.use_alarm_sound) + let list = this._settings.get_value(this.config_keys.steep_times).unpack(); + let file_name = this._settings.get_string(this.config_keys.alarm_sound); + this.alarmSoundFile.set_uri(file_name); - // stop everyone from reacting to the changes we are about to produce - // in the model - this._inhibitUpdate = true; + // stop everyone from reacting to the changes we are about to produce + // in the model + this._inhibitUpdate = true; - this._tealist.clear(); - for (let teaname in list) { - let time = list[teaname].get_uint32(); + this._tealist.clear(); + for (let teaname in list) { + let time = list[teaname].get_uint32(); + let adj = new Gtk.Adjustment({ + lower: 1, + step_increment: 1, + upper: 65535, + value: time + }); + this._tealist.set(this._tealist.append(), [Columns.TEA_NAME, Columns.STEEP_TIME, Columns.ADJUSTMENT], [teaname, time, adj]); + } + + this._inhibitUpdate = false; + }; + this._addTea = function () { let adj = new Gtk.Adjustment({ lower: 1, step_increment: 1, upper: 65535, - value: time + value: 1 }); - this._tealist.set(this._tealist.append(), [Columns.TEA_NAME, Columns.STEEP_TIME, Columns.ADJUSTMENT], [teaname, time, adj]); - } - - this._inhibitUpdate = false; - }, - _addTea: function () { - let adj = new Gtk.Adjustment({ - lower: 1, - step_increment: 1, - upper: 65535, - value: 1 - }); - let item = this._tealist.append(); - this._tealist.set(item, [Columns.TEA_NAME, Columns.STEEP_TIME, Columns.ADJUSTMENT], ["", 1, adj]); - this.treeview.set_cursor(this._tealist.get_path(item), - this.treeview.get_column(Columns.TEA_NAME), - true); - }, - _removeSelectedTea: function () { - let [selection, store] = this.treeview.get_selection().get_selected_rows(); - let iters = []; - for (let i = 0; i < selection.length; ++i) { - let [isSet, iter] = store.get_iter(selection[i]); - if (isSet) { - iters.push(iter); + let item = this._tealist.append(); + this._tealist.set(item, [Columns.TEA_NAME, Columns.STEEP_TIME, Columns.ADJUSTMENT], ["", 1, adj]); + this.treeview.set_cursor(this._tealist.get_path(item), + this.treeview.get_column(Columns.TEA_NAME), + true); + }; + this._removeSelectedTea = function () { + let [selection, store] = this.treeview.get_selection().get_selected_rows(); + let iters = []; + for (let i = 0; i < selection.length; ++i) { + let [isSet, iter] = store.get_iter(selection[i]); + if (isSet) { + iters.push(iter); + } } - } - // it's ok not to inhibit updates here as remove != change - iters.forEach(function (value, index, array) { - store.remove(value) - }); + // it's ok not to inhibit updates here as remove != change + iters.forEach(function (value, index, array) { + store.remove(value) + }); - this.treeview.get_selection().unselect_all(); - }, - _saveFullscreenNotifications: function (sw, data) { - // don't update the backend if someone else is messing with the model - if (this._inhibitUpdate) - return; - this._inhibitUpdate = true; - this._settings.set_boolean(this.config_keys.fullscreen_notification, - sw.active); - this._inhibitUpdate = false; - }, - _saveGraphicalCountdown: function (sw, data) { - // don't update the backend if someone else is messing with the model - if (this._inhibitUpdate) - return; - this._inhibitUpdate = true; - this._settings.set_boolean(this.config_keys.graphical_countdown, - sw.active); - this._inhibitUpdate = false; - }, - _saveUseAlarm: function (sw, data) { - // don't update the backend if someone else is messing with the model - if (this._inhibitUpdate) - return; - this._inhibitUpdate = true; - this._settings.set_boolean(this.config_keys.use_alarm_sound, - sw.active); - this._inhibitUpdate = false; - }, - _saveSoundFile: function (sw, data) { - // don't update the backend if someone else is messing with the model - if (this._inhibitUpdate) - return; - let alarm_sound = this.alarmSoundFile.get_uri(); - Utils.debug(this._settings.get_string(this.config_keys.alarm_sound) + "-->" + alarm_sound); + this.treeview.get_selection().unselect_all(); + }; + this._saveFullscreenNotifications = function (sw, data) { + // don't update the backend if someone else is messing with the model + if (this._inhibitUpdate) + return; + this._inhibitUpdate = true; + this._settings.set_boolean(this.config_keys.fullscreen_notification, + sw.active); + this._inhibitUpdate = false; + }; + this._saveGraphicalCountdown = function (sw, data) { + // don't update the backend if someone else is messing with the model + if (this._inhibitUpdate) + return; + this._inhibitUpdate = true; + this._settings.set_boolean(this.config_keys.graphical_countdown, + sw.active); + this._inhibitUpdate = false; + }; + this._saveUseAlarm = function (sw, data) { + // don't update the backend if someone else is messing with the model + if (this._inhibitUpdate) + return; + this._inhibitUpdate = true; + this._settings.set_boolean(this.config_keys.use_alarm_sound, + sw.active); + this._inhibitUpdate = false; + }; + this._saveSoundFile = function (sw, data) { + // don't update the backend if someone else is messing with the model + if (this._inhibitUpdate) + return; + let alarm_sound = this.alarmSoundFile.get_uri(); + Utils.debug(this._settings.get_string(this.config_keys.alarm_sound) + "-->" + alarm_sound); - let have_value = Utils.isType(alarm_sound, "string"); - let setting_is_different = - this._settings.get_string(this.config_keys.alarm_sound) != alarm_sound; - if (have_value && setting_is_different) { + let have_value = Utils.isType(alarm_sound, "string"); + let setting_is_different = + this._settings.get_string(this.config_keys.alarm_sound) != alarm_sound; + if (have_value && setting_is_different) { + this._inhibitUpdate = true; + + Utils.playSound(alarm_sound); + this._settings.set_string(this.config_keys.alarm_sound, alarm_sound); + this._inhibitUpdate = false; + } + }; + this._save = function (store, path_, iter_) { + const GLib = imports.gi.GLib; + + // don't update the backend if someone else is messing with the model + if (this._inhibitUpdate) + return; + + let values = []; + this._tealist.foreach(function (store, path, iter) { + values.push(GLib.Variant.new_dict_entry( + GLib.Variant.new_string(store.get_value(iter, Columns.TEA_NAME)), + GLib.Variant.new_uint32(store.get_value(iter, Columns.STEEP_TIME)))) + }); + let settingsValue = GLib.Variant.new_array(GLib.VariantType.new("{su}"), values); + + // all changes have happened through the UI, we can safely + // disable updating it here to avoid an infinite loop this._inhibitUpdate = true; - Utils.playSound(alarm_sound); - this._settings.set_string(this.config_keys.alarm_sound, alarm_sound); + this._settings.set_value(this.config_keys.steep_times, settingsValue); + this._inhibitUpdate = false; - } - }, - _save: function (store, path_, iter_) { - const GLib = imports.gi.GLib; - - // don't update the backend if someone else is messing with the model - if (this._inhibitUpdate) - return; - - let values = []; - this._tealist.foreach(function (store, path, iter) { - values.push(GLib.Variant.new_dict_entry( - GLib.Variant.new_string(store.get_value(iter, Columns.TEA_NAME)), - GLib.Variant.new_uint32(store.get_value(iter, Columns.STEEP_TIME)))) - }); - let settingsValue = GLib.Variant.new_array(GLib.VariantType.new("{su}"), values); - - // all changes have happened through the UI, we can safely - // disable updating it here to avoid an infinite loop - this._inhibitUpdate = true; - - this._settings.set_value(this.config_keys.steep_times, settingsValue); - - this._inhibitUpdate = false; - }, - config_keys: Utils.GetConfigKeys() -}); + }; + this.config_keys = Utils.GetConfigKeys(); + this.myinit(); + } +}; function init() {} diff --git a/src/utils.js b/src/utils.js index 290284c..7388418 100644 --- a/src/utils.js +++ b/src/utils.js @@ -116,7 +116,6 @@ function formatTime(sec_num) { function playSound(uri) { const Gst = imports.gi.Gst; - const Lang = imports.lang; debug("Playing " + uri); @@ -125,7 +124,7 @@ function playSound(uri) { this.player = Gst.ElementFactory.make("playbin", "player"); this.playBus = this.player.get_bus(); this.playBus.add_signal_watch(); - this.playBus.connect("message", Lang.bind(this, + this.playBus.connect("message", function (playBus, message) { if (message != null) { // IMPORTANT: to reuse the player, set state to READY @@ -134,7 +133,7 @@ function playSound(uri) { this.player.set_state(Gst.State.READY); } } // message handler - })); + }.bind(this)); } // if undefined this.player.set_property('uri', uri); this.player.set_state(Gst.State.PLAYING);