b19d38
From 2e00e631c7def6d58bdb1eb0fa3254ae82a37574 Mon Sep 17 00:00:00 2001
1205f8
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
1205f8
Date: Wed, 17 May 2017 19:13:50 +0200
1205f8
Subject: [PATCH 1/6] extensions: Resurrect systemMonitor extension
1205f8
1205f8
The extension was removed upstream because:
1205f8
 - it hooks into the message tray that was removed
1205f8
 - it was known to have performance issues
1205f8
 - there are plenty of alternatives
1205f8
1205f8
Those aren't good enough reasons for dropping it downstream
1205f8
as well though, so we need to bring it back ...
1205f8
1205f8
This reverts commit c9a6421f362cd156cf731289eadc11f44f6970ac.
1205f8
---
1205f8
 extensions/systemMonitor/extension.js     | 376 ++++++++++++++++++++++
1205f8
 extensions/systemMonitor/meson.build      |   5 +
1205f8
 extensions/systemMonitor/metadata.json.in |  11 +
1205f8
 extensions/systemMonitor/stylesheet.css   |  35 ++
1205f8
 meson.build                               |   1 +
1205f8
 5 files changed, 428 insertions(+)
1205f8
 create mode 100644 extensions/systemMonitor/extension.js
1205f8
 create mode 100644 extensions/systemMonitor/meson.build
1205f8
 create mode 100644 extensions/systemMonitor/metadata.json.in
1205f8
 create mode 100644 extensions/systemMonitor/stylesheet.css
