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