|
1 | | -const St = imports.gi.St; |
2 | | -const PanelMenu = imports.ui.panelMenu; |
3 | | -const Main = imports.ui.main; |
4 | 1 | const Lang = imports.lang; |
5 | | -const GLib = imports.gi.GLib; |
6 | | -const Gio = imports.gi.Gio; |
| 2 | +const UPower = imports.gi.UPowerGlib; |
| 3 | +const BaseIndicator = imports.ui.status.power.Indicator; |
| 4 | +const ExtensionUtils = imports.misc.extensionUtils; |
| 5 | +const Panel = imports.ui.main.panel; |
7 | 6 | const Shell = imports.gi.Shell; |
| 7 | +const GObject = imports.gi.GObject; |
| 8 | +const GLib = imports.gi.GLib; |
| 9 | +const Config = imports.misc.config; |
| 10 | + |
8 | 11 |
|
9 | | -const Clutter = imports.gi.Clutter |
| 12 | +/** Settings |
| 13 | + */ |
10 | 14 |
|
| 15 | +const HISTORY_DEPTH = 5; |
| 16 | +const MEASURE_PERIOD = 1000; |
| 17 | +const FORCE_SYNC_PERIOD = 5000; |
| 18 | + |
| 19 | +const BAT_STATUS = "/sys/class/power_supply/BAT0/status"; |
11 | 20 | const POWER_NOW = "/sys/class/power_supply/BAT0/power_now"; |
12 | 21 |
|
13 | | -let meta; |
14 | | -let tp_wattmeter; |
15 | | -let label; |
16 | | -let interval; |
17 | 22 |
|
18 | | -var TPWattMeter = class TPWattMeter extends PanelMenu.Button { |
19 | | - constructor(meta) { |
| 23 | +/** Indicator |
| 24 | + */ |
| 25 | + |
| 26 | +var TPIndicator = class extends BaseIndicator { |
| 27 | + constructor() { |
20 | 28 | super(); |
21 | | - this.meta = meta; |
| 29 | + |
| 30 | + this.readings = []; |
| 31 | + this.last_value = 0.0; |
| 32 | + this.tm_measure = null; |
| 33 | + this.tm_force_sync = null; |
22 | 34 | } |
23 | | - _init() { |
24 | | - super._init(St.Align.START); |
25 | | - this.mainBox = null; |
26 | | - this.buttonText = new St.Label({ |
27 | | - text: _("?W"), |
28 | | - y_align: Clutter.ActorAlign.CENTER, |
29 | | - style_class: 'tp_wattmeter_lbl', |
30 | | - }); |
31 | | - this.actor.add_actor(this.buttonText); |
32 | | - this.powerWindows = []; |
33 | | - this.lastStatus = '?W'; |
| 35 | + |
| 36 | + _getBatteryStatus() { |
| 37 | + const pct = this._proxy.Percentage; |
| 38 | + const power = this.last_value.toFixed(1); |
| 39 | + const status = this._read_file(BAT_STATUS, '???'); |
| 40 | + |
| 41 | + let sign = ' '; |
| 42 | + if (status == 'Charging') { |
| 43 | + sign = '+'; |
| 44 | + } else if (status == 'Discharging') { |
| 45 | + sign = '-'; |
| 46 | + } |
| 47 | + |
| 48 | + return _("%s%% %s%sW").format(pct, sign, power); |
| 49 | + } |
| 50 | + |
| 51 | + _sync() { |
| 52 | + super._sync(); |
| 53 | + this._percentageLabel.clutter_text.set_text(this._getBatteryStatus()); |
| 54 | + return true; |
| 55 | + } |
| 56 | + |
| 57 | + _read_file(filePath, defaultValue) { |
| 58 | + try { |
| 59 | + return Shell.get_file_contents_utf8_sync(filePath).trim(); |
| 60 | + } catch (e) { |
| 61 | + log(`Cannot read file ${filePath}`, e); |
| 62 | + } |
| 63 | + return defaultValue; |
34 | 64 | } |
35 | 65 |
|
36 | 66 | _measure() { |
37 | | - const power = getPower(); |
38 | | - if (power < 0) { |
39 | | - this.powerWindows = []; |
40 | | - return true; |
| 67 | + const power = parseFloat(this._read_file(POWER_NOW), 0) / 1000000; |
| 68 | + this.readings.push(power) |
| 69 | + |
| 70 | + if (this.readings.length >= HISTORY_DEPTH) { |
| 71 | + let avg = this.readings.reduce((acc, elem) => acc + elem, 0.0) / this.readings.length; |
| 72 | + this.last_value = avg; |
| 73 | + |
| 74 | + while (this.readings.length) { this.readings.pop(); }; |
| 75 | + this.readings.push(avg); |
41 | 76 | } |
42 | | - this.powerWindows.push(power); |
43 | 77 | return true; |
44 | 78 | } |
45 | | - _refresh() { |
46 | | - let temp = this.buttonText; |
47 | | - let power_text = ''; |
48 | | - |
49 | | - if (this.powerWindows.length < 1) { |
50 | | - power_text = this.lastStatus != null ? this.lastStatus : 'N/A'; |
51 | | - } else { |
52 | | - let avg = this.powerWindows.reduce((acc, elem) => acc + elem, 0.0) / this.powerWindows.length; |
53 | | - while (this.powerWindows.length) { this.powerWindows.pop(); }; |
54 | | - this.powerWindows.push(avg); |
55 | | - |
56 | | - power_text = avg.toFixed(2) + 'W'; |
57 | | - } |
58 | 79 |
|
59 | | - temp.set_text(power_text); |
| 80 | + _force_sync() { |
| 81 | + this._sync(); |
60 | 82 | return true; |
61 | 83 | } |
62 | 84 |
|
63 | | - _enable() { |
64 | | - this.measure = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 250, |
| 85 | + _spawn() { |
| 86 | + this.tm_measure = GLib.timeout_add( |
| 87 | + GLib.PRIORITY_DEFAULT, |
| 88 | + MEASURE_PERIOD, |
65 | 89 | Lang.bind(this, this._measure)); |
66 | | - this.interval = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 5000, |
67 | | - Lang.bind(this, this._refresh)); |
| 90 | + this.tm_force_sync = GLib.timeout_add( |
| 91 | + GLib.PRIORITY_DEFAULT, |
| 92 | + FORCE_SYNC_PERIOD, |
| 93 | + Lang.bind(this, this._force_sync)); |
68 | 94 | } |
69 | 95 |
|
70 | | - _disable() { |
71 | | - GLib.source_remove(this.interval); |
72 | | - GLib.source_remove(this.measure); |
| 96 | + _stop() { |
| 97 | + GLib.source_remove(this.tm_measure); |
| 98 | + GLib.source_remove(this.tm_force_sync); |
73 | 99 | } |
74 | 100 | } |
75 | | -const GObject = imports.gi.GObject; |
76 | | -const Config = imports.misc.config; |
77 | | -let shellMinorVersion = parseInt(Config.PACKAGE_VERSION.split('.')[1]); |
78 | 101 |
|
79 | | -if (shellMinorVersion > 30) { |
80 | | - TPWattMeter = GObject.registerClass( |
81 | | - { GTypeName: 'TPWattMeter' }, |
82 | | - TPWattMeter |
83 | | - ); |
84 | | -} |
85 | 102 |
|
86 | | -function getPower() { |
87 | | - const power = parseFloat(readFileSafely(POWER_NOW), -1); |
88 | | - return power === -1 ? power : power / 1000000; |
89 | | -} |
| 103 | +/** Extension |
| 104 | + */ |
90 | 105 |
|
91 | | -function readFileSafely(filePath, defaultValue) { |
92 | | - try { |
93 | | - return Shell.get_file_contents_utf8_sync(filePath); |
94 | | - } catch (e) { |
95 | | - log(`Cannot read file ${filePath}`, e); |
96 | | - } |
97 | | - return defaultValue; |
98 | | -} |
99 | | -function checkFile(filename) { |
100 | | - //Checks for the existance of a file |
101 | | - if (GLib.file_test(filename, GLib.FileTest.EXISTS)) { |
102 | | - return true; |
| 106 | +class TPWattMeter { |
| 107 | + constructor() { |
| 108 | + this.customIndicator = new TPIndicator(); |
| 109 | + this.customIndicator._spawn(); |
| 110 | + |
| 111 | + this.aggregateMenu = Panel.statusArea['aggregateMenu']; |
| 112 | + this.originalIndicator = this.aggregateMenu._power; |
| 113 | + this.aggregateMenu._indicators.replace_child(this.originalIndicator.indicators, this.customIndicator.indicators); |
103 | 114 | } |
104 | | - else { |
105 | | - return false; |
| 115 | + |
| 116 | + destroy(arg) { |
| 117 | + this.customIndicator._stop(); |
| 118 | + this.aggregateMenu._indicators.replace_child(this.customIndicator.indicators, this.originalIndicator.indicators); |
| 119 | + this.customIndicator = null; |
106 | 120 | } |
107 | 121 | } |
108 | 122 |
|
109 | | -// Shell entry points |
110 | | -function init(metadata) { |
111 | | - meta = metadata; |
112 | | -} |
| 123 | + |
| 124 | +/** Init |
| 125 | + */ |
| 126 | + |
| 127 | +let tp_wattmeter; |
| 128 | + |
113 | 129 |
|
114 | 130 | function enable() { |
115 | | - tp_wattmeter = new TPWattMeter(meta); |
116 | | - tp_wattmeter._enable(); |
117 | | - Main.panel.addToStatusArea('tp_wattmeter', tp_wattmeter, -1); //, 'right'); |
| 131 | + tp_wattmeter = new TPWattMeter(); //tp_reader, tp_indicator); |
118 | 132 | } |
119 | 133 |
|
120 | 134 | function disable() { |
121 | | - tp_wattmeter._disable(); |
122 | 135 | tp_wattmeter.destroy(); |
123 | 136 | tp_wattmeter = null; |
124 | 137 | } |
0 commit comments