1205f8
1205f8
diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js
1205f8
new file mode 100644
b19d38
index 0000000..7b09df0
1205f8
--- /dev/null
1205f8
+++ b/extensions/systemMonitor/extension.js
1205f8
@@ -0,0 +1,376 @@
1205f8
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
1205f8
+
1205f8
+const Clutter = imports.gi.Clutter;
1205f8
+const GTop = imports.gi.GTop;
1205f8
+const Lang = imports.lang;
1205f8
+const Mainloop = imports.mainloop;
1205f8
+const St = imports.gi.St;
1205f8
+const Shell = imports.gi.Shell;
1205f8
+
1205f8
+const Main = imports.ui.main;
1205f8
+const Tweener = imports.ui.tweener;
1205f8
+
1205f8
+const Gettext = imports.gettext.domain('gnome-shell-extensions');
1205f8
+const _ = Gettext.gettext;
1205f8
+
1205f8
+const ExtensionUtils = imports.misc.extensionUtils;
1205f8
+const Me = ExtensionUtils.getCurrentExtension();
1205f8
+const Convenience = Me.imports.convenience;
1205f8
+
1205f8
+const INDICATOR_UPDATE_INTERVAL = 500;
1205f8
+const INDICATOR_NUM_GRID_LINES = 3;
1205f8
+
1205f8
+const ITEM_LABEL_SHOW_TIME = 0.15;
1205f8
+const ITEM_LABEL_HIDE_TIME = 0.1;
1205f8
+const ITEM_HOVER_TIMEOUT = 300;
1205f8
+
1205f8
+const Indicator = new Lang.Class({
1205f8
+    Name: 'SystemMonitor.Indicator',
1205f8
+
1205f8
+    _init: function() {
1205f8
+        this._initValues();
1205f8
+        this.drawing_area = new St.DrawingArea({ reactive: true });
1205f8
+        this.drawing_area.connect('repaint', Lang.bind(this, this._draw));
1205f8
+        this.drawing_area.connect('button-press-event', function() {
1205f8
+            let app = Shell.AppSystem.get_default().lookup_app('gnome-system-monitor.desktop');
1205f8
+            app.open_new_window(-1);
1205f8
+            return true;
1205f8
+        });
1205f8
+
1205f8
+        this.actor = new St.Bin({ style_class: "extension-systemMonitor-indicator-area",
1205f8
+                                  reactive: true, track_hover: true,
1205f8
+				  x_fill: true, y_fill: true });
1205f8
+        this.actor.add_actor(this.drawing_area);
1205f8
+
1205f8
+        this._timeout = Mainloop.timeout_add(INDICATOR_UPDATE_INTERVAL, Lang.bind(this, function () {
1205f8
+            this._updateValues();
1205f8
+            this.drawing_area.queue_repaint();
1205f8
+            return true;
1205f8
+        }));
1205f8
+    },
1205f8
+
1205f8
+    showLabel: function() {
1205f8
+        if (this.label == null)
1205f8
+            return;
1205f8
+
1205f8
+        this.label.opacity = 0;
1205f8
+        this.label.show();
1205f8
+
1205f8
+        let [stageX, stageY] = this.actor.get_transformed_position();
1205f8
+
1205f8
+	let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
1205f8
+        let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
1205f8
+
1205f8
+	let labelWidth = this.label.width;
1205f8
+        let labelHeight = this.label.height;
1205f8
+        let xOffset = Math.floor((itemWidth - labelWidth) / 2)
1205f8
+
1205f8
+        let x = stageX + xOffset;
1205f8
+
1205f8
+        let node = this.label.get_theme_node();
1205f8
+        let yOffset = node.get_length('-y-offset');
1205f8
+
1205f8
+        let y = stageY - this.label.get_height() - yOffset;
1205f8
+
1205f8
+        this.label.set_position(x, y);
1205f8
+        Tweener.addTween(this.label,
1205f8
+                         { opacity: 255,
1205f8
+                           time: ITEM_LABEL_SHOW_TIME,
1205f8
+                           transition: 'easeOutQuad',
1205f8
+                         });
1205f8
+    },
1205f8
+
1205f8
+    setLabelText: function(text) {
1205f8
+        if (this.label == null)
1205f8
+            this.label = new St.Label({ style_class: 'extension-systemMonitor-indicator-label'});
1205f8
+
1205f8
+        this.label.set_text(text);
1205f8
+        Main.layoutManager.addChrome(this.label);
1205f8
+        this.label.hide();
1205f8
+    },
1205f8
+
1205f8
+    hideLabel: function () {
1205f8
+        Tweener.addTween(this.label,
1205f8
+                         { opacity: 0,
1205f8
+                           time: ITEM_LABEL_HIDE_TIME,
1205f8
+                           transition: 'easeOutQuad',
1205f8
+                           onComplete: Lang.bind(this, function() {
1205f8
+                               this.label.hide();
1205f8
+                           })
1205f8
+                         });
1205f8
+    },
1205f8
+
1205f8
+    destroy: function() {
1205f8
+        Mainloop.source_remove(this._timeout);
1205f8
+
1205f8
+        this.actor.destroy();
1205f8
+	if (this.label)
1205f8
+	    this.label.destroy();
1205f8
+    },
1205f8
+
1205f8
+    _initValues: function() {
1205f8
+    },
1205f8
+
1205f8
+    _updateValues: function() {
1205f8
+    },
1205f8
+
1205f8
+    _draw: function(area) {
1205f8
+        let [width, height] = area.get_surface_size();
1205f8
+        let themeNode = this.actor.get_theme_node();
1205f8
+        let cr = area.get_context();
1205f8
+
1205f8
+        //draw the background grid
1205f8
+        let color = themeNode.get_color(this.gridColor);
1205f8
+        let gridOffset = Math.floor(height / (INDICATOR_NUM_GRID_LINES + 1));
1205f8
+        for (let i = 1; i <= INDICATOR_NUM_GRID_LINES; ++i) {
1205f8
+                cr.moveTo(0, i * gridOffset + .5);
1205f8
+                cr.lineTo(width, i * gridOffset + .5);
1205f8
+        }
1205f8
+        Clutter.cairo_set_source_color(cr, color);
1205f8
+        cr.setLineWidth(1);
1205f8
+        cr.setDash([4,1], 0);
1205f8
+        cr.stroke();
1205f8
+
1205f8
+        //draw the foreground
1205f8
+
1205f8
+        function makePath(values, reverse, nudge) {
1205f8
+            if (nudge == null) {
1205f8
+                nudge = 0;
1205f8
+            }
1205f8
+            //if we are going in reverse, we are completing the bottom of a chart, so use lineTo
1205f8
+            if (reverse) {
1205f8
+                cr.lineTo(values.length - 1, (1 - values[values.length - 1]) * height + nudge);
1205f8
+                for (let k = values.length - 2; k >= 0; --k) {
1205f8
+                    cr.lineTo(k, (1 - values[k]) * height + nudge);
1205f8
+                }
1205f8
+            } else {
1205f8
+                cr.moveTo(0, (1 - values[0]) * height + nudge);
1205f8
+                for (let k = 1; k < values.length; ++k) {
1205f8
+                    cr.lineTo(k, (1 - values[k]) * height + nudge);
1205f8
+                }
1205f8
+
1205f8
+            }
1205f8
+        }
1205f8
+
1205f8
+        let renderStats = this.renderStats;
1205f8
+
1205f8
+        // Make sure we don't have more sample points than pixels
1205f8
+        renderStats.map(Lang.bind(this, function(k){
1205f8
+            let stat = this.stats[k];
1205f8
+            if (stat.values.length > width) {
1205f8
+                stat.values = stat.values.slice(stat.values.length - width, stat.values.length);
1205f8
+            }
1205f8
+        }));
1205f8
+
1205f8
+        for (let i = 0; i < renderStats.length; ++i) {
1205f8
+            let stat = this.stats[renderStats[i]];
1205f8
+            // We outline at full opacity and fill with 40% opacity
1205f8
+            let outlineColor = themeNode.get_color(stat.color);
1205f8
+            let color = new Clutter.Color(outlineColor);
1205f8
+            color.alpha = color.alpha * .4;
1205f8
+
1205f8
+            // Render the background between us and the next level
1205f8
+            makePath(stat.values, false);
1205f8
+            // If there is a process below us, render the cpu between us and it, otherwise,
1205f8
+            // render to the bottom of the chart
1205f8
+            if (i == renderStats.length - 1) {
1205f8
+                cr.lineTo(stat.values.length - 1, height);
1205f8
+                cr.lineTo(0, height);
1205f8
+                cr.closePath();
1205f8
+            } else {
1205f8
+                let nextStat = this.stats[renderStats[i+1]];
1205f8
+                makePath(nextStat.values, true);
1205f8
+            }
1205f8
+            cr.closePath()
1205f8
+            Clutter.cairo_set_source_color(cr, color);
1205f8
+            cr.fill();
1205f8
+
1205f8
+            // Render the outline of this level
1205f8
+            makePath(stat.values, false, .5);
1205f8
+            Clutter.cairo_set_source_color(cr, outlineColor);
1205f8
+            cr.setLineWidth(1.0);
1205f8
+            cr.setDash([], 0);
1205f8
+            cr.stroke();
1205f8
+        }
1205f8
+    }
1205f8
+});
1205f8
+
1205f8
+const CpuIndicator = new Lang.Class({
1205f8
+    Name: 'SystemMonitor.CpuIndicator',
1205f8
+    Extends: Indicator,
1205f8
+
1205f8
+    _init: function() {
1205f8
+        this.parent();
1205f8
+
1205f8
+        this.gridColor = '-grid-color';
1205f8
+        this.renderStats = [ 'cpu-user', 'cpu-sys', 'cpu-iowait' ];
1205f8
+
1205f8
+        // Make sure renderStats is sorted as necessary for rendering
1205f8
+        let renderStatOrder = {'cpu-total': 0, 'cpu-user': 1, 'cpu-sys': 2, 'cpu-iowait': 3};
1205f8
+        this.renderStats = this.renderStats.sort(function(a,b) {
1205f8
+            return renderStatOrder[a] - renderStatOrder[b];
1205f8
+        });
1205f8
+
1205f8
+	this.setLabelText(_("CPU"));
1205f8
+    },
1205f8
+
1205f8
+    _initValues: function() {
1205f8
+        this._prev = new GTop.glibtop_cpu;
1205f8
+        GTop.glibtop_get_cpu(this._prev);
1205f8
+
1205f8
+        this.stats = {
1205f8
+                       'cpu-user': {color: '-cpu-user-color', values: []},
1205f8
+                       'cpu-sys': {color: '-cpu-sys-color', values: []},
1205f8
+                       'cpu-iowait': {color: '-cpu-iowait-color', values: []},
1205f8
+                       'cpu-total': {color: '-cpu-total-color', values: []}
1205f8
+                     };
1205f8
+    },
1205f8
+
1205f8
+    _updateValues: function() {
1205f8
+        let cpu = new GTop.glibtop_cpu;
1205f8
+        let t = 0.0;
1205f8
+        GTop.glibtop_get_cpu(cpu);
1205f8
+        let total = cpu.total - this._prev.total;
1205f8
+        let user = cpu.user - this._prev.user;
1205f8
+        let sys = cpu.sys - this._prev.sys;
1205f8
+        let iowait = cpu.iowait - this._prev.iowait;
1205f8
+        let idle = cpu.idle - this._prev.idle;
1205f8
+
1205f8
+        t += iowait / total;
1205f8
+        this.stats['cpu-iowait'].values.push(t);
1205f8
+        t += sys / total;
1205f8
+        this.stats['cpu-sys'].values.push(t);
1205f8
+        t += user / total;
1205f8
+        this.stats['cpu-user'].values.push(t);
1205f8
+        this.stats['cpu-total'].values.push(1 - idle / total);
1205f8
+
1205f8
+        this._prev = cpu;
1205f8
+    }
1205f8
+});
1205f8
+
1205f8
+const MemoryIndicator = new Lang.Class({
1205f8
+    Name: 'SystemMonitor.MemoryIndicator',
1205f8
+    Extends: Indicator,
1205f8
+
1205f8
+    _init: function() {
1205f8
+        this.parent();
1205f8
+
1205f8
+        this.gridColor = '-grid-color';
1205f8
+        this.renderStats = [ 'mem-user', 'mem-other', 'mem-cached' ];
1205f8
+
1205f8
+        // Make sure renderStats is sorted as necessary for rendering
1205f8
+        let renderStatOrder = { 'mem-cached': 0, 'mem-other': 1, 'mem-user': 2 };
1205f8
+        this.renderStats = this.renderStats.sort(function(a,b) {
1205f8
+            return renderStatOrder[a] - renderStatOrder[b];
1205f8
+        });
1205f8
+
1205f8
+	this.setLabelText(_("Memory"));
1205f8
+    },
1205f8
+
1205f8
+    _initValues: function() {
1205f8
+        this.mem = new GTop.glibtop_mem;
1205f8
+        this.stats = {
1205f8
+                        'mem-user': { color: "-mem-user-color", values: [] },
1205f8
+                        'mem-other': { color: "-mem-other-color", values: [] },
1205f8
+                        'mem-cached': { color: "-mem-cached-color", values: [] }
1205f8
+                     };
1205f8
+    },
1205f8
+
1205f8
+    _updateValues: function() {
1205f8
+        GTop.glibtop_get_mem(this.mem);
1205f8
+
1205f8
+        let t = this.mem.user / this.mem.total;
1205f8
+        this.stats['mem-user'].values.push(t);
1205f8
+        t += (this.mem.used - this.mem.user - this.mem.cached) / this.mem.total;
1205f8
+        this.stats['mem-other'].values.push(t);
1205f8
+        t += this.mem.cached / this.mem.total;
1205f8
+        this.stats['mem-cached'].values.push(t);
1205f8
+    }
1205f8
+});
1205f8
+
1205f8
+const INDICATORS = [CpuIndicator, MemoryIndicator];
1205f8
+
1205f8
+const Extension = new Lang.Class({
1205f8
+    Name: 'SystemMonitor.Extension',
1205f8
+
1205f8
+    _init: function() {
1205f8
+	Convenience.initTranslations();
1205f8
+
1205f8
+	this._showLabelTimeoutId = 0;
1205f8
+	this._resetHoverTimeoutId = 0;
1205f8
+	this._labelShowing = false;
1205f8
+    },
1205f8
+
1205f8
+    enable: function() {
1205f8
+	this._box = new St.BoxLayout({ style_class: 'extension-systemMonitor-container',
1205f8
+				       x_align: Clutter.ActorAlign.START,
1205f8
+				       x_expand: true });
1205f8
+	this._indicators = [ ];
1205f8
+
1205f8
+	for (let i = 0; i < INDICATORS.length; i++) {
1205f8
+	    let indicator = new (INDICATORS[i])();
1205f8
+
1205f8
+            indicator.actor.connect('notify::hover', Lang.bind(this, function() {
1205f8
+		this._onHover(indicator);
1205f8
+	    }));
1205f8
+	    this._box.add_actor(indicator.actor);
1205f8
+	    this._indicators.push(indicator);
1205f8
+	}
1205f8
+
1205f8
+	this._boxHolder = new St.BoxLayout({ x_expand: true,
1205f8
+					     y_expand: true,
1205f8
+					     x_align: Clutter.ActorAlign.START,
1205f8
+					   });
1205f8
+	let menuButton = Main.messageTray._messageTrayMenuButton.actor;
1205f8
+	Main.messageTray.actor.remove_child(menuButton);
1205f8
+	Main.messageTray.actor.add_child(this._boxHolder);
1205f8
+
1205f8
+	this._boxHolder.add_child(this._box);
1205f8
+	this._boxHolder.add_child(menuButton);
1205f8
+    },
1205f8
+
1205f8
+    disable: function() {
1205f8
+	this._indicators.forEach(function(i) { i.destroy(); });
1205f8
+
1205f8
+	let menuButton = Main.messageTray._messageTrayMenuButton.actor;
1205f8
+	this._boxHolder.remove_child(menuButton);
1205f8
+	Main.messageTray.actor.add_child(menuButton);
1205f8
+
1205f8
+	this._box.destroy();
1205f8
+	this._boxHolder.destroy();
1205f8
+    },
1205f8
+
1205f8
+    _onHover: function (item) {
1205f8
+        if (item.actor.get_hover()) {
1205f8
+            if (this._showLabelTimeoutId == 0) {
1205f8
+                let timeout = this._labelShowing ? 0 : ITEM_HOVER_TIMEOUT;
1205f8
+                this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
1205f8
+                    Lang.bind(this, function() {
1205f8
+                        this._labelShowing = true;
1205f8
+                        item.showLabel();
1205f8
+                        return false;
1205f8
+                    }));
1205f8
+                if (this._resetHoverTimeoutId > 0) {
1205f8
+                    Mainloop.source_remove(this._resetHoverTimeoutId);
1205f8
+                    this._resetHoverTimeoutId = 0;
1205f8
+                }
1205f8
+            }
1205f8
+        } else {
1205f8
+            if (this._showLabelTimeoutId > 0)
1205f8
+                Mainloop.source_remove(this._showLabelTimeoutId);
1205f8
+            this._showLabelTimeoutId = 0;
1205f8
+            item.hideLabel();
1205f8
+            if (this._labelShowing) {
1205f8
+                this._resetHoverTimeoutId = Mainloop.timeout_add(ITEM_HOVER_TIMEOUT,
1205f8
+                    Lang.bind(this, function() {
1205f8
+                        this._labelShowing = false;
1205f8
+                        return false;
1205f8
+                    }));
1205f8
+            }
1205f8
+        }
1205f8
+    },
1205f8
+});
1205f8
+
1205f8
+function init() {
1205f8
+    return new Extension();
1205f8
+}
1205f8
diff --git a/extensions/systemMonitor/meson.build b/extensions/systemMonitor/meson.build
1205f8
new file mode 100644
b19d38
index 0000000..48504f6
1205f8
--- /dev/null
1205f8
+++ b/extensions/systemMonitor/meson.build
1205f8
@@ -0,0 +1,5 @@
1205f8
+extension_data += configure_file(
1205f8
+  input: metadata_name + '.in',
1205f8
+  output: metadata_name,
1205f8
+  configuration: metadata_conf
1205f8
+)
1205f8
diff --git a/extensions/systemMonitor/metadata.json.in b/extensions/systemMonitor/metadata.json.in
1205f8
new file mode 100644
b19d38
index 0000000..fa75007
1205f8
--- /dev/null
1205f8
+++ b/extensions/systemMonitor/metadata.json.in
1205f8
@@ -0,0 +1,11 @@
1205f8
+{
1205f8
+    "shell-version": ["@shell_current@" ],
1205f8
+    "uuid": "@uuid@",
1205f8
+    "extension-id": "@extension_id@",
1205f8
+    "settings-schema": "@gschemaname@",
1205f8
+    "gettext-domain": "@gettext_domain@",
1205f8
+    "original-author": "zaspire@rambler.ru",
1205f8
+    "name": "SystemMonitor",
1205f8
+    "description": "System monitor showing CPU and memory usage in the message tray.",
1205f8
+    "url": "@url@"
1205f8
+}
1205f8
diff --git a/extensions/systemMonitor/stylesheet.css b/extensions/systemMonitor/stylesheet.css
1205f8
new file mode 100644
b19d38
index 0000000..13f95ec
1205f8
--- /dev/null
1205f8
+++ b/extensions/systemMonitor/stylesheet.css
1205f8
@@ -0,0 +1,35 @@
1205f8
+.extension-systemMonitor-container {
1205f8
+    spacing: 5px;
1205f8
+    padding-left: 5px;
1205f8
+    padding-right: 5px;
1205f8
+    padding-bottom: 10px;
1205f8
+    padding-top: 10px;
1205f8
+}
1205f8
+
1205f8
+.extension-systemMonitor-indicator-area {
1205f8
+    border: 1px solid #8d8d8d;
1205f8
+    border-radius: 3px;
1205f8
+    width: 100px;
1205f8
+    /* message tray is 72px, so 20px padding of the container,
1205f8
+       2px of border, makes it 50px */
1205f8
+    height: 50px;
1205f8
+    -grid-color: #575757;
1205f8
+    -cpu-total-color: rgb(0,154,62);
1205f8
+    -cpu-user-color: rgb(69,154,0);
1205f8
+    -cpu-sys-color: rgb(255,253,81);
1205f8
+    -cpu-iowait-color: rgb(210,148,0);
1205f8
+    -mem-user-color: rgb(210,148,0);
1205f8
+    -mem-cached-color: rgb(90,90,90);
1205f8
+    -mem-other-color: rgb(205,203,41);
1205f8
+    background-color: #1e1e1e;
1205f8
+}
1205f8
+
1205f8
+.extension-systemMonitor-indicator-label {
1205f8
+    border-radius: 7px;
1205f8
+    padding: 4px 12px;
1205f8
+    background-color: rgba(0,0,0,0.9);
1205f8
+    text-align: center;
1205f8
+    -y-offset: 8px;
1205f8
+    font-size: 9pt;
1205f8
+    font-weight: bold;
1205f8
+}
1205f8
diff --git a/meson.build b/meson.build
b19d38
index 6a2fdf0..afc0133 100644
1205f8
--- a/meson.build
1205f8
+++ b/meson.build
1205f8
@@ -48,6 +48,7 @@ all_extensions += [
1205f8
   'dash-to-dock',
1205f8
   'native-window-placement',
1205f8
   'panel-favorites',
1205f8
+  'systemMonitor',
1205f8
   'top-icons',
1205f8
   'updates-dialog',
1205f8
   'user-theme'
1205f8
-- 
b19d38
2.32.0
1205f8
1205f8
b19d38
From 59927edac1f40239d7926f0285249c933ea42caf Mon Sep 17 00:00:00 2001
1205f8
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
1205f8
Date: Fri, 17 May 2019 22:55:48 +0000
1205f8
Subject: [PATCH 2/6] systemMonitor: Modernise code
1205f8
1205f8
 - port to ES6 classes
1205f8
 - replace Lang.bind()
1205f8
 - replace Tweener
1205f8
 - use standard align/expand properties
1205f8
 - destructure imports
1205f8
 - fix style issues (stray/missing spaces/semi-colons, indent, ...)
1205f8
---
1205f8
 extensions/systemMonitor/extension.js | 422 +++++++++++++-------------
1205f8
 1 file changed, 212 insertions(+), 210 deletions(-)
1205f8
1205f8
diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js
b19d38
index 7b09df0..f7c6a4a 100644
1205f8
--- a/extensions/systemMonitor/extension.js
1205f8
+++ b/extensions/systemMonitor/extension.js
1205f8
@@ -1,56 +1,57 @@
1205f8
 /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
1205f8
 
1205f8
-const Clutter = imports.gi.Clutter;
1205f8
-const GTop = imports.gi.GTop;
1205f8
-const Lang = imports.lang;
1205f8
-const Mainloop = imports.mainloop;
1205f8
-const St = imports.gi.St;
1205f8
-const Shell = imports.gi.Shell;
1205f8
+/* exported init */
1205f8
 
1205f8
+const { Clutter, GLib, GTop, Shell, St } = imports.gi;
1205f8
+
1205f8
+const ExtensionUtils = imports.misc.extensionUtils;
1205f8
 const Main = imports.ui.main;
1205f8
-const Tweener = imports.ui.tweener;
1205f8
 
1205f8
 const Gettext = imports.gettext.domain('gnome-shell-extensions');
1205f8
 const _ = Gettext.gettext;
1205f8
 
1205f8
-const ExtensionUtils = imports.misc.extensionUtils;
1205f8
-const Me = ExtensionUtils.getCurrentExtension();
1205f8
-const Convenience = Me.imports.convenience;
1205f8
-
1205f8
 const INDICATOR_UPDATE_INTERVAL = 500;
1205f8
 const INDICATOR_NUM_GRID_LINES = 3;
1205f8
 
1205f8
-const ITEM_LABEL_SHOW_TIME = 0.15;
1205f8
-const ITEM_LABEL_HIDE_TIME = 0.1;
1205f8
+const ITEM_LABEL_SHOW_TIME = 150;
1205f8
+const ITEM_LABEL_HIDE_TIME = 100;
1205f8
 const ITEM_HOVER_TIMEOUT = 300;
1205f8
 
1205f8
-const Indicator = new Lang.Class({
1205f8
-    Name: 'SystemMonitor.Indicator',
1205f8
-
1205f8
-    _init: function() {
1205f8
+const Indicator = class {
1205f8
+    constructor() {
1205f8
         this._initValues();
1205f8
-        this.drawing_area = new St.DrawingArea({ reactive: true });
1205f8
-        this.drawing_area.connect('repaint', Lang.bind(this, this._draw));
1205f8
-        this.drawing_area.connect('button-press-event', function() {
1205f8
+        this._drawingArea = new St.DrawingArea({
1205f8
+            reactive: true,
1205f8
+            x_expand: true,
1205f8
+            y_expand: true,
1205f8
+        });
1205f8
+        this._drawingArea.connect('repaint', this._draw.bind(this));
1205f8
+        this._drawingArea.connect('button-press-event', () => {
1205f8
             let app = Shell.AppSystem.get_default().lookup_app('gnome-system-monitor.desktop');
1205f8
             app.open_new_window(-1);
1205f8
             return true;
1205f8
         });
1205f8
 
1205f8
-        this.actor = new St.Bin({ style_class: "extension-systemMonitor-indicator-area",
1205f8
-                                  reactive: true, track_hover: true,
1205f8
-				  x_fill: true, y_fill: true });
1205f8
-        this.actor.add_actor(this.drawing_area);
1205f8
+        this.actor = new St.Bin({
1205f8
+            style_class: 'extension-systemMonitor-indicator-area',
1205f8
+            reactive: true,
1205f8
+            track_hover: true,
1205f8
+        });
1205f8
+        this.actor.add_actor(this._drawingArea);
1205f8
+
1205f8
+        this.actor.connect('destroy', this._onDestroy.bind(this));
1205f8
 
1205f8
-        this._timeout = Mainloop.timeout_add(INDICATOR_UPDATE_INTERVAL, Lang.bind(this, function () {
1205f8
-            this._updateValues();
1205f8
-            this.drawing_area.queue_repaint();
1205f8
-            return true;
1205f8
-        }));
1205f8
-    },
1205f8
+        this._timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
1205f8
+            INDICATOR_UPDATE_INTERVAL,
1205f8
+            () => {
1205f8
+                this._updateValues();
1205f8
+                this._drawingArea.queue_repaint();
1205f8
+                return GLib.SOURCE_CONTINUE;
1205f8
+            });
1205f8
+    }
1205f8
 
1205f8
-    showLabel: function() {
1205f8
-        if (this.label == null)
1205f8
+    showLabel() {
1205f8
+        if (this.label === null)
1205f8
             return;
1205f8
 
1205f8
         this.label.opacity = 0;
1205f8
@@ -58,12 +59,10 @@ const Indicator = new Lang.Class({
1205f8
 
1205f8
         let [stageX, stageY] = this.actor.get_transformed_position();
1205f8
 
1205f8
-	let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
1205f8
-        let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
1205f8
+        let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
1205f8
 
1205f8
-	let labelWidth = this.label.width;
1205f8
-        let labelHeight = this.label.height;
1205f8
-        let xOffset = Math.floor((itemWidth - labelWidth) / 2)
1205f8
+        let labelWidth = this.label.width;
1205f8
+        let xOffset = Math.floor((itemWidth - labelWidth) / 2);
1205f8
 
1205f8
         let x = stageX + xOffset;
1205f8
 
1205f8
@@ -73,116 +72,113 @@ const Indicator = new Lang.Class({
1205f8
         let y = stageY - this.label.get_height() - yOffset;
1205f8
 
1205f8
         this.label.set_position(x, y);
1205f8
-        Tweener.addTween(this.label,
1205f8
-                         { opacity: 255,
1205f8
-                           time: ITEM_LABEL_SHOW_TIME,
1205f8
-                           transition: 'easeOutQuad',
1205f8
-                         });
1205f8
-    },
1205f8
+        this.label.ease({
1205f8
+            opacity: 255,
1205f8
+            duration: ITEM_LABEL_SHOW_TIME,
1205f8
+            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
1205f8
+        });
1205f8
+    }
1205f8
 
1205f8
-    setLabelText: function(text) {
1205f8
-        if (this.label == null)
1205f8
-            this.label = new St.Label({ style_class: 'extension-systemMonitor-indicator-label'});
1205f8
+    setLabelText(text) {
1205f8
+        if (this.label === null) {
1205f8
+            this.label = new St.Label({
1205f8
+                style_class: 'extension-systemMonitor-indicator-label',
1205f8
+            });
1205f8
+        }
1205f8
 
1205f8
         this.label.set_text(text);
1205f8
         Main.layoutManager.addChrome(this.label);
1205f8
         this.label.hide();
1205f8
-    },
1205f8
-
1205f8
-    hideLabel: function () {
1205f8
-        Tweener.addTween(this.label,
1205f8
-                         { opacity: 0,
1205f8
-                           time: ITEM_LABEL_HIDE_TIME,
1205f8
-                           transition: 'easeOutQuad',
1205f8
-                           onComplete: Lang.bind(this, function() {
1205f8
-                               this.label.hide();
1205f8
-                           })
1205f8
-                         });
1205f8
-    },
1205f8
-
1205f8
-    destroy: function() {
1205f8
-        Mainloop.source_remove(this._timeout);
1205f8
+    }
1205f8
 
1205f8
+    hideLabel() {
1205f8
+        this.label.ease({
1205f8
+            opacity: 0,
1205f8
+            duration: ITEM_LABEL_HIDE_TIME,
1205f8
+            mode: Clutter.AnimationMode.EASE_OUT_QUAD,
1205f8
+            onComplete: () => this.label.hide(),
1205f8
+        });
1205f8
+    }
1205f8
+
1205f8
+    destroy() {
1205f8
         this.actor.destroy();
1205f8
-	if (this.label)
1205f8
-	    this.label.destroy();
1205f8
-    },
1205f8
+    }
1205f8
 
1205f8
-    _initValues: function() {
1205f8
-    },
1205f8
+    _onDestroy() {
1205f8
+        GLib.source_remove(this._timeout);
1205f8
 
1205f8
-    _updateValues: function() {
1205f8
-    },
1205f8
+        if (this.label)
1205f8
+            this.label.destroy();
1205f8
+    }
1205f8
+
1205f8
+    _initValues() {
1205f8
+    }
1205f8
 
1205f8
-    _draw: function(area) {
1205f8
+    _updateValues() {
1205f8
+    }
1205f8
+
1205f8
+    _draw(area) {
1205f8
         let [width, height] = area.get_surface_size();
1205f8
         let themeNode = this.actor.get_theme_node();
1205f8
         let cr = area.get_context();
1205f8
 
1205f8
-        //draw the background grid
1205f8
+        // draw the background grid
1205f8
         let color = themeNode.get_color(this.gridColor);
1205f8
         let gridOffset = Math.floor(height / (INDICATOR_NUM_GRID_LINES + 1));
1205f8
         for (let i = 1; i <= INDICATOR_NUM_GRID_LINES; ++i) {
1205f8
-                cr.moveTo(0, i * gridOffset + .5);
1205f8
-                cr.lineTo(width, i * gridOffset + .5);
1205f8
+            cr.moveTo(0, i * gridOffset + .5);
1205f8
+            cr.lineTo(width, i * gridOffset + .5);
1205f8
         }
1205f8
         Clutter.cairo_set_source_color(cr, color);
1205f8
         cr.setLineWidth(1);
1205f8
-        cr.setDash([4,1], 0);
1205f8
+        cr.setDash([4, 1], 0);
1205f8
         cr.stroke();
1205f8
 
1205f8
-        //draw the foreground
1205f8
+        // draw the foreground
1205f8
 
1205f8
-        function makePath(values, reverse, nudge) {
1205f8
-            if (nudge == null) {
1205f8
-                nudge = 0;
1205f8
-            }
1205f8
-            //if we are going in reverse, we are completing the bottom of a chart, so use lineTo
1205f8
+        function makePath(values, reverse, nudge = 0) {
1205f8
+            // if we are going in reverse, we are completing the bottom of a chart, so use lineTo
1205f8
             if (reverse) {
1205f8
                 cr.lineTo(values.length - 1, (1 - values[values.length - 1]) * height + nudge);
1205f8
-                for (let k = values.length - 2; k >= 0; --k) {
1205f8
+                for (let k = values.length - 2; k >= 0; --k)
1205f8
                     cr.lineTo(k, (1 - values[k]) * height + nudge);
1205f8
-                }
1205f8
             } else {
1205f8
                 cr.moveTo(0, (1 - values[0]) * height + nudge);
1205f8
-                for (let k = 1; k < values.length; ++k) {
1205f8
+                for (let k = 1; k < values.length; ++k)
1205f8
                     cr.lineTo(k, (1 - values[k]) * height + nudge);
1205f8
-                }
1205f8
-
1205f8
             }
1205f8
         }
1205f8
 
1205f8
         let renderStats = this.renderStats;
1205f8
 
1205f8
         // Make sure we don't have more sample points than pixels
1205f8
-        renderStats.map(Lang.bind(this, function(k){
1205f8
+        renderStats.forEach(k => {
1205f8
             let stat = this.stats[k];
1205f8
-            if (stat.values.length > width) {
1205f8
+            if (stat.values.length > width)
1205f8
                 stat.values = stat.values.slice(stat.values.length - width, stat.values.length);
1205f8
-            }
1205f8
-        }));
1205f8
+        });
1205f8
 
1205f8
         for (let i = 0; i < renderStats.length; ++i) {
1205f8
             let stat = this.stats[renderStats[i]];
1205f8
             // We outline at full opacity and fill with 40% opacity
1205f8
             let outlineColor = themeNode.get_color(stat.color);
1205f8
-            let color = new Clutter.Color(outlineColor);
1205f8
-            color.alpha = color.alpha * .4;
1205f8
+            let fillColor = new Clutter.Color(outlineColor);
1205f8
+            fillColor.alpha *= .4;
1205f8
 
1205f8
             // Render the background between us and the next level
1205f8
             makePath(stat.values, false);
1205f8
             // If there is a process below us, render the cpu between us and it, otherwise,
1205f8
             // render to the bottom of the chart
1205f8
-            if (i == renderStats.length - 1) {
1205f8
+            if (i === renderStats.length - 1) {
1205f8
                 cr.lineTo(stat.values.length - 1, height);
1205f8
                 cr.lineTo(0, height);
1205f8
                 cr.closePath();
1205f8
             } else {
1205f8
-                let nextStat = this.stats[renderStats[i+1]];
1205f8
+                let nextStat = this.stats[renderStats[i + 1]];
1205f8
                 makePath(nextStat.values, true);
1205f8
             }
1205f8
-            cr.closePath()
1205f8
-            Clutter.cairo_set_source_color(cr, color);
1205f8
+            cr.closePath();
1205f8
+            Clutter.cairo_set_source_color(cr, fillColor);
1205f8
             cr.fill();
1205f8
 
1205f8
             // Render the outline of this level
1205f8
@@ -193,41 +189,43 @@ const Indicator = new Lang.Class({
1205f8
             cr.stroke();
1205f8
         }
1205f8
     }
1205f8
-});
1205f8
+};
1205f8
 
1205f8
-const CpuIndicator = new Lang.Class({
1205f8
-    Name: 'SystemMonitor.CpuIndicator',
1205f8
-    Extends: Indicator,
1205f8
-
1205f8
-    _init: function() {
1205f8
-        this.parent();
1205f8
+const CpuIndicator = class extends Indicator {
1205f8
+    constructor() {
1205f8
+        super();
1205f8
 
1205f8
         this.gridColor = '-grid-color';
1205f8
-        this.renderStats = [ 'cpu-user', 'cpu-sys', 'cpu-iowait' ];
1205f8
+        this.renderStats = ['cpu-user', 'cpu-sys', 'cpu-iowait'];
1205f8
 
1205f8
         // Make sure renderStats is sorted as necessary for rendering
1205f8
-        let renderStatOrder = {'cpu-total': 0, 'cpu-user': 1, 'cpu-sys': 2, 'cpu-iowait': 3};
1205f8
-        this.renderStats = this.renderStats.sort(function(a,b) {
1205f8
+        let renderStatOrder = {
1205f8
+            'cpu-total': 0,
1205f8
+            'cpu-user': 1,
1205f8
+            'cpu-sys': 2,
1205f8
+            'cpu-iowait': 3,
1205f8
+        };
1205f8
+        this.renderStats = this.renderStats.sort((a, b) => {
1205f8
             return renderStatOrder[a] - renderStatOrder[b];
1205f8
         });
1205f8
 
1205f8
-	this.setLabelText(_("CPU"));
1205f8
-    },
1205f8
+        this.setLabelText(_('CPU'));
1205f8
+    }
1205f8
 
1205f8
-    _initValues: function() {
1205f8
-        this._prev = new GTop.glibtop_cpu;
1205f8
+    _initValues() {
1205f8
+        this._prev = new GTop.glibtop_cpu();
1205f8
         GTop.glibtop_get_cpu(this._prev);
1205f8
 
1205f8
         this.stats = {
1205f8
-                       'cpu-user': {color: '-cpu-user-color', values: []},
1205f8
-                       'cpu-sys': {color: '-cpu-sys-color', values: []},
1205f8
-                       'cpu-iowait': {color: '-cpu-iowait-color', values: []},
1205f8
-                       'cpu-total': {color: '-cpu-total-color', values: []}
1205f8
-                     };
1205f8
-    },
1205f8
-
1205f8
-    _updateValues: function() {
1205f8
-        let cpu = new GTop.glibtop_cpu;
1205f8
+            'cpu-user': { color: '-cpu-user-color', values: [] },
1205f8
+            'cpu-sys': { color: '-cpu-sys-color', values: [] },
1205f8
+            'cpu-iowait': { color: '-cpu-iowait-color', values: [] },
1205f8
+            'cpu-total': { color: '-cpu-total-color', values: [] },
1205f8
+        };
1205f8
+    }
1205f8
+
1205f8
+    _updateValues() {
1205f8
+        let cpu = new GTop.glibtop_cpu();
1205f8
         let t = 0.0;
1205f8
         GTop.glibtop_get_cpu(cpu);
1205f8
         let total = cpu.total - this._prev.total;
1205f8
@@ -246,37 +244,34 @@ const CpuIndicator = new Lang.Class({
1205f8
 
1205f8
         this._prev = cpu;
1205f8
     }
1205f8
-});
1205f8
+};
1205f8
 
1205f8
-const MemoryIndicator = new Lang.Class({
1205f8
-    Name: 'SystemMonitor.MemoryIndicator',
1205f8
-    Extends: Indicator,
1205f8
-
1205f8
-    _init: function() {
1205f8
-        this.parent();
1205f8
+const MemoryIndicator = class extends Indicator {
1205f8
+    constructor() {
1205f8
+        super();
1205f8
 
1205f8
         this.gridColor = '-grid-color';
1205f8
-        this.renderStats = [ 'mem-user', 'mem-other', 'mem-cached' ];
1205f8
+        this.renderStats = ['mem-user', 'mem-other', 'mem-cached'];
1205f8
 
1205f8
         // Make sure renderStats is sorted as necessary for rendering
1205f8
         let renderStatOrder = { 'mem-cached': 0, 'mem-other': 1, 'mem-user': 2 };
1205f8
-        this.renderStats = this.renderStats.sort(function(a,b) {
1205f8
+        this.renderStats = this.renderStats.sort((a, b) => {
1205f8
             return renderStatOrder[a] - renderStatOrder[b];
1205f8
         });
1205f8
 
1205f8
-	this.setLabelText(_("Memory"));
1205f8
-    },
1205f8
+        this.setLabelText(_('Memory'));
1205f8
+    }
1205f8
 
1205f8
-    _initValues: function() {
1205f8
-        this.mem = new GTop.glibtop_mem;
1205f8
+    _initValues() {
1205f8
+        this.mem = new GTop.glibtop_mem();
1205f8
         this.stats = {
1205f8
-                        'mem-user': { color: "-mem-user-color", values: [] },
1205f8
-                        'mem-other': { color: "-mem-other-color", values: [] },
1205f8
-                        'mem-cached': { color: "-mem-cached-color", values: [] }
1205f8
-                     };
1205f8
-    },
1205f8
+            'mem-user': { color: '-mem-user-color', values: [] },
1205f8
+            'mem-other': { color: '-mem-other-color', values: [] },
1205f8
+            'mem-cached': { color: '-mem-cached-color', values: [] },
1205f8
+        };
1205f8
+    }
1205f8
 
1205f8
-    _updateValues: function() {
1205f8
+    _updateValues() {
1205f8
         GTop.glibtop_get_mem(this.mem);
1205f8
 
1205f8
         let t = this.mem.user / this.mem.total;
1205f8
@@ -286,90 +281,97 @@ const MemoryIndicator = new Lang.Class({
1205f8
         t += this.mem.cached / this.mem.total;
1205f8
         this.stats['mem-cached'].values.push(t);
1205f8
     }
1205f8
-});
1205f8
+};
1205f8
 
1205f8
 const INDICATORS = [CpuIndicator, MemoryIndicator];
1205f8
 
1205f8
-const Extension = new Lang.Class({
1205f8
-    Name: 'SystemMonitor.Extension',
1205f8
-
1205f8
-    _init: function() {
1205f8
-	Convenience.initTranslations();
1205f8
-
1205f8
-	this._showLabelTimeoutId = 0;
1205f8
-	this._resetHoverTimeoutId = 0;
1205f8
-	this._labelShowing = false;
1205f8
-    },
1205f8
-
1205f8
-    enable: function() {
1205f8
-	this._box = new St.BoxLayout({ style_class: 'extension-systemMonitor-container',
1205f8
-				       x_align: Clutter.ActorAlign.START,
1205f8
-				       x_expand: true });
1205f8
-	this._indicators = [ ];
1205f8
-
1205f8
-	for (let i = 0; i < INDICATORS.length; i++) {
1205f8
-	    let indicator = new (INDICATORS[i])();
1205f8
-
1205f8
-            indicator.actor.connect('notify::hover', Lang.bind(this, function() {
1205f8
-		this._onHover(indicator);
1205f8
-	    }));
1205f8
-	    this._box.add_actor(indicator.actor);
1205f8
-	    this._indicators.push(indicator);
1205f8
-	}
1205f8
-
1205f8
-	this._boxHolder = new St.BoxLayout({ x_expand: true,
1205f8
-					     y_expand: true,
1205f8
-					     x_align: Clutter.ActorAlign.START,
1205f8
-					   });
1205f8
-	let menuButton = Main.messageTray._messageTrayMenuButton.actor;
1205f8
-	Main.messageTray.actor.remove_child(menuButton);
1205f8
-	Main.messageTray.actor.add_child(this._boxHolder);
1205f8
-
1205f8
-	this._boxHolder.add_child(this._box);
1205f8
-	this._boxHolder.add_child(menuButton);
1205f8
-    },
1205f8
-
1205f8
-    disable: function() {
1205f8
-	this._indicators.forEach(function(i) { i.destroy(); });
1205f8
-
1205f8
-	let menuButton = Main.messageTray._messageTrayMenuButton.actor;
1205f8
-	this._boxHolder.remove_child(menuButton);
1205f8
-	Main.messageTray.actor.add_child(menuButton);
1205f8
-
1205f8
-	this._box.destroy();
1205f8
-	this._boxHolder.destroy();
1205f8
-    },
1205f8
-
1205f8
-    _onHover: function (item) {
1205f8
+class Extension {
1205f8
+    constructor() {
1205f8
+        ExtensionUtils.initTranslations();
1205f8
+
1205f8
+        this._showLabelTimeoutId = 0;
1205f8
+        this._resetHoverTimeoutId = 0;
1205f8
+        this._labelShowing = false;
1205f8
+    }
1205f8
+
1205f8
+    enable() {
1205f8
+        this._box = new St.BoxLayout({
1205f8
+            style_class: 'extension-systemMonitor-container',
1205f8
+            x_align: Clutter.ActorAlign.START,
1205f8
+            x_expand: true,
1205f8
+        });
1205f8
+        this._indicators = [];
1205f8
+
1205f8
+        for (let i = 0; i < INDICATORS.length; i++) {
1205f8
+            let indicator = new INDICATORS[i]();
1205f8
+
1205f8
+            indicator.actor.connect('notify::hover', () => {
1205f8
+                this._onHover(indicator);
1205f8
+            });
1205f8
+            this._box.add_actor(indicator.actor);
1205f8
+            this._indicators.push(indicator);
1205f8
+        }
1205f8
+
1205f8
+        this._boxHolder = new St.BoxLayout({
1205f8
+            x_expand: true,
1205f8
+            y_expand: true,
1205f8
+            x_align: Clutter.ActorAlign.START,
1205f8
+        });
1205f8
+        let menuButton = Main.messageTray._messageTrayMenuButton.actor;
1205f8
+        Main.messageTray.actor.remove_child(menuButton);
1205f8
+        Main.messageTray.actor.add_child(this._boxHolder);
1205f8
+
1205f8
+        this._boxHolder.add_child(this._box);
1205f8
+        this._boxHolder.add_child(menuButton);
1205f8
+    }
1205f8
+
1205f8
+    disable() {
1205f8
+        this._indicators.forEach(i => i.destroy());
1205f8
+
1205f8
+        let menuButton = Main.messageTray._messageTrayMenuButton.actor;
1205f8
+        this._boxHolder.remove_child(menuButton);
1205f8
+        Main.messageTray.actor.add_child(menuButton);
1205f8
+
1205f8
+        this._box.destroy();
1205f8
+        this._boxHolder.destroy();
1205f8
+    }
1205f8
+
1205f8
+    _onHover(item) {
1205f8
         if (item.actor.get_hover()) {
1205f8
-            if (this._showLabelTimeoutId == 0) {
1205f8
-                let timeout = this._labelShowing ? 0 : ITEM_HOVER_TIMEOUT;
1205f8
-                this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
1205f8
-                    Lang.bind(this, function() {
1205f8
-                        this._labelShowing = true;
1205f8
-                        item.showLabel();
1205f8
-                        return false;
1205f8
-                    }));
1205f8
-                if (this._resetHoverTimeoutId > 0) {
1205f8
-                    Mainloop.source_remove(this._resetHoverTimeoutId);
1205f8
-                    this._resetHoverTimeoutId = 0;
1205f8
-                }
1205f8
+            if (this._showLabelTimeoutId)
1205f8
+                return;
1205f8
+
1205f8
+            let timeout = this._labelShowing ? 0 : ITEM_HOVER_TIMEOUT;
1205f8
+            this._showLabelTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
1205f8
+                timeout,
1205f8
+                () => {
1205f8
+                    this._labelShowing = true;
1205f8
+                    item.showLabel();
1205f8
+                    this._showLabelTimeoutId = 0;
1205f8
+                    return GLib.SOURCE_REMOVE;
1205f8
+                });
1205f8
+
1205f8
+            if (this._resetHoverTimeoutId > 0) {
1205f8
+                GLib.source_remove(this._resetHoverTimeoutId);
1205f8
+                this._resetHoverTimeoutId = 0;
1205f8
             }
1205f8
         } else {
1205f8
             if (this._showLabelTimeoutId > 0)
1205f8
-                Mainloop.source_remove(this._showLabelTimeoutId);
1205f8
+                GLib.source_remove(this._showLabelTimeoutId);
1205f8
             this._showLabelTimeoutId = 0;
1205f8
             item.hideLabel();
1205f8
-            if (this._labelShowing) {
1205f8
-                this._resetHoverTimeoutId = Mainloop.timeout_add(ITEM_HOVER_TIMEOUT,
1205f8
-                    Lang.bind(this, function() {
1205f8
-                        this._labelShowing = false;
1205f8
-                        return false;
1205f8
-                    }));
1205f8
-            }
1205f8
+            if (!this._labelShowing)
1205f8
+                return;
1205f8
+
1205f8
+            this._resetHoverTimeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
1205f8
+                ITEM_HOVER_TIMEOUT,
1205f8
+                () => {
1205f8
+                    this._labelShowing = false;
1205f8
+                    return GLib.SOURCE_REMOVE;
1205f8
+                });
1205f8
         }
1205f8
-    },
1205f8
-});
1205f8
+    }
1205f8
+}
1205f8
 
1205f8
 function init() {
1205f8
     return new Extension();
1205f8
-- 
b19d38
2.32.0
1205f8
1205f8
b19d38
From 71e275ba45b09c5f8c6ca5445a459196dc65474b Mon Sep 17 00:00:00 2001
1205f8
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
1205f8
Date: Wed, 26 May 2021 19:50:37 +0200
1205f8
Subject: [PATCH 3/6] systemMonitor: Make label property private
1205f8
1205f8
There is no good reason to use a public property, and the name will
1205f8
clash when we subclass St.Button.
1205f8
---
1205f8
 extensions/systemMonitor/extension.js | 35 ++++++++++++++-------------
1205f8
 1 file changed, 18 insertions(+), 17 deletions(-)
1205f8
1205f8
diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js
b19d38
index f7c6a4a..bde25a1 100644
1205f8
--- a/extensions/systemMonitor/extension.js
1205f8
+++ b/extensions/systemMonitor/extension.js
1205f8
@@ -19,6 +19,7 @@ const ITEM_HOVER_TIMEOUT = 300;
1205f8
 
1205f8
 const Indicator = class {
1205f8
     constructor() {
1205f8
+        this._label = null;
1205f8
         this._initValues();
1205f8
         this._drawingArea = new St.DrawingArea({
1205f8
             reactive: true,
1205f8
@@ -51,28 +52,28 @@ const Indicator = class {
1205f8
     }
1205f8
 
1205f8
     showLabel() {
1205f8
-        if (this.label === null)
1205f8
+        if (this._label === null)
1205f8
             return;
1205f8
 
1205f8
-        this.label.opacity = 0;
1205f8
-        this.label.show();
1205f8
+        this._label.opacity = 0;
1205f8
+        this._label.show();
1205f8
 
1205f8
         let [stageX, stageY] = this.actor.get_transformed_position();
1205f8
 
1205f8
         let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
1205f8
 
1205f8
-        let labelWidth = this.label.width;
1205f8
+        let labelWidth = this._label.width;
1205f8
         let xOffset = Math.floor((itemWidth - labelWidth) / 2);
1205f8
 
1205f8
         let x = stageX + xOffset;
1205f8
 
1205f8
-        let node = this.label.get_theme_node();
1205f8
+        let node = this._label.get_theme_node();
1205f8
         let yOffset = node.get_length('-y-offset');
1205f8
 
1205f8
-        let y = stageY - this.label.get_height() - yOffset;
1205f8
+        let y = stageY - this._label.get_height() - yOffset;
1205f8
 
1205f8
-        this.label.set_position(x, y);
1205f8
-        this.label.ease({
1205f8
+        this._label.set_position(x, y);
1205f8
+        this._label.ease({
1205f8
             opacity: 255,
1205f8
             duration: ITEM_LABEL_SHOW_TIME,
1205f8
             mode: Clutter.AnimationMode.EASE_OUT_QUAD,
1205f8
@@ -80,23 +81,23 @@ const Indicator = class {
1205f8
     }
1205f8
 
1205f8
     setLabelText(text) {
1205f8
-        if (this.label === null) {
1205f8
-            this.label = new St.Label({
1205f8
+        if (this._label === null) {
1205f8
+            this._label = new St.Label({
1205f8
                 style_class: 'extension-systemMonitor-indicator-label',
1205f8
             });
1205f8
         }
1205f8
 
1205f8
-        this.label.set_text(text);
1205f8
-        Main.layoutManager.addChrome(this.label);
1205f8
-        this.label.hide();
1205f8
+        this._label.set_text(text);
1205f8
+        Main.layoutManager.addChrome(this._label);
1205f8
+        this._label.hide();
1205f8
     }
1205f8
 
1205f8
     hideLabel() {
1205f8
-        this.label.ease({
1205f8
+        this._label.ease({
1205f8
             opacity: 0,
1205f8
             duration: ITEM_LABEL_HIDE_TIME,
1205f8
             mode: Clutter.AnimationMode.EASE_OUT_QUAD,
1205f8
-            onComplete: () => this.label.hide(),
1205f8
+            onComplete: () => this._label.hide(),
1205f8
         });
1205f8
     }
1205f8
 
1205f8
@@ -107,8 +108,8 @@ const Indicator = class {
1205f8
     _onDestroy() {
1205f8
         GLib.source_remove(this._timeout);
1205f8
 
1205f8
-        if (this.label)
1205f8
-            this.label.destroy();
1205f8
+        if (this._label)
1205f8
+            this._label.destroy();
1205f8
     }
1205f8
 
1205f8
     _initValues() {
1205f8
-- 
b19d38
2.32.0
1205f8
1205f8
b19d38
From b310c3a5b532a18af38390021daa332961e404ef Mon Sep 17 00:00:00 2001
1205f8
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
1205f8
Date: Wed, 17 May 2017 19:31:58 +0200
1205f8
Subject: [PATCH 4/6] systemMonitor: Move indicators to calendar
1205f8
1205f8
The message tray joined the invisible choir, so we have to find
1205f8
a new home for the extension UI. The message list in the calendar
1205f8
drop-down looks like the best option, given that it replaced the
1205f8
old tray (and also took over the old keyboard shortcut to bring
1205f8
it up quickly).
1205f8
---
1205f8
 extensions/systemMonitor/extension.js   | 106 +++++++++++-------------
1205f8
 extensions/systemMonitor/stylesheet.css |  14 ----
1205f8
 2 files changed, 50 insertions(+), 70 deletions(-)
1205f8
1205f8
diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js
b19d38
index bde25a1..1fd01ab 100644
1205f8
--- a/extensions/systemMonitor/extension.js
1205f8
+++ b/extensions/systemMonitor/extension.js
1205f8
@@ -2,10 +2,11 @@
1205f8
 
1205f8
 /* exported init */
1205f8
 
1205f8
-const { Clutter, GLib, GTop, Shell, St } = imports.gi;
1205f8
+const { Clutter, GLib, GObject, GTop, Shell, St } = imports.gi;
1205f8
 
1205f8
 const ExtensionUtils = imports.misc.extensionUtils;
1205f8
 const Main = imports.ui.main;
1205f8
+const MessageList = imports.ui.messageList;
1205f8
 
1205f8
 const Gettext = imports.gettext.domain('gnome-shell-extensions');
1205f8
 const _ = Gettext.gettext;
1205f8
@@ -17,30 +18,38 @@ const ITEM_LABEL_SHOW_TIME = 150;
1205f8
 const ITEM_LABEL_HIDE_TIME = 100;
1205f8
 const ITEM_HOVER_TIMEOUT = 300;
1205f8
 
1205f8
-const Indicator = class {
1205f8
-    constructor() {
1205f8
+const Indicator = GObject.registerClass({
1205f8
+    Signals: {
1205f8
+        'close': {},
1205f8
+        'expanded': {},
1205f8
+        'unexpanded': {},
1205f8
+    },
1205f8
+}, class Indicator extends St.Button {
1205f8
+    _init() {
1205f8
         this._label = null;
1205f8
         this._initValues();
1205f8
         this._drawingArea = new St.DrawingArea({
1205f8
-            reactive: true,
1205f8
             x_expand: true,
1205f8
             y_expand: true,
1205f8
         });
1205f8
         this._drawingArea.connect('repaint', this._draw.bind(this));
1205f8
-        this._drawingArea.connect('button-press-event', () => {
1205f8
+
1205f8
+        super._init({
1205f8
+            style_class: 'message message-content extension-systemMonitor-indicator-area',
1205f8
+            child: this._drawingArea,
1205f8
+            x_expand: true,
1205f8
+            can_focus: true,
1205f8
+        });
1205f8
+
1205f8
+        this.connect('clicked', () => {
1205f8
             let app = Shell.AppSystem.get_default().lookup_app('gnome-system-monitor.desktop');
1205f8
             app.open_new_window(-1);
1205f8
-            return true;
1205f8
-        });
1205f8
 
1205f8
-        this.actor = new St.Bin({
1205f8
-            style_class: 'extension-systemMonitor-indicator-area',
1205f8
-            reactive: true,
1205f8
-            track_hover: true,
1205f8
+            Main.overview.hide();
1205f8
+            Main.panel.closeCalendar();
1205f8
         });
1205f8
-        this.actor.add_actor(this._drawingArea);
1205f8
 
1205f8
-        this.actor.connect('destroy', this._onDestroy.bind(this));
1205f8
+        this.connect('destroy', this._onDestroy.bind(this));
1205f8
 
1205f8
         this._timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT,
1205f8
             INDICATOR_UPDATE_INTERVAL,
1205f8
@@ -58,9 +67,9 @@ const Indicator = class {
1205f8
         this._label.opacity = 0;
1205f8
         this._label.show();
1205f8
 
1205f8
-        let [stageX, stageY] = this.actor.get_transformed_position();
1205f8
+        let [stageX, stageY] = this.get_transformed_position();
1205f8
 
1205f8
-        let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
1205f8
+        let itemWidth = this.allocation.x2 - this.allocation.x1;
1205f8
 
1205f8
         let labelWidth = this._label.width;
1205f8
         let xOffset = Math.floor((itemWidth - labelWidth) / 2);
1205f8
@@ -73,6 +82,7 @@ const Indicator = class {
1205f8
         let y = stageY - this._label.get_height() - yOffset;
1205f8
 
1205f8
         this._label.set_position(x, y);
1205f8
+        this._label.get_parent().set_child_above_sibling(this._label, null);
1205f8
         this._label.ease({
1205f8
             opacity: 255,
1205f8
             duration: ITEM_LABEL_SHOW_TIME,
1205f8
@@ -101,8 +111,12 @@ const Indicator = class {
1205f8
         });
1205f8
     }
1205f8
 
1205f8
-    destroy() {
1205f8
-        this.actor.destroy();
1205f8
+    /* MessageList.Message boilerplate */
1205f8
+    canClose() {
1205f8
+        return false;
1205f8
+    }
1205f8
+
1205f8
+    clear() {
1205f8
     }
1205f8
 
1205f8
     _onDestroy() {
1205f8
@@ -120,7 +134,7 @@ const Indicator = class {
1205f8
 
1205f8
     _draw(area) {
1205f8
         let [width, height] = area.get_surface_size();
1205f8
-        let themeNode = this.actor.get_theme_node();
1205f8
+        let themeNode = this.get_theme_node();
1205f8
         let cr = area.get_context();
1205f8
 
1205f8
         // draw the background grid
1205f8
@@ -190,11 +204,12 @@ const Indicator = class {
1205f8
             cr.stroke();
1205f8
         }
1205f8
     }
1205f8
-};
1205f8
+});
1205f8
 
1205f8
-const CpuIndicator = class extends Indicator {
1205f8
-    constructor() {
1205f8
-        super();
1205f8
+const CpuIndicator = GObject.registerClass(
1205f8
+class CpuIndicator extends Indicator {
1205f8
+    _init() {
1205f8
+        super._init();
1205f8
 
1205f8
         this.gridColor = '-grid-color';
1205f8
         this.renderStats = ['cpu-user', 'cpu-sys', 'cpu-iowait'];
1205f8
@@ -245,11 +260,12 @@ const CpuIndicator = class extends Indicator {
1205f8
 
1205f8
         this._prev = cpu;
1205f8
     }
1205f8
-};
1205f8
+});
1205f8
 
1205f8
-const MemoryIndicator = class extends Indicator {
1205f8
-    constructor() {
1205f8
-        super();
1205f8
+const MemoryIndicator = GObject.registerClass(
1205f8
+class MemoryIndicator extends Indicator {
1205f8
+    _init() {
1205f8
+        super._init();
1205f8
 
1205f8
         this.gridColor = '-grid-color';
1205f8
         this.renderStats = ['mem-user', 'mem-other', 'mem-cached'];
1205f8
@@ -282,7 +298,7 @@ const MemoryIndicator = class extends Indicator {
1205f8
         t += this.mem.cached / this.mem.total;
1205f8
         this.stats['mem-cached'].values.push(t);
1205f8
     }
1205f8
-};
1205f8
+});
1205f8
 
1205f8
 const INDICATORS = [CpuIndicator, MemoryIndicator];
1205f8
 
1205f8
@@ -296,49 +312,27 @@ class Extension {
1205f8
     }
1205f8
 
1205f8
     enable() {
1205f8
-        this._box = new St.BoxLayout({
1205f8
-            style_class: 'extension-systemMonitor-container',
1205f8
-            x_align: Clutter.ActorAlign.START,
1205f8
-            x_expand: true,
1205f8
-        });
1205f8
-        this._indicators = [];
1205f8
+        this._section = new MessageList.MessageListSection(_('System Monitor'));
1205f8
 
1205f8
         for (let i = 0; i < INDICATORS.length; i++) {
1205f8
             let indicator = new INDICATORS[i]();
1205f8
 
1205f8
-            indicator.actor.connect('notify::hover', () => {
1205f8
+            indicator.connect('notify::hover', () => {
1205f8
                 this._onHover(indicator);
1205f8
             });
1205f8
-            this._box.add_actor(indicator.actor);
1205f8
-            this._indicators.push(indicator);
1205f8
+            this._section.addMessage(indicator, false);
1205f8
         }
1205f8
 
1205f8
-        this._boxHolder = new St.BoxLayout({
1205f8
-            x_expand: true,
1205f8
-            y_expand: true,
1205f8
-            x_align: Clutter.ActorAlign.START,
1205f8
-        });
1205f8
-        let menuButton = Main.messageTray._messageTrayMenuButton.actor;
1205f8
-        Main.messageTray.actor.remove_child(menuButton);
1205f8
-        Main.messageTray.actor.add_child(this._boxHolder);
1205f8
-
1205f8
-        this._boxHolder.add_child(this._box);
1205f8
-        this._boxHolder.add_child(menuButton);
1205f8
+        Main.panel.statusArea.dateMenu._messageList._addSection(this._section);
1205f8
+        this._section.get_parent().set_child_at_index(this._section, 0);
1205f8
     }
1205f8
 
1205f8
     disable() {
1205f8
-        this._indicators.forEach(i => i.destroy());
1205f8
-
1205f8
-        let menuButton = Main.messageTray._messageTrayMenuButton.actor;
1205f8
-        this._boxHolder.remove_child(menuButton);
1205f8
-        Main.messageTray.actor.add_child(menuButton);
1205f8
-
1205f8
-        this._box.destroy();
1205f8
-        this._boxHolder.destroy();
1205f8
+        this._section.destroy();
1205f8
     }
1205f8
 
1205f8
     _onHover(item) {
1205f8
-        if (item.actor.get_hover()) {
1205f8
+        if (item.get_hover()) {
1205f8
             if (this._showLabelTimeoutId)
1205f8
                 return;
1205f8
 
1205f8
diff --git a/extensions/systemMonitor/stylesheet.css b/extensions/systemMonitor/stylesheet.css
b19d38
index 13f95ec..978ac12 100644
1205f8
--- a/extensions/systemMonitor/stylesheet.css
1205f8
+++ b/extensions/systemMonitor/stylesheet.css
1205f8
@@ -1,17 +1,4 @@
1205f8
-.extension-systemMonitor-container {
1205f8
-    spacing: 5px;
1205f8
-    padding-left: 5px;
1205f8
-    padding-right: 5px;
1205f8
-    padding-bottom: 10px;
1205f8
-    padding-top: 10px;
1205f8
-}
1205f8
-
1205f8
 .extension-systemMonitor-indicator-area {
1205f8
-    border: 1px solid #8d8d8d;
1205f8
-    border-radius: 3px;
1205f8
-    width: 100px;
1205f8
-    /* message tray is 72px, so 20px padding of the container,
1205f8
-       2px of border, makes it 50px */
1205f8
     height: 50px;
1205f8
     -grid-color: #575757;
1205f8
     -cpu-total-color: rgb(0,154,62);
1205f8
@@ -21,7 +8,6 @@
1205f8
     -mem-user-color: rgb(210,148,0);
1205f8
     -mem-cached-color: rgb(90,90,90);
1205f8
     -mem-other-color: rgb(205,203,41);
1205f8
-    background-color: #1e1e1e;
1205f8
 }
1205f8
 
1205f8
 .extension-systemMonitor-indicator-label {
1205f8
-- 
b19d38
2.32.0
1205f8
1205f8
b19d38
From 432f525336a5da1a545546ab40f882f44ac42bb7 Mon Sep 17 00:00:00 2001
1205f8
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
1205f8
Date: Thu, 18 May 2017 16:20:07 +0200
1205f8
Subject: [PATCH 5/6] systemMonitor: Handle clicks on section title
1205f8
1205f8
While on 3.24.x only the event section still has a clickable title,
1205f8
it's a generic message list feature in previous versions. It's easy
1205f8
enough to support with a small subclass, so use that instead of
1205f8
the generic baseclass.
1205f8
1205f8
Fixes: https://gitlab.gnome.org/GNOME/gnome-shell-extensions3
1205f8
---
1205f8
 extensions/systemMonitor/extension.js | 18 +++++++++++++++++-
1205f8
 1 file changed, 17 insertions(+), 1 deletion(-)
1205f8
1205f8
diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js
b19d38
index 1fd01ab..57bdb51 100644
1205f8
--- a/extensions/systemMonitor/extension.js
1205f8
+++ b/extensions/systemMonitor/extension.js
1205f8
@@ -300,6 +300,22 @@ class MemoryIndicator extends Indicator {
1205f8
     }
1205f8
 });
1205f8
 
1205f8
+const SystemMonitorSection = GObject.registerClass(
1205f8
+class SystemMonitorSection extends MessageList.MessageListSection {
1205f8
+    _init() {
1205f8
+        super._init(_('System Monitor'));
1205f8
+    }
1205f8
+
1205f8
+    _onTitleClicked() {
1205f8
+        super._onTitleClicked();
1205f8
+
1205f8
+        let appSys = Shell.AppSystem.get_default();
1205f8
+        let app = appSys.lookup_app('gnome-system-monitor.desktop');
1205f8
+        if (app)
1205f8
+            app.open_new_window(-1);
1205f8
+    }
1205f8
+});
1205f8
+
1205f8
 const INDICATORS = [CpuIndicator, MemoryIndicator];
1205f8
 
1205f8
 class Extension {
1205f8
@@ -312,7 +328,7 @@ class Extension {
1205f8
     }
1205f8
 
1205f8
     enable() {
1205f8
-        this._section = new MessageList.MessageListSection(_('System Monitor'));
1205f8
+        this._section = new SystemMonitorSection();
1205f8
 
1205f8
         for (let i = 0; i < INDICATORS.length; i++) {
1205f8
             let indicator = new INDICATORS[i]();
1205f8
-- 
b19d38
2.32.0
1205f8
1205f8
b19d38
From 657155f8f37a8d0ddf7c39dbff954d87202c681e Mon Sep 17 00:00:00 2001
1205f8
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
1205f8
Date: Thu, 18 May 2017 18:00:17 +0200
1205f8
Subject: [PATCH 6/6] systemMonitor: Provide classic styling
1205f8
1205f8
The indicator tooltips currently don't work out in classic mode
1205f8
(dark text on dark background), so provide some mode-specific
1205f8
style.
1205f8
1205f8
Fixes: #4
1205f8
---
1205f8
 extensions/systemMonitor/classic.css | 6 ++++++
1205f8
 extensions/systemMonitor/meson.build | 4 ++++
1205f8
 2 files changed, 10 insertions(+)
1205f8
 create mode 100644 extensions/systemMonitor/classic.css
1205f8
1205f8
diff --git a/extensions/systemMonitor/classic.css b/extensions/systemMonitor/classic.css
1205f8
new file mode 100644
b19d38
index 0000000..946863d
1205f8
--- /dev/null
1205f8
+++ b/extensions/systemMonitor/classic.css
1205f8
@@ -0,0 +1,6 @@
1205f8
+@import url("stylesheet.css");
1205f8
+
1205f8
+.extension-systemMonitor-indicator-label {
1205f8
+    background-color: rgba(237,237,237,0.9);
1205f8
+    border: 1px solid #a1a1a1;
1205f8
+}
1205f8
diff --git a/extensions/systemMonitor/meson.build b/extensions/systemMonitor/meson.build
b19d38
index 48504f6..b6548b1 100644
1205f8
--- a/extensions/systemMonitor/meson.build
1205f8
+++ b/extensions/systemMonitor/meson.build
1205f8
@@ -3,3 +3,7 @@ extension_data += configure_file(
1205f8
   output: metadata_name,
1205f8
   configuration: metadata_conf
1205f8
 )
1205f8
+
1205f8
+if classic_mode_enabled
1205f8
+  extension_data += files('classic.css')
1205f8
+endif
1205f8
-- 
b19d38
2.32.0
1205f8