Blame SOURCES/resurrect-system-monitor.patch

f6a177
From 57bb099db30703a474a023122f1106e199ff79ed Mon Sep 17 00:00:00 2001
f6a177
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
f6a177
Date: Wed, 17 May 2017 19:13:50 +0200
f6a177
Subject: [PATCH 1/4] extensions: Resurrect systemMonitor extension
f6a177
f6a177
The extension was removed upstream because:
f6a177
 - it hooks into the message tray that was removed
f6a177
 - it was known to have performance issues
f6a177
 - there are plenty of alternatives
f6a177
f6a177
Those aren't good enough reasons for dropping it downstream
f6a177
as well though, so we need to bring it back ...
f6a177
f6a177
This reverts commit c9a6421f362cd156cf731289eadc11f44f6970ac.
f6a177
---
f6a177
 extensions/systemMonitor/extension.js     | 376 ++++++++++++++++++++++
f6a177
 extensions/systemMonitor/meson.build      |   5 +
f6a177
 extensions/systemMonitor/metadata.json.in |  11 +
f6a177
 extensions/systemMonitor/stylesheet.css   |  35 ++
f6a177
 meson.build                               |   1 +
f6a177
 5 files changed, 428 insertions(+)
f6a177
 create mode 100644 extensions/systemMonitor/extension.js
f6a177
 create mode 100644 extensions/systemMonitor/meson.build
f6a177
 create mode 100644 extensions/systemMonitor/metadata.json.in
f6a177
 create mode 100644 extensions/systemMonitor/stylesheet.css
f6a177
f6a177
diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js
f6a177
new file mode 100644
f6a177
index 0000000..7b09df0
f6a177
--- /dev/null
f6a177
+++ b/extensions/systemMonitor/extension.js
f6a177
@@ -0,0 +1,376 @@
f6a177
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
f6a177
+
f6a177
+const Clutter = imports.gi.Clutter;
f6a177
+const GTop = imports.gi.GTop;
f6a177
+const Lang = imports.lang;
f6a177
+const Mainloop = imports.mainloop;
f6a177
+const St = imports.gi.St;
f6a177
+const Shell = imports.gi.Shell;
f6a177
+
f6a177
+const Main = imports.ui.main;
f6a177
+const Tweener = imports.ui.tweener;
f6a177
+
f6a177
+const Gettext = imports.gettext.domain('gnome-shell-extensions');
f6a177
+const _ = Gettext.gettext;
f6a177
+
f6a177
+const ExtensionUtils = imports.misc.extensionUtils;
f6a177
+const Me = ExtensionUtils.getCurrentExtension();
f6a177
+const Convenience = Me.imports.convenience;
f6a177
+
f6a177
+const INDICATOR_UPDATE_INTERVAL = 500;
f6a177
+const INDICATOR_NUM_GRID_LINES = 3;
f6a177
+
f6a177
+const ITEM_LABEL_SHOW_TIME = 0.15;
f6a177
+const ITEM_LABEL_HIDE_TIME = 0.1;
f6a177
+const ITEM_HOVER_TIMEOUT = 300;
f6a177
+
f6a177
+const Indicator = new Lang.Class({
f6a177
+    Name: 'SystemMonitor.Indicator',
f6a177
+
f6a177
+    _init: function() {
f6a177
+        this._initValues();
f6a177
+        this.drawing_area = new St.DrawingArea({ reactive: true });
f6a177
+        this.drawing_area.connect('repaint', Lang.bind(this, this._draw));
f6a177
+        this.drawing_area.connect('button-press-event', function() {
f6a177
+            let app = Shell.AppSystem.get_default().lookup_app('gnome-system-monitor.desktop');
f6a177
+            app.open_new_window(-1);
f6a177
+            return true;
f6a177
+        });
f6a177
+
f6a177
+        this.actor = new St.Bin({ style_class: "extension-systemMonitor-indicator-area",
f6a177
+                                  reactive: true, track_hover: true,
f6a177
+				  x_fill: true, y_fill: true });
f6a177
+        this.actor.add_actor(this.drawing_area);
f6a177
+
f6a177
+        this._timeout = Mainloop.timeout_add(INDICATOR_UPDATE_INTERVAL, Lang.bind(this, function () {
f6a177
+            this._updateValues();
f6a177
+            this.drawing_area.queue_repaint();
f6a177
+            return true;
f6a177
+        }));
f6a177
+    },
f6a177
+
f6a177
+    showLabel: function() {
f6a177
+        if (this.label == null)
f6a177
+            return;
f6a177
+
f6a177
+        this.label.opacity = 0;
f6a177
+        this.label.show();
f6a177
+
f6a177
+        let [stageX, stageY] = this.actor.get_transformed_position();
f6a177
+
f6a177
+	let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
f6a177
+        let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
f6a177
+
f6a177
+	let labelWidth = this.label.width;
f6a177
+        let labelHeight = this.label.height;
f6a177
+        let xOffset = Math.floor((itemWidth - labelWidth) / 2)
f6a177
+
f6a177
+        let x = stageX + xOffset;
f6a177
+
f6a177
+        let node = this.label.get_theme_node();
f6a177
+        let yOffset = node.get_length('-y-offset');
f6a177
+
f6a177
+        let y = stageY - this.label.get_height() - yOffset;
f6a177
+
f6a177
+        this.label.set_position(x, y);
f6a177
+        Tweener.addTween(this.label,
f6a177
+                         { opacity: 255,
f6a177
+                           time: ITEM_LABEL_SHOW_TIME,
f6a177
+                           transition: 'easeOutQuad',
f6a177
+                         });
f6a177
+    },
f6a177
+
f6a177
+    setLabelText: function(text) {
f6a177
+        if (this.label == null)
f6a177
+            this.label = new St.Label({ style_class: 'extension-systemMonitor-indicator-label'});
f6a177
+
f6a177
+        this.label.set_text(text);
f6a177
+        Main.layoutManager.addChrome(this.label);
f6a177
+        this.label.hide();
f6a177
+    },
f6a177
+
f6a177
+    hideLabel: function () {
f6a177
+        Tweener.addTween(this.label,
f6a177
+                         { opacity: 0,
f6a177
+                           time: ITEM_LABEL_HIDE_TIME,
f6a177
+                           transition: 'easeOutQuad',
f6a177
+                           onComplete: Lang.bind(this, function() {
f6a177
+                               this.label.hide();
f6a177
+                           })
f6a177
+                         });
f6a177
+    },
f6a177
+
f6a177
+    destroy: function() {
f6a177
+        Mainloop.source_remove(this._timeout);
f6a177
+
f6a177
+        this.actor.destroy();
f6a177
+	if (this.label)
f6a177
+	    this.label.destroy();
f6a177
+    },
f6a177
+
f6a177
+    _initValues: function() {
f6a177
+    },
f6a177
+
f6a177
+    _updateValues: function() {
f6a177
+    },
f6a177
+
f6a177
+    _draw: function(area) {
f6a177
+        let [width, height] = area.get_surface_size();
f6a177
+        let themeNode = this.actor.get_theme_node();
f6a177
+        let cr = area.get_context();
f6a177
+
f6a177
+        //draw the background grid
f6a177
+        let color = themeNode.get_color(this.gridColor);
f6a177
+        let gridOffset = Math.floor(height / (INDICATOR_NUM_GRID_LINES + 1));
f6a177
+        for (let i = 1; i <= INDICATOR_NUM_GRID_LINES; ++i) {
f6a177
+                cr.moveTo(0, i * gridOffset + .5);
f6a177
+                cr.lineTo(width, i * gridOffset + .5);
f6a177
+        }
f6a177
+        Clutter.cairo_set_source_color(cr, color);
f6a177
+        cr.setLineWidth(1);
f6a177
+        cr.setDash([4,1], 0);
f6a177
+        cr.stroke();
f6a177
+
f6a177
+        //draw the foreground
f6a177
+
f6a177
+        function makePath(values, reverse, nudge) {
f6a177
+            if (nudge == null) {
f6a177
+                nudge = 0;
f6a177
+            }
f6a177
+            //if we are going in reverse, we are completing the bottom of a chart, so use lineTo
f6a177
+            if (reverse) {
f6a177
+                cr.lineTo(values.length - 1, (1 - values[values.length - 1]) * height + nudge);
f6a177
+                for (let k = values.length - 2; k >= 0; --k) {
f6a177
+                    cr.lineTo(k, (1 - values[k]) * height + nudge);
f6a177
+                }
f6a177
+            } else {
f6a177
+                cr.moveTo(0, (1 - values[0]) * height + nudge);
f6a177
+                for (let k = 1; k < values.length; ++k) {
f6a177
+                    cr.lineTo(k, (1 - values[k]) * height + nudge);
f6a177
+                }
f6a177
+
f6a177
+            }
f6a177
+        }
f6a177
+
f6a177
+        let renderStats = this.renderStats;
f6a177
+
f6a177
+        // Make sure we don't have more sample points than pixels
f6a177
+        renderStats.map(Lang.bind(this, function(k){
f6a177
+            let stat = this.stats[k];
f6a177
+            if (stat.values.length > width) {
f6a177
+                stat.values = stat.values.slice(stat.values.length - width, stat.values.length);
f6a177
+            }
f6a177
+        }));
f6a177
+
f6a177
+        for (let i = 0; i < renderStats.length; ++i) {
f6a177
+            let stat = this.stats[renderStats[i]];
f6a177
+            // We outline at full opacity and fill with 40% opacity
f6a177
+            let outlineColor = themeNode.get_color(stat.color);
f6a177
+            let color = new Clutter.Color(outlineColor);
f6a177
+            color.alpha = color.alpha * .4;
f6a177
+
f6a177
+            // Render the background between us and the next level
f6a177
+            makePath(stat.values, false);
f6a177
+            // If there is a process below us, render the cpu between us and it, otherwise,
f6a177
+            // render to the bottom of the chart
f6a177
+            if (i == renderStats.length - 1) {
f6a177
+                cr.lineTo(stat.values.length - 1, height);
f6a177
+                cr.lineTo(0, height);
f6a177
+                cr.closePath();
f6a177
+            } else {
f6a177
+                let nextStat = this.stats[renderStats[i+1]];
f6a177
+                makePath(nextStat.values, true);
f6a177
+            }
f6a177
+            cr.closePath()
f6a177
+            Clutter.cairo_set_source_color(cr, color);
f6a177
+            cr.fill();
f6a177
+
f6a177
+            // Render the outline of this level
f6a177
+            makePath(stat.values, false, .5);
f6a177
+            Clutter.cairo_set_source_color(cr, outlineColor);
f6a177
+            cr.setLineWidth(1.0);
f6a177
+            cr.setDash([], 0);
f6a177
+            cr.stroke();
f6a177
+        }
f6a177
+    }
f6a177
+});
f6a177
+
f6a177
+const CpuIndicator = new Lang.Class({
f6a177
+    Name: 'SystemMonitor.CpuIndicator',
f6a177
+    Extends: Indicator,
f6a177
+
f6a177
+    _init: function() {
f6a177
+        this.parent();
f6a177
+
f6a177
+        this.gridColor = '-grid-color';
f6a177
+        this.renderStats = [ 'cpu-user', 'cpu-sys', 'cpu-iowait' ];
f6a177
+
f6a177
+        // Make sure renderStats is sorted as necessary for rendering
f6a177
+        let renderStatOrder = {'cpu-total': 0, 'cpu-user': 1, 'cpu-sys': 2, 'cpu-iowait': 3};
f6a177
+        this.renderStats = this.renderStats.sort(function(a,b) {
f6a177
+            return renderStatOrder[a] - renderStatOrder[b];
f6a177
+        });
f6a177
+
f6a177
+	this.setLabelText(_("CPU"));
f6a177
+    },
f6a177
+
f6a177
+    _initValues: function() {
f6a177
+        this._prev = new GTop.glibtop_cpu;
f6a177
+        GTop.glibtop_get_cpu(this._prev);
f6a177
+
f6a177
+        this.stats = {
f6a177
+                       'cpu-user': {color: '-cpu-user-color', values: []},
f6a177
+                       'cpu-sys': {color: '-cpu-sys-color', values: []},
f6a177
+                       'cpu-iowait': {color: '-cpu-iowait-color', values: []},
f6a177
+                       'cpu-total': {color: '-cpu-total-color', values: []}
f6a177
+                     };
f6a177
+    },
f6a177
+
f6a177
+    _updateValues: function() {
f6a177
+        let cpu = new GTop.glibtop_cpu;
f6a177
+        let t = 0.0;
f6a177
+        GTop.glibtop_get_cpu(cpu);
f6a177
+        let total = cpu.total - this._prev.total;
f6a177
+        let user = cpu.user - this._prev.user;
f6a177
+        let sys = cpu.sys - this._prev.sys;
f6a177
+        let iowait = cpu.iowait - this._prev.iowait;
f6a177
+        let idle = cpu.idle - this._prev.idle;
f6a177
+
f6a177
+        t += iowait / total;
f6a177
+        this.stats['cpu-iowait'].values.push(t);
f6a177
+        t += sys / total;
f6a177
+        this.stats['cpu-sys'].values.push(t);
f6a177
+        t += user / total;
f6a177
+        this.stats['cpu-user'].values.push(t);
f6a177
+        this.stats['cpu-total'].values.push(1 - idle / total);
f6a177
+
f6a177
+        this._prev = cpu;
f6a177
+    }
f6a177
+});
f6a177
+
f6a177
+const MemoryIndicator = new Lang.Class({
f6a177
+    Name: 'SystemMonitor.MemoryIndicator',
f6a177
+    Extends: Indicator,
f6a177
+
f6a177
+    _init: function() {
f6a177
+        this.parent();
f6a177
+
f6a177
+        this.gridColor = '-grid-color';
f6a177
+        this.renderStats = [ 'mem-user', 'mem-other', 'mem-cached' ];
f6a177
+
f6a177
+        // Make sure renderStats is sorted as necessary for rendering
f6a177
+        let renderStatOrder = { 'mem-cached': 0, 'mem-other': 1, 'mem-user': 2 };
f6a177
+        this.renderStats = this.renderStats.sort(function(a,b) {
f6a177
+            return renderStatOrder[a] - renderStatOrder[b];
f6a177
+        });
f6a177
+
f6a177
+	this.setLabelText(_("Memory"));
f6a177
+    },
f6a177
+
f6a177
+    _initValues: function() {
f6a177
+        this.mem = new GTop.glibtop_mem;
f6a177
+        this.stats = {
f6a177
+                        'mem-user': { color: "-mem-user-color", values: [] },
f6a177
+                        'mem-other': { color: "-mem-other-color", values: [] },
f6a177
+                        'mem-cached': { color: "-mem-cached-color", values: [] }
f6a177
+                     };
f6a177
+    },
f6a177
+
f6a177
+    _updateValues: function() {
f6a177
+        GTop.glibtop_get_mem(this.mem);
f6a177
+
f6a177
+        let t = this.mem.user / this.mem.total;
f6a177
+        this.stats['mem-user'].values.push(t);
f6a177
+        t += (this.mem.used - this.mem.user - this.mem.cached) / this.mem.total;
f6a177
+        this.stats['mem-other'].values.push(t);
f6a177
+        t += this.mem.cached / this.mem.total;
f6a177
+        this.stats['mem-cached'].values.push(t);
f6a177
+    }
f6a177
+});
f6a177
+
f6a177
+const INDICATORS = [CpuIndicator, MemoryIndicator];
f6a177
+
f6a177
+const Extension = new Lang.Class({
f6a177
+    Name: 'SystemMonitor.Extension',
f6a177
+
f6a177
+    _init: function() {
f6a177
+	Convenience.initTranslations();
f6a177
+
f6a177
+	this._showLabelTimeoutId = 0;
f6a177
+	this._resetHoverTimeoutId = 0;
f6a177
+	this._labelShowing = false;
f6a177
+    },
f6a177
+
f6a177
+    enable: function() {
f6a177
+	this._box = new St.BoxLayout({ style_class: 'extension-systemMonitor-container',
f6a177
+				       x_align: Clutter.ActorAlign.START,
f6a177
+				       x_expand: true });
f6a177
+	this._indicators = [ ];
f6a177
+
f6a177
+	for (let i = 0; i < INDICATORS.length; i++) {
f6a177
+	    let indicator = new (INDICATORS[i])();
f6a177
+
f6a177
+            indicator.actor.connect('notify::hover', Lang.bind(this, function() {
f6a177
+		this._onHover(indicator);
f6a177
+	    }));
f6a177
+	    this._box.add_actor(indicator.actor);
f6a177
+	    this._indicators.push(indicator);
f6a177
+	}
f6a177
+
f6a177
+	this._boxHolder = new St.BoxLayout({ x_expand: true,
f6a177
+					     y_expand: true,
f6a177
+					     x_align: Clutter.ActorAlign.START,
f6a177
+					   });
f6a177
+	let menuButton = Main.messageTray._messageTrayMenuButton.actor;
f6a177
+	Main.messageTray.actor.remove_child(menuButton);
f6a177
+	Main.messageTray.actor.add_child(this._boxHolder);
f6a177
+
f6a177
+	this._boxHolder.add_child(this._box);
f6a177
+	this._boxHolder.add_child(menuButton);
f6a177
+    },
f6a177
+
f6a177
+    disable: function() {
f6a177
+	this._indicators.forEach(function(i) { i.destroy(); });
f6a177
+
f6a177
+	let menuButton = Main.messageTray._messageTrayMenuButton.actor;
f6a177
+	this._boxHolder.remove_child(menuButton);
f6a177
+	Main.messageTray.actor.add_child(menuButton);
f6a177
+
f6a177
+	this._box.destroy();
f6a177
+	this._boxHolder.destroy();
f6a177
+    },
f6a177
+
f6a177
+    _onHover: function (item) {
f6a177
+        if (item.actor.get_hover()) {
f6a177
+            if (this._showLabelTimeoutId == 0) {
f6a177
+                let timeout = this._labelShowing ? 0 : ITEM_HOVER_TIMEOUT;
f6a177
+                this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
f6a177
+                    Lang.bind(this, function() {
f6a177
+                        this._labelShowing = true;
f6a177
+                        item.showLabel();
f6a177
+                        return false;
f6a177
+                    }));
f6a177
+                if (this._resetHoverTimeoutId > 0) {
f6a177
+                    Mainloop.source_remove(this._resetHoverTimeoutId);
f6a177
+                    this._resetHoverTimeoutId = 0;
f6a177
+                }
f6a177
+            }
f6a177
+        } else {
f6a177
+            if (this._showLabelTimeoutId > 0)
f6a177
+                Mainloop.source_remove(this._showLabelTimeoutId);
f6a177
+            this._showLabelTimeoutId = 0;
f6a177
+            item.hideLabel();
f6a177
+            if (this._labelShowing) {
f6a177
+                this._resetHoverTimeoutId = Mainloop.timeout_add(ITEM_HOVER_TIMEOUT,
f6a177
+                    Lang.bind(this, function() {
f6a177
+                        this._labelShowing = false;
f6a177
+                        return false;
f6a177
+                    }));
f6a177
+            }
f6a177
+        }
f6a177
+    },
f6a177
+});
f6a177
+
f6a177
+function init() {
f6a177
+    return new Extension();
f6a177
+}
f6a177
diff --git a/extensions/systemMonitor/meson.build b/extensions/systemMonitor/meson.build
f6a177
new file mode 100644
f6a177
index 0000000..48504f6
f6a177
--- /dev/null
f6a177
+++ b/extensions/systemMonitor/meson.build
f6a177
@@ -0,0 +1,5 @@
f6a177
+extension_data += configure_file(
f6a177
+  input: metadata_name + '.in',
f6a177
+  output: metadata_name,
f6a177
+  configuration: metadata_conf
f6a177
+)
f6a177
diff --git a/extensions/systemMonitor/metadata.json.in b/extensions/systemMonitor/metadata.json.in
f6a177
new file mode 100644
f6a177
index 0000000..fa75007
f6a177
--- /dev/null
f6a177
+++ b/extensions/systemMonitor/metadata.json.in
f6a177
@@ -0,0 +1,11 @@
f6a177
+{
f6a177
+    "shell-version": ["@shell_current@" ],
f6a177
+    "uuid": "@uuid@",
f6a177
+    "extension-id": "@extension_id@",
f6a177
+    "settings-schema": "@gschemaname@",
f6a177
+    "gettext-domain": "@gettext_domain@",
f6a177
+    "original-author": "zaspire@rambler.ru",
f6a177
+    "name": "SystemMonitor",
f6a177
+    "description": "System monitor showing CPU and memory usage in the message tray.",
f6a177
+    "url": "@url@"
f6a177
+}
f6a177
diff --git a/extensions/systemMonitor/stylesheet.css b/extensions/systemMonitor/stylesheet.css
f6a177
new file mode 100644
f6a177
index 0000000..13f95ec
f6a177
--- /dev/null
f6a177
+++ b/extensions/systemMonitor/stylesheet.css
f6a177
@@ -0,0 +1,35 @@
f6a177
+.extension-systemMonitor-container {
f6a177
+    spacing: 5px;
f6a177
+    padding-left: 5px;
f6a177
+    padding-right: 5px;
f6a177
+    padding-bottom: 10px;
f6a177
+    padding-top: 10px;
f6a177
+}
f6a177
+
f6a177
+.extension-systemMonitor-indicator-area {
f6a177
+    border: 1px solid #8d8d8d;
f6a177
+    border-radius: 3px;
f6a177
+    width: 100px;
f6a177
+    /* message tray is 72px, so 20px padding of the container,
f6a177
+       2px of border, makes it 50px */
f6a177
+    height: 50px;
f6a177
+    -grid-color: #575757;
f6a177
+    -cpu-total-color: rgb(0,154,62);
f6a177
+    -cpu-user-color: rgb(69,154,0);
f6a177
+    -cpu-sys-color: rgb(255,253,81);
f6a177
+    -cpu-iowait-color: rgb(210,148,0);
f6a177
+    -mem-user-color: rgb(210,148,0);
f6a177
+    -mem-cached-color: rgb(90,90,90);
f6a177
+    -mem-other-color: rgb(205,203,41);
f6a177
+    background-color: #1e1e1e;
f6a177
+}
f6a177
+
f6a177
+.extension-systemMonitor-indicator-label {
f6a177
+    border-radius: 7px;
f6a177
+    padding: 4px 12px;
f6a177
+    background-color: rgba(0,0,0,0.9);
f6a177
+    text-align: center;
f6a177
+    -y-offset: 8px;
f6a177
+    font-size: 9pt;
f6a177
+    font-weight: bold;
f6a177
+}
f6a177
diff --git a/meson.build b/meson.build
f6a177
index 7562eb1..955b5ee 100644
f6a177
--- a/meson.build
f6a177
+++ b/meson.build
f6a177
@@ -58,6 +58,7 @@ all_extensions += [
f6a177
   'native-window-placement',
f6a177
   'no-hot-corner',
f6a177
   'panel-favorites',
f6a177
+  'systemMonitor',
f6a177
   'top-icons',
f6a177
   'updates-dialog',
f6a177
   'user-theme',
f6a177
-- 
f6a177
2.21.0
f6a177
f6a177
f6a177
From 2f3092238bf17bf41749674dd94bf4609a955624 Mon Sep 17 00:00:00 2001
f6a177
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
f6a177
Date: Wed, 17 May 2017 19:31:58 +0200
f6a177
Subject: [PATCH 2/4] systemMonitor: Move indicators to calendar
f6a177
f6a177
The message tray joined the invisible choir, so we have to find
f6a177
a new home for the extension UI. The message list in the calendar
f6a177
drop-down looks like the best option, given that it replaced the
f6a177
old tray (and also took over the old keyboard shortcut to bring
f6a177
it up quickly).
f6a177
---
f6a177
 extensions/systemMonitor/extension.js   | 56 ++++++++++++-------------
f6a177
 extensions/systemMonitor/stylesheet.css | 14 -------
f6a177
 2 files changed, 28 insertions(+), 42 deletions(-)
f6a177
f6a177
diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js
f6a177
index 7b09df0..1388a1f 100644
f6a177
--- a/extensions/systemMonitor/extension.js
f6a177
+++ b/extensions/systemMonitor/extension.js
f6a177
@@ -1,132 +1,146 @@
f6a177
 /* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
f6a177
 
f6a177
 const Clutter = imports.gi.Clutter;
f6a177
 const GTop = imports.gi.GTop;
f6a177
 const Lang = imports.lang;
f6a177
 const Mainloop = imports.mainloop;
f6a177
+const Signals = imports.signals;
f6a177
 const St = imports.gi.St;
f6a177
 const Shell = imports.gi.Shell;
f6a177
 
f6a177
 const Main = imports.ui.main;
f6a177
+const MessageList = imports.ui.messageList;
f6a177
 const Tweener = imports.ui.tweener;
f6a177
 
f6a177
 const Gettext = imports.gettext.domain('gnome-shell-extensions');
f6a177
 const _ = Gettext.gettext;
f6a177
 
f6a177
 const ExtensionUtils = imports.misc.extensionUtils;
f6a177
 const Me = ExtensionUtils.getCurrentExtension();
f6a177
 const Convenience = Me.imports.convenience;
f6a177
 
f6a177
 const INDICATOR_UPDATE_INTERVAL = 500;
f6a177
 const INDICATOR_NUM_GRID_LINES = 3;
f6a177
 
f6a177
 const ITEM_LABEL_SHOW_TIME = 0.15;
f6a177
 const ITEM_LABEL_HIDE_TIME = 0.1;
f6a177
 const ITEM_HOVER_TIMEOUT = 300;
f6a177
 
f6a177
 const Indicator = new Lang.Class({
f6a177
     Name: 'SystemMonitor.Indicator',
f6a177
 
f6a177
     _init: function() {
f6a177
         this._initValues();
f6a177
-        this.drawing_area = new St.DrawingArea({ reactive: true });
f6a177
+        this.drawing_area = new St.DrawingArea();
f6a177
         this.drawing_area.connect('repaint', Lang.bind(this, this._draw));
f6a177
-        this.drawing_area.connect('button-press-event', function() {
f6a177
+
f6a177
+        this.actor = new St.Button({ style_class: "message message-content extension-systemMonitor-indicator-area",
f6a177
+				      x_expand: true, x_fill: true,
f6a177
+                                      y_fill: true, can_focus: true });
f6a177
+        this.actor.add_actor(this.drawing_area);
f6a177
+
f6a177
+        this.actor.connect('clicked', function() {
f6a177
             let app = Shell.AppSystem.get_default().lookup_app('gnome-system-monitor.desktop');
f6a177
             app.open_new_window(-1);
f6a177
-            return true;
f6a177
-        });
f6a177
 
f6a177
-        this.actor = new St.Bin({ style_class: "extension-systemMonitor-indicator-area",
f6a177
-                                  reactive: true, track_hover: true,
f6a177
-				  x_fill: true, y_fill: true });
f6a177
-        this.actor.add_actor(this.drawing_area);
f6a177
+            Main.overview.hide();
f6a177
+            Main.panel.closeCalendar();
f6a177
+        });
f6a177
 
f6a177
         this._timeout = Mainloop.timeout_add(INDICATOR_UPDATE_INTERVAL, Lang.bind(this, function () {
f6a177
             this._updateValues();
f6a177
             this.drawing_area.queue_repaint();
f6a177
             return true;
f6a177
         }));
f6a177
     },
f6a177
 
f6a177
     showLabel: function() {
f6a177
         if (this.label == null)
f6a177
             return;
f6a177
 
f6a177
         this.label.opacity = 0;
f6a177
         this.label.show();
f6a177
 
f6a177
         let [stageX, stageY] = this.actor.get_transformed_position();
f6a177
 
f6a177
 	let itemWidth = this.actor.allocation.x2 - this.actor.allocation.x1;
f6a177
         let itemHeight = this.actor.allocation.y2 - this.actor.allocation.y1;
f6a177
 
f6a177
 	let labelWidth = this.label.width;
f6a177
         let labelHeight = this.label.height;
f6a177
         let xOffset = Math.floor((itemWidth - labelWidth) / 2)
f6a177
 
f6a177
         let x = stageX + xOffset;
f6a177
 
f6a177
         let node = this.label.get_theme_node();
f6a177
         let yOffset = node.get_length('-y-offset');
f6a177
 
f6a177
         let y = stageY - this.label.get_height() - yOffset;
f6a177
 
f6a177
         this.label.set_position(x, y);
f6a177
+        this.label.get_parent().set_child_above_sibling(this.label, null);
f6a177
         Tweener.addTween(this.label,
f6a177
                          { opacity: 255,
f6a177
                            time: ITEM_LABEL_SHOW_TIME,
f6a177
                            transition: 'easeOutQuad',
f6a177
                          });
f6a177
     },
f6a177
 
f6a177
     setLabelText: function(text) {
f6a177
         if (this.label == null)
f6a177
             this.label = new St.Label({ style_class: 'extension-systemMonitor-indicator-label'});
f6a177
 
f6a177
         this.label.set_text(text);
f6a177
         Main.layoutManager.addChrome(this.label);
f6a177
         this.label.hide();
f6a177
     },
f6a177
 
f6a177
     hideLabel: function () {
f6a177
         Tweener.addTween(this.label,
f6a177
                          { opacity: 0,
f6a177
                            time: ITEM_LABEL_HIDE_TIME,
f6a177
                            transition: 'easeOutQuad',
f6a177
                            onComplete: Lang.bind(this, function() {
f6a177
                                this.label.hide();
f6a177
                            })
f6a177
                          });
f6a177
     },
f6a177
 
f6a177
+    /* MessageList.Message boilerplate */
f6a177
+    canClose: function() {
f6a177
+        return false;
f6a177
+    },
f6a177
+
f6a177
+    clear: function() {
f6a177
+    },
f6a177
+
f6a177
     destroy: function() {
f6a177
         Mainloop.source_remove(this._timeout);
f6a177
 
f6a177
         this.actor.destroy();
f6a177
 	if (this.label)
f6a177
 	    this.label.destroy();
f6a177
     },
f6a177
 
f6a177
     _initValues: function() {
f6a177
     },
f6a177
 
f6a177
     _updateValues: function() {
f6a177
     },
f6a177
 
f6a177
     _draw: function(area) {
f6a177
         let [width, height] = area.get_surface_size();
f6a177
         let themeNode = this.actor.get_theme_node();
f6a177
         let cr = area.get_context();
f6a177
 
f6a177
         //draw the background grid
f6a177
         let color = themeNode.get_color(this.gridColor);
f6a177
         let gridOffset = Math.floor(height / (INDICATOR_NUM_GRID_LINES + 1));
f6a177
         for (let i = 1; i <= INDICATOR_NUM_GRID_LINES; ++i) {
f6a177
                 cr.moveTo(0, i * gridOffset + .5);
f6a177
                 cr.lineTo(width, i * gridOffset + .5);
f6a177
         }
f6a177
         Clutter.cairo_set_source_color(cr, color);
f6a177
         cr.setLineWidth(1);
f6a177
         cr.setDash([4,1], 0);
f6a177
         cr.stroke();
f6a177
@@ -167,60 +181,61 @@ const Indicator = new Lang.Class({
f6a177
             // We outline at full opacity and fill with 40% opacity
f6a177
             let outlineColor = themeNode.get_color(stat.color);
f6a177
             let color = new Clutter.Color(outlineColor);
f6a177
             color.alpha = color.alpha * .4;
f6a177
 
f6a177
             // Render the background between us and the next level
f6a177
             makePath(stat.values, false);
f6a177
             // If there is a process below us, render the cpu between us and it, otherwise,
f6a177
             // render to the bottom of the chart
f6a177
             if (i == renderStats.length - 1) {
f6a177
                 cr.lineTo(stat.values.length - 1, height);
f6a177
                 cr.lineTo(0, height);
f6a177
                 cr.closePath();
f6a177
             } else {
f6a177
                 let nextStat = this.stats[renderStats[i+1]];
f6a177
                 makePath(nextStat.values, true);
f6a177
             }
f6a177
             cr.closePath()
f6a177
             Clutter.cairo_set_source_color(cr, color);
f6a177
             cr.fill();
f6a177
 
f6a177
             // Render the outline of this level
f6a177
             makePath(stat.values, false, .5);
f6a177
             Clutter.cairo_set_source_color(cr, outlineColor);
f6a177
             cr.setLineWidth(1.0);
f6a177
             cr.setDash([], 0);
f6a177
             cr.stroke();
f6a177
         }
f6a177
     }
f6a177
 });
f6a177
+Signals.addSignalMethods(Indicator.prototype); // For MessageList.Message compat
f6a177
 
f6a177
 const CpuIndicator = new Lang.Class({
f6a177
     Name: 'SystemMonitor.CpuIndicator',
f6a177
     Extends: Indicator,
f6a177
 
f6a177
     _init: function() {
f6a177
         this.parent();
f6a177
 
f6a177
         this.gridColor = '-grid-color';
f6a177
         this.renderStats = [ 'cpu-user', 'cpu-sys', 'cpu-iowait' ];
f6a177
 
f6a177
         // Make sure renderStats is sorted as necessary for rendering
f6a177
         let renderStatOrder = {'cpu-total': 0, 'cpu-user': 1, 'cpu-sys': 2, 'cpu-iowait': 3};
f6a177
         this.renderStats = this.renderStats.sort(function(a,b) {
f6a177
             return renderStatOrder[a] - renderStatOrder[b];
f6a177
         });
f6a177
 
f6a177
 	this.setLabelText(_("CPU"));
f6a177
     },
f6a177
 
f6a177
     _initValues: function() {
f6a177
         this._prev = new GTop.glibtop_cpu;
f6a177
         GTop.glibtop_get_cpu(this._prev);
f6a177
 
f6a177
         this.stats = {
f6a177
                        'cpu-user': {color: '-cpu-user-color', values: []},
f6a177
                        'cpu-sys': {color: '-cpu-sys-color', values: []},
f6a177
                        'cpu-iowait': {color: '-cpu-iowait-color', values: []},
f6a177
                        'cpu-total': {color: '-cpu-total-color', values: []}
f6a177
                      };
f6a177
@@ -275,96 +290,81 @@ const MemoryIndicator = new Lang.Class({
f6a177
                         'mem-cached': { color: "-mem-cached-color", values: [] }
f6a177
                      };
f6a177
     },
f6a177
 
f6a177
     _updateValues: function() {
f6a177
         GTop.glibtop_get_mem(this.mem);
f6a177
 
f6a177
         let t = this.mem.user / this.mem.total;
f6a177
         this.stats['mem-user'].values.push(t);
f6a177
         t += (this.mem.used - this.mem.user - this.mem.cached) / this.mem.total;
f6a177
         this.stats['mem-other'].values.push(t);
f6a177
         t += this.mem.cached / this.mem.total;
f6a177
         this.stats['mem-cached'].values.push(t);
f6a177
     }
f6a177
 });
f6a177
 
f6a177
 const INDICATORS = [CpuIndicator, MemoryIndicator];
f6a177
 
f6a177
 const Extension = new Lang.Class({
f6a177
     Name: 'SystemMonitor.Extension',
f6a177
 
f6a177
     _init: function() {
f6a177
 	Convenience.initTranslations();
f6a177
 
f6a177
 	this._showLabelTimeoutId = 0;
f6a177
 	this._resetHoverTimeoutId = 0;
f6a177
 	this._labelShowing = false;
f6a177
     },
f6a177
 
f6a177
     enable: function() {
f6a177
-	this._box = new St.BoxLayout({ style_class: 'extension-systemMonitor-container',
f6a177
-				       x_align: Clutter.ActorAlign.START,
f6a177
-				       x_expand: true });
f6a177
+	this._section = new MessageList.MessageListSection(_("System Monitor"));
f6a177
 	this._indicators = [ ];
f6a177
 
f6a177
 	for (let i = 0; i < INDICATORS.length; i++) {
f6a177
 	    let indicator = new (INDICATORS[i])();
f6a177
 
f6a177
             indicator.actor.connect('notify::hover', Lang.bind(this, function() {
f6a177
 		this._onHover(indicator);
f6a177
 	    }));
f6a177
-	    this._box.add_actor(indicator.actor);
f6a177
+	    this._section.addMessage(indicator, false);
f6a177
 	    this._indicators.push(indicator);
f6a177
 	}
f6a177
 
f6a177
-	this._boxHolder = new St.BoxLayout({ x_expand: true,
f6a177
-					     y_expand: true,
f6a177
-					     x_align: Clutter.ActorAlign.START,
f6a177
-					   });
f6a177
-	let menuButton = Main.messageTray._messageTrayMenuButton.actor;
f6a177
-	Main.messageTray.actor.remove_child(menuButton);
f6a177
-	Main.messageTray.actor.add_child(this._boxHolder);
f6a177
-
f6a177
-	this._boxHolder.add_child(this._box);
f6a177
-	this._boxHolder.add_child(menuButton);
f6a177
+        Main.panel.statusArea.dateMenu._messageList._addSection(this._section);
f6a177
+        this._section.actor.get_parent().set_child_at_index(this._section.actor, 0);
f6a177
     },
f6a177
 
f6a177
     disable: function() {
f6a177
 	this._indicators.forEach(function(i) { i.destroy(); });
f6a177
 
f6a177
-	let menuButton = Main.messageTray._messageTrayMenuButton.actor;
f6a177
-	this._boxHolder.remove_child(menuButton);
f6a177
-	Main.messageTray.actor.add_child(menuButton);
f6a177
-
f6a177
-	this._box.destroy();
f6a177
-	this._boxHolder.destroy();
f6a177
+        Main.panel.statusArea.dateMenu._messageList._removeSection(this._section);
f6a177
     },
f6a177
 
f6a177
     _onHover: function (item) {
f6a177
         if (item.actor.get_hover()) {
f6a177
             if (this._showLabelTimeoutId == 0) {
f6a177
                 let timeout = this._labelShowing ? 0 : ITEM_HOVER_TIMEOUT;
f6a177
                 this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
f6a177
                     Lang.bind(this, function() {
f6a177
                         this._labelShowing = true;
f6a177
                         item.showLabel();
f6a177
                         return false;
f6a177
                     }));
f6a177
                 if (this._resetHoverTimeoutId > 0) {
f6a177
                     Mainloop.source_remove(this._resetHoverTimeoutId);
f6a177
                     this._resetHoverTimeoutId = 0;
f6a177
                 }
f6a177
             }
f6a177
         } else {
f6a177
             if (this._showLabelTimeoutId > 0)
f6a177
                 Mainloop.source_remove(this._showLabelTimeoutId);
f6a177
             this._showLabelTimeoutId = 0;
f6a177
             item.hideLabel();
f6a177
             if (this._labelShowing) {
f6a177
                 this._resetHoverTimeoutId = Mainloop.timeout_add(ITEM_HOVER_TIMEOUT,
f6a177
                     Lang.bind(this, function() {
f6a177
                         this._labelShowing = false;
f6a177
                         return false;
f6a177
                     }));
f6a177
             }
f6a177
         }
f6a177
diff --git a/extensions/systemMonitor/stylesheet.css b/extensions/systemMonitor/stylesheet.css
f6a177
index 13f95ec..978ac12 100644
f6a177
--- a/extensions/systemMonitor/stylesheet.css
f6a177
+++ b/extensions/systemMonitor/stylesheet.css
f6a177
@@ -1,35 +1,21 @@
f6a177
-.extension-systemMonitor-container {
f6a177
-    spacing: 5px;
f6a177
-    padding-left: 5px;
f6a177
-    padding-right: 5px;
f6a177
-    padding-bottom: 10px;
f6a177
-    padding-top: 10px;
f6a177
-}
f6a177
-
f6a177
 .extension-systemMonitor-indicator-area {
f6a177
-    border: 1px solid #8d8d8d;
f6a177
-    border-radius: 3px;
f6a177
-    width: 100px;
f6a177
-    /* message tray is 72px, so 20px padding of the container,
f6a177
-       2px of border, makes it 50px */
f6a177
     height: 50px;
f6a177
     -grid-color: #575757;
f6a177
     -cpu-total-color: rgb(0,154,62);
f6a177
     -cpu-user-color: rgb(69,154,0);
f6a177
     -cpu-sys-color: rgb(255,253,81);
f6a177
     -cpu-iowait-color: rgb(210,148,0);
f6a177
     -mem-user-color: rgb(210,148,0);
f6a177
     -mem-cached-color: rgb(90,90,90);
f6a177
     -mem-other-color: rgb(205,203,41);
f6a177
-    background-color: #1e1e1e;
f6a177
 }
f6a177
 
f6a177
 .extension-systemMonitor-indicator-label {
f6a177
     border-radius: 7px;
f6a177
     padding: 4px 12px;
f6a177
     background-color: rgba(0,0,0,0.9);
f6a177
     text-align: center;
f6a177
     -y-offset: 8px;
f6a177
     font-size: 9pt;
f6a177
     font-weight: bold;
f6a177
 }
f6a177
-- 
f6a177
2.17.1
f6a177
f6a177
f6a177
From e1133a8a92c49a90e02f8d2f1e66c7aae9d19519 Mon Sep 17 00:00:00 2001
f6a177
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
f6a177
Date: Thu, 18 May 2017 16:20:07 +0200
f6a177
Subject: [PATCH 3/4] systemMonitor: Handle clicks on section title
f6a177
f6a177
While on 3.24.x only the event section still has a clickable title,
f6a177
it's a generic message list feature in previous versions. It's easy
f6a177
enough to support with a small subclass, so use that instead of
f6a177
the generic baseclass.
f6a177
f6a177
Fixes: #3
f6a177
---
f6a177
 extensions/systemMonitor/extension.js | 20 +++++++++++++++++++-
f6a177
 1 file changed, 19 insertions(+), 1 deletion(-)
f6a177
f6a177
diff --git a/extensions/systemMonitor/extension.js b/extensions/systemMonitor/extension.js
f6a177
index 1388a1f..9c010d8 100644
f6a177
--- a/extensions/systemMonitor/extension.js
f6a177
+++ b/extensions/systemMonitor/extension.js
f6a177
@@ -276,75 +276,93 @@ const MemoryIndicator = new Lang.Class({
f6a177
         // Make sure renderStats is sorted as necessary for rendering
f6a177
         let renderStatOrder = { 'mem-cached': 0, 'mem-other': 1, 'mem-user': 2 };
f6a177
         this.renderStats = this.renderStats.sort(function(a,b) {
f6a177
             return renderStatOrder[a] - renderStatOrder[b];
f6a177
         });
f6a177
 
f6a177
 	this.setLabelText(_("Memory"));
f6a177
     },
f6a177
 
f6a177
     _initValues: function() {
f6a177
         this.mem = new GTop.glibtop_mem;
f6a177
         this.stats = {
f6a177
                         'mem-user': { color: "-mem-user-color", values: [] },
f6a177
                         'mem-other': { color: "-mem-other-color", values: [] },
f6a177
                         'mem-cached': { color: "-mem-cached-color", values: [] }
f6a177
                      };
f6a177
     },
f6a177
 
f6a177
     _updateValues: function() {
f6a177
         GTop.glibtop_get_mem(this.mem);
f6a177
 
f6a177
         let t = this.mem.user / this.mem.total;
f6a177
         this.stats['mem-user'].values.push(t);
f6a177
         t += (this.mem.used - this.mem.user - this.mem.cached) / this.mem.total;
f6a177
         this.stats['mem-other'].values.push(t);
f6a177
         t += this.mem.cached / this.mem.total;
f6a177
         this.stats['mem-cached'].values.push(t);
f6a177
     }
f6a177
 });
f6a177
 
f6a177
+const SystemMonitorSection = new Lang.Class({
f6a177
+    Name: 'SystemMonitorSection',
f6a177
+    Extends: MessageList.MessageListSection,
f6a177
+
f6a177
+    _init: function() {
f6a177
+        this.parent(_("System Monitor"));
f6a177
+    },
f6a177
+
f6a177
+    _onTitleClicked: function() {
f6a177
+        this.parent();
f6a177
+
f6a177
+        let appSys = Shell.AppSystem.get_default();
f6a177
+        let app = appSys.lookup_app('gnome-system-monitor.desktop');
f6a177
+        if (app)
f6a177
+            app.open_new_window(-1);
f6a177
+    }
f6a177
+});
f6a177
+
f6a177
 const INDICATORS = [CpuIndicator, MemoryIndicator];
f6a177
 
f6a177
 const Extension = new Lang.Class({
f6a177
     Name: 'SystemMonitor.Extension',
f6a177
 
f6a177
     _init: function() {
f6a177
 	Convenience.initTranslations();
f6a177
 
f6a177
 	this._showLabelTimeoutId = 0;
f6a177
 	this._resetHoverTimeoutId = 0;
f6a177
 	this._labelShowing = false;
f6a177
     },
f6a177
 
f6a177
     enable: function() {
f6a177
-	this._section = new MessageList.MessageListSection(_("System Monitor"));
f6a177
+	this._section = new SystemMonitorSection();
f6a177
 	this._indicators = [ ];
f6a177
 
f6a177
 	for (let i = 0; i < INDICATORS.length; i++) {
f6a177
 	    let indicator = new (INDICATORS[i])();
f6a177
 
f6a177
             indicator.actor.connect('notify::hover', Lang.bind(this, function() {
f6a177
 		this._onHover(indicator);
f6a177
 	    }));
f6a177
 	    this._section.addMessage(indicator, false);
f6a177
 	    this._indicators.push(indicator);
f6a177
 	}
f6a177
 
f6a177
         Main.panel.statusArea.dateMenu._messageList._addSection(this._section);
f6a177
         this._section.actor.get_parent().set_child_at_index(this._section.actor, 0);
f6a177
     },
f6a177
 
f6a177
     disable: function() {
f6a177
 	this._indicators.forEach(function(i) { i.destroy(); });
f6a177
 
f6a177
         Main.panel.statusArea.dateMenu._messageList._removeSection(this._section);
f6a177
     },
f6a177
 
f6a177
     _onHover: function (item) {
f6a177
         if (item.actor.get_hover()) {
f6a177
             if (this._showLabelTimeoutId == 0) {
f6a177
                 let timeout = this._labelShowing ? 0 : ITEM_HOVER_TIMEOUT;
f6a177
                 this._showLabelTimeoutId = Mainloop.timeout_add(timeout,
f6a177
                     Lang.bind(this, function() {
f6a177
                         this._labelShowing = true;
f6a177
                         item.showLabel();
f6a177
-- 
f6a177
2.17.1
f6a177
f6a177
f6a177
From d2a0c7bfdb3fedf56021b6fd64628e4cda1aa294 Mon Sep 17 00:00:00 2001
f6a177
From: =?UTF-8?q?Florian=20M=C3=BCllner?= <fmuellner@gnome.org>
f6a177
Date: Thu, 18 May 2017 18:00:17 +0200
f6a177
Subject: [PATCH 4/4] systemMonitor: Provide classic styling
f6a177
f6a177
The indicator tooltips currently don't work out in classic mode
f6a177
(dark text on dark background), so provide some mode-specific
f6a177
style.
f6a177
f6a177
Fixes: #4
f6a177
---
f6a177
 extensions/systemMonitor/classic.css | 6 ++++++
f6a177
 extensions/systemMonitor/meson.build | 4 ++++
f6a177
 2 files changed, 10 insertions(+)
f6a177
 create mode 100644 extensions/systemMonitor/classic.css
f6a177
f6a177
diff --git a/extensions/systemMonitor/classic.css b/extensions/systemMonitor/classic.css
f6a177
new file mode 100644
f6a177
index 0000000..946863d
f6a177
--- /dev/null
f6a177
+++ b/extensions/systemMonitor/classic.css
f6a177
@@ -0,0 +1,6 @@
f6a177
+@import url("stylesheet.css");
f6a177
+
f6a177
+.extension-systemMonitor-indicator-label {
f6a177
+    background-color: rgba(237,237,237,0.9);
f6a177
+    border: 1px solid #a1a1a1;
f6a177
+}
f6a177
diff --git a/extensions/systemMonitor/meson.build b/extensions/systemMonitor/meson.build
f6a177
index 48504f6..b6548b1 100644
f6a177
--- a/extensions/systemMonitor/meson.build
f6a177
+++ b/extensions/systemMonitor/meson.build
f6a177
@@ -1,5 +1,9 @@
f6a177
 extension_data += configure_file(
f6a177
   input: metadata_name + '.in',
f6a177
   output: metadata_name,
f6a177
   configuration: metadata_conf
f6a177
 )
f6a177
+
f6a177
+if classic_mode_enabled
f6a177
+  extension_data += files('classic.css')
f6a177
+endif
f6a177
-- 
f6a177
2.17.1
f6a177