diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 24edbd7d..8b137891 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -patreon: stsdc + diff --git a/data/Application.css b/data/Application.css index 4a728fba..74f90a78 100644 --- a/data/Application.css +++ b/data/Application.css @@ -14,6 +14,33 @@ border-width: 0; } +/* .vertical-label, +.vertical-label:hover, +.vertical-label:selected, +.vertical-label:selected:focus, +.vertical-label:hover:selected { + +} */ + +.label-vertical { + +} + +.label-vertical-val { + color: alpha(@text_color, 1); + font-size: 30px; + font-weight: 100; + /* padding: 0 6px; + margin: 0 3px; */ + border-width: 0; +} + +.usage-label-container { + border: 1px solid @SILVER_300;; + border-radius: 3px; + background-color: alpha(@SILVER_100, 0.5); + } + .username-current { background-color: @SILVER_300; color: @SILVER_900; @@ -45,6 +72,35 @@ border-width: 0; } +.core_badge { + background-color: @SILVER_100; + border-radius: 8px; + padding-right: 4px; + padding-left:2px; + font-size: 10px; + /* font-weight:bold; */ + color: black; + border: 1px solid @SILVER_300; +} + +.core_badge-mild-warning { + background-color: @BANANA_100; + color: @BANANA_900; + border: 1px solid @BANANA_300; +} + +.core_badge-strong-warning { + background-color: @ORANGE_100; + color: @ORANGE_900; + border: 1px solid @ORANGE_300; +} + +.core_badge-critical-warning { + background-color: @STRAWBERRY_100; + color: @STRAWBERRY_700; + border: 1px solid @STRAWBERRY_300; +} + .command_wrapper { background-color: #fdf6e3; border-radius: 3px; @@ -59,10 +115,10 @@ font-family: monospace; } -.pid { +.small-text { color:grey; -font-weight:bold; -font-size:9px; + font-weight:bold; + font-size:9px; } .graph { @@ -93,3 +149,11 @@ font-size:9px; color: @SILVER_700; margin: 6px; } + +.bold { + font-weight: bold; +} + +.text-secondary { + color: @SILVER_700; +} \ No newline at end of file diff --git a/data/com.github.stsdc.monitor.appdata.xml.in b/data/com.github.stsdc.monitor.appdata.xml.in index bdf8725b..c2c49120 100644 --- a/data/com.github.stsdc.monitor.appdata.xml.in +++ b/data/com.github.stsdc.monitor.appdata.xml.in @@ -28,6 +28,15 @@ https://github.com/stsdc/monitor/issues + +​ +​
    +
  • Better System Tab
  • +
  • Update Portuguese translation (@rottenpants466)
  • +
  • Save last opened view (@ryonakano)
  • +
+​
+​
    diff --git a/data/com.github.stsdc.monitor.gschema.xml b/data/com.github.stsdc.monitor.gschema.xml index b7f8c63b..90fc778d 100644 --- a/data/com.github.stsdc.monitor.gschema.xml +++ b/data/com.github.stsdc.monitor.gschema.xml @@ -40,5 +40,10 @@ To start Monitor in background or not To start Monitor in background or not + + 'process_view' + Opened view + The last opened view + diff --git a/data/screenshots/monitor-system.png b/data/screenshots/monitor-system.png index da9946d8..65d77500 100644 Binary files a/data/screenshots/monitor-system.png and b/data/screenshots/monitor-system.png differ diff --git a/meson.build b/meson.build index 230091e3..fb04f056 100644 --- a/meson.build +++ b/meson.build @@ -1,4 +1,4 @@ -project('com.github.stsdc.monitor', 'vala', 'c', version: '0.8.1') +project('com.github.stsdc.monitor', 'vala', 'c', version: '0.9.0') # these are Meson modules gnome = import('gnome') @@ -67,14 +67,13 @@ executable( 'src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala', 'src/Views/SystemView/SystemView.vala', - 'src/Views/SystemView/SystemCPUChart.vala', 'src/Views/SystemView/SystemCPUView.vala', + 'src/Views/SystemView/SystemCPUInfoPopover.vala', 'src/Views/SystemView/SystemMemoryView.vala', + 'src/Views/SystemView/SystemNetworkView.vala', # Widgets related only to ProcessInfoView 'src/Views/ProcessView/ProcessInfoView/Preventor.vala', - 'src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala', - 'src/Views/ProcessView/ProcessInfoView/Chart.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala', 'src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala', @@ -84,7 +83,13 @@ executable( 'src/Widgets/Headerbar/Headerbar.vala', 'src/Widgets/Headerbar/Search.vala', 'src/Widgets/Statusbar/Statusbar.vala', - + 'src/Widgets/Labels/LabelVertical.vala', + 'src/Widgets/Labels/LabelRoundy.vala', + 'src/Widgets/Labels/LabelH4.vala', + 'src/Widgets/Chart/Chart.vala', + 'src/Widgets/Chart/ProcessChart.vala', + 'src/Widgets/Chart/NetworkChart.vala', + # Models 'src/Models/TreeViewModel.vala', @@ -106,6 +111,8 @@ executable( 'src/Resources/Core.vala', 'src/Resources/Memory.vala', 'src/Resources/Swap.vala', + 'src/Resources/TemperatureSensor.vala', + 'src/Resources/Network.vala', c_args: c_args, dependencies: [ glib, diff --git a/po/pt.po b/po/pt.po index daab273e..d02e8a09 100644 --- a/po/pt.po +++ b/po/pt.po @@ -9,14 +9,14 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2020-04-28 22:18+0400\n" -"PO-Revision-Date: 2019-11-04 11:58+0000\n" -"Last-Translator: Hugo Carvalho \n" +"PO-Revision-Date: 2020-08-16 14:07+0100\n" +"Last-Translator: André Barata \n" "Language-Team: \n" "Language: pt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.2.4\n" +"X-Generator: Poedit 2.4.1\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" #: src/Utils.vala:13 @@ -29,11 +29,11 @@ msgstr "" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala:34 #: src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala:35 msgid "N/A" -msgstr "" +msgstr "N/A" #: src/Utils.vala:45 msgid "B" -msgstr "" +msgstr "B" #: src/Utils.vala:50 #: src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala:113 @@ -55,19 +55,19 @@ msgstr "Fechar Monitor" #: src/Views/ProcessView/ProcessInfoView/OpenFilesListBox.vala:56 msgid "Deleted" -msgstr "" +msgstr "Apagado" #: src/Views/ProcessView/ProcessInfoView/Preventor.vala:21 msgid "Are you sure you want to do this?" -msgstr "" +msgstr "Tem a certeza que quer fazer isso?" #: src/Views/ProcessView/ProcessInfoView/Preventor.vala:24 msgid "Yes" -msgstr "" +msgstr "Sim" #: src/Views/ProcessView/ProcessInfoView/Preventor.vala:28 msgid "No" -msgstr "" +msgstr "Não" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala:39 #: src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala:59 @@ -76,36 +76,35 @@ msgstr "PID" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala:40 msgid "NI" -msgstr "" +msgstr "NI" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala:41 -#, fuzzy msgid "PRI" -msgstr "PID" +msgstr "PRI" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala:42 msgid "THR" -msgstr "" +msgstr "THR" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala:18 msgid "Opened files" -msgstr "" +msgstr "Ficheiros abertos" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala:22 msgid "Characters" -msgstr "" +msgstr "Caracteres" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala:27 msgid "System calls" -msgstr "" +msgstr "Chamadas de sistema" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala:32 msgid "Read/Written" -msgstr "" +msgstr "Ler/Escrita" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoIOStats.vala:37 msgid "Cancelled write" -msgstr "" +msgstr "Escrita cancelada" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala:79 msgid "End Process" @@ -125,11 +124,11 @@ msgstr "Matar processo selecionado" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala:96 msgid "Confirm kill of the process?" -msgstr "" +msgstr "Confirma matar o processo?" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala:103 msgid "Confirm end of the process?" -msgstr "" +msgstr "Confirma terminar o processo?" #. setup name column #: src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala:17 @@ -155,12 +154,12 @@ msgstr "GiB" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala:50 #, c-format msgid "CPU: %.1f%%" -msgstr "" +msgstr "CPU: %.1f%%" #: src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala:51 #, c-format msgid "RAM: %.1f%%" -msgstr "" +msgstr "RAM: %.1f%%" #: src/Widgets/Headerbar/Headerbar.vala:13 msgid "Monitor" @@ -188,7 +187,7 @@ msgstr "Escreva o nome do processo ou PID a pesquisar" #: src/Widgets/Statusbar/Statusbar.vala:14 msgid "Swap" -msgstr "" +msgstr "Trocar" #: src/Widgets/Statusbar/Statusbar.vala:16 #: src/Widgets/Statusbar/Statusbar.vala:20 @@ -198,7 +197,7 @@ msgstr "A calcular…" #: src/Widgets/Statusbar/Statusbar.vala:38 msgid "GHz" -msgstr "" +msgstr "GHz" #~ msgid "Monitor Indicator" #~ msgstr "Indicador do monitor" @@ -213,7 +212,7 @@ msgstr "" #~ msgstr "Ctrl+E" #~ msgid "CPU:" -#~ msgstr "CPU :" +#~ msgstr "CPU:" #~ msgid "Memory:" -#~ msgstr "Memória :" +#~ msgstr "Memória:" diff --git a/src/MainWindow.vala b/src/MainWindow.vala index 7adce5b4..f36441ac 100644 --- a/src/MainWindow.vala +++ b/src/MainWindow.vala @@ -10,6 +10,7 @@ public ProcessView process_view; public SystemView system_view; + private Gtk.Stack stack; private Statusbar statusbar; @@ -29,7 +30,7 @@ process_view = new ProcessView (); system_view = new SystemView (resources); - Gtk.Stack stack = new Gtk.Stack (); + stack = new Gtk.Stack (); stack.set_transition_type (Gtk.StackTransitionType.SLIDE_LEFT_RIGHT); stack.add_titled (process_view, "process_view", _("Processes")); stack.add_titled (system_view, "system_view", _("System")); @@ -48,6 +49,8 @@ main_box.pack_start (statusbar, false, true, 0); this.add (main_box); + show_all (); + dbusserver = DBusServer.get_default (); stack.notify["visible-child-name"].connect (() => { @@ -87,6 +90,8 @@ MonitorApp.settings.set_int ("position-y", position_y); MonitorApp.settings.set_boolean ("is-maximized", this.is_maximized); + MonitorApp.settings.set_string ("opened-view", stack.visible_child_name); + if (MonitorApp.settings.get_boolean ("indicator-state")) { this.hide_on_delete (); } else { @@ -98,6 +103,7 @@ }); dbusserver.indicator_state (MonitorApp.settings.get_boolean ("indicator-state")); + stack.visible_child_name = MonitorApp.settings.get_string ("opened-view"); } private void setup_window_state () { diff --git a/src/Resources/CPU.vala b/src/Resources/CPU.vala index df0ded16..8700a4f7 100644 --- a/src/Resources/CPU.vala +++ b/src/Resources/CPU.vala @@ -2,6 +2,17 @@ public class Monitor.CPU : Object { private float last_used; private float last_total; private float load; + private TemperatureSensor temperature_sensor; + + public string? model_name; + public string? model; + public string? family; + public string? microcode; + public string? cache_size; + public string? flags; + public string? bogomips; + public string? bugs; + public string? address_sizes; GTop.Cpu ? cpu; @@ -21,18 +32,31 @@ public class Monitor.CPU : Object { } } + public double temperature { + get { + return temperature_sensor.cpu / 1000; + } + } + construct { last_used = 0; last_total = 0; core_list = new Gee.ArrayList (); + model_name = get_cpu_info (); + + parse_cpuinfo (); debug ("Number of cores: %d", (int) get_num_processors ()); for (int i = 0; i < (int) get_num_processors (); i++) { var core = new Core(i); core_list.add (core); } + + // Temperature sensor shouldn't be created here since it + // will provides not only cpu temperature + temperature_sensor = new TemperatureSensor (); } public void update () { @@ -83,4 +107,86 @@ public class Monitor.CPU : Object { _frequency = (double)maxcur; } + + private void parse_cpuinfo () { + unowned GTop.SysInfo? info = GTop.glibtop_get_sysinfo (); + + if (info == null) { + warning ("No CPU info"); + return; + } + + // let core 0 represents whole processor + // TODO: parse all the values to corresponding core objects in core_list + // does it even makes sense?? + + unowned GLib.HashTable values = info.cpuinfo[0].values; + model = values["model"]; + family = values["cpu family"]; + microcode = values["microcode"]; + cache_size = values["cache size"]; + flags = values["flags"]; + bogomips = values["bogomips"]; + bugs = values["bugs"]; + address_sizes = values["address sizes"]; + } + + // straight from elementary about-plug + private string? get_cpu_info () { + unowned GTop.SysInfo? info = GTop.glibtop_get_sysinfo (); + + if (info == null) { + return null; + } + + var counts = new Gee.HashMap (); + const string[] KEYS = { "model name", "cpu", "Processor" }; + + for (int i = 0; i < info.ncpu; i++) { + unowned GLib.HashTable values = info.cpuinfo[i].values; + string? model = null; + foreach (var key in KEYS) { + model = values.lookup (key); + + if (model != null) { + break; + } + } + + string? core_count = values.lookup ("cpu cores"); + if (core_count != null) { + counts.@set (model, int.parse (core_count)); + continue; + } + + if (!counts.has_key (model)) { + counts.@set (model, 1); + } else { + counts.@set (model, counts.@get (model) + 1); + } + } + + if (counts.size == 0) { + return null; + } + + string result = ""; + foreach (var cpu in counts.entries) { + if (result.length > 0) { + result += "\n"; + } + + if (cpu.@value == 2) { + result += _("Dual-Core %s").printf ( (cpu.key)); + } else if (cpu.@value == 4) { + result += _("Quad-Core %s").printf ( (cpu.key)); + } else if (cpu.@value == 6) { + result += _("Hexa-Core %s").printf ( (cpu.key)); + } else { + result += "%u\u00D7 %s ".printf (cpu.@value, (cpu.key)); + } + } + + return Utils.Strings.beautify (result); + } } diff --git a/src/Resources/Network.vala b/src/Resources/Network.vala new file mode 100644 index 00000000..272f2978 --- /dev/null +++ b/src/Resources/Network.vala @@ -0,0 +1,86 @@ +/*- + * Copyright (c) 2020 Tudor Plugaru (https://github.com/PlugaruT/wingpanel-monitor) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * Authored by: Tudor Plugaru + */ + + +public class Monitor.Network : GLib.Object { + private int _bytes_in; + private int _bytes_in_old; + private bool control; + + private int _bytes_out; + private int _bytes_out_old; + + // flag first run + // bc first calculasion is wrong + private bool dumb_flag; + + public Network () { + _bytes_in = 0; + _bytes_in_old = 0; + _bytes_out = 0; + _bytes_out_old = 0; + control = false; + dumb_flag = true; + } + + public int[] get_bytes () { + if (control == false) { + control = true; + update_bytes_total (); + } else { + control = false; + } + int[] ret; + ret = {_bytes_out, _bytes_in}; + return ret; + } + + private void update_bytes_total () { + GTop.NetList netlist; + GTop.NetLoad netload; + + var devices = GTop.get_netlist (out netlist); + var n_bytes_out = 0; + var n_bytes_in = 0; + for (uint j = 0; j < netlist.number; ++j) { + var device = devices[j]; + if (device != "lo" && device.substring (0, 3) != "tun") { + GTop.get_netload (out netload, device); + + n_bytes_out += (int)netload.bytes_out; + n_bytes_in += (int)netload.bytes_in; + } + } + + var bout = (n_bytes_out - _bytes_out_old) / 1; + var bin = (n_bytes_in - _bytes_in_old) / 1; + + _bytes_out_old = n_bytes_out; + _bytes_in_old = n_bytes_in; + + if (!dumb_flag) { + _bytes_out = bout; + _bytes_in = bin; + } + dumb_flag = false; + + } + } diff --git a/src/Resources/Resources.vala b/src/Resources/Resources.vala index 1deef74c..04f2b898 100644 --- a/src/Resources/Resources.vala +++ b/src/Resources/Resources.vala @@ -2,11 +2,13 @@ public class Monitor.Resources : Object { public CPU cpu; public Memory memory; public Swap swap; + public Network network; construct { memory = new Memory (); cpu = new CPU (); swap = new Swap (); + network = new Network (); } public void update() { diff --git a/src/Resources/TemperatureSensor.vala b/src/Resources/TemperatureSensor.vala new file mode 100644 index 00000000..b64a8e20 --- /dev/null +++ b/src/Resources/TemperatureSensor.vala @@ -0,0 +1,81 @@ +class TemperatureSensor : Object { + private const string hwmon_path = "/sys/class/hwmon"; + + // contains list of paths to files with a temperature values + // Intel reports per core temperature, while AMD Ryzen Tdie + public Gee.ArrayList cpu_temp_paths; + + public double cpu { + get { + double total_temperature = 0; + foreach (var path in cpu_temp_paths) { + total_temperature += double.parse (open_file (path)); + } + return total_temperature / cpu_temp_paths.size; + } + } + + construct { + cpu_temp_paths = new Gee.ArrayList (); + traverser (); + } + + public TemperatureSensor() { + + } + + + private void traverser () { + Dir hwmon_dir = Dir.open (hwmon_path, 0); + + string ? hwmonx = null; + while ((hwmonx = hwmon_dir.read_name ()) != null) { + string hwmonx_name = Path.build_filename (hwmon_path, hwmonx, "name"); + string sensor_location = open_file (hwmonx_name); + + if (sensor_location == "coretemp" || sensor_location == "k10temp") { + debug ("Found temp. sensor: %s", sensor_location); + + Dir hwmonx_dir = Dir.open (Path.build_filename (hwmon_path, hwmonx), 0); + string ? hwmonx_prop = null; + while ((hwmonx_prop = hwmonx_dir.read_name ()) != null) { + // debug (open_file (hwmonx_name)); + + if (hwmonx_prop.contains ("temp")) { + // AMD stuff + // Tdie contains true temperature value, while Tctl contains value for fans + // Tctl = Tdie + offset in some processors + if ("Tdie" == open_file (Path.build_filename (hwmon_path, hwmonx, hwmonx_prop))) { + string tempx_input = "temp%c_input".printf(hwmonx_prop[4]); + cpu_temp_paths.add (Path.build_filename (hwmon_path, hwmonx, tempx_input)); + + debug (open_file (cpu_temp_paths[0])); + + // Intel stuff + // Intel reports per core + } else if (open_file (Path.build_filename (hwmon_path, hwmonx, hwmonx_prop)).contains ("Core")) { + string tempx_input = "temp%c_input".printf(hwmonx_prop[4]); + cpu_temp_paths.add (Path.build_filename (hwmon_path, hwmonx, tempx_input)); + debug (open_file (cpu_temp_paths[0])); + } + } + } + } else if (sensor_location == "amdgpu" ) { + debug ("Found temp. sensor: %s", sensor_location); + } else { + debug ("Found temp. sensor: %s", sensor_location); + } + } + } + + private string open_file (string filename) { + try { + string read; + FileUtils.get_contents (filename, out read); + return read.replace ("\n",""); + } catch (FileError e) { + error ("%s\n", e.message); + return "0"; + } + } +} \ No newline at end of file diff --git a/src/Utils.vala b/src/Utils.vala index 4d020acf..628dbaf9 100644 --- a/src/Utils.vala +++ b/src/Utils.vala @@ -1,54 +1,88 @@ namespace Monitor.Utils { - const string NOT_AVAILABLE = (_("N/A")); + const string NOT_AVAILABLE = (_ ("N/A")); const string NO_DATA = "\u2014"; } +public class Monitor.Utils.Strings { + // straight from elementary about-plug + + struct GraphicsReplaceStrings { + string regex; + string replacement; + } + + public static string beautify (string info) { + string pretty = GLib.Markup.escape_text (info).strip (); + + + const GraphicsReplaceStrings REPLACE_STRINGS[] = { + // { "Mesa DRI ", ""}, + { "[(]R[)]", "®"}, + { "[(]TM[)]", "™"}, + // { "Gallium .* on (AMD .*)", "\\1"}, + // { "(AMD .*) [(].*", "\\1"}, + // { "(AMD [A-Z])(.*)", "\\1\\L\\2\\E"}, + // { "Graphics Controller", "Graphics"}, + }; + + try { + foreach (GraphicsReplaceStrings replace_string in REPLACE_STRINGS) { + GLib.Regex re = new GLib.Regex (replace_string.regex, 0, 0); + pretty = re.replace (pretty, -1, 0, replace_string.replacement, 0); + } + } catch (Error e) { + critical ("Couldn't cleanup vendor string: %s", e.message); + } + + return pretty; + } +} + +/** + * Static helper class for unit formatting + * Author: Laurent Callarec @lcallarec + */ +public class Monitor.Utils.HumanUnitFormatter { + const string[] SIZE_UNITS = {"B", "KiB", "MiB", "GiB", "TiB"}; + const double KFACTOR = 1024; + /** - * Static helper class for unit formatting - * Author: Laurent Callarec @lcallarec + * format a string of bytes to an human readable format with units */ - public class Monitor.Utils.HumanUnitFormatter { - - const string[] SIZE_UNITS = {"B", "KiB", "MiB", "GiB", "TiB"}; - const double KFACTOR = 1024; - - /** - * format a string of bytes to an human readable format with units - */ - public static string string_bytes_to_human(string bytes) { - double current_size = double.parse(bytes); - string current_size_formatted = bytes.to_string() + HumanUnitFormatter.SIZE_UNITS[0]; - - for (int i = 0; i<= HumanUnitFormatter.SIZE_UNITS.length; i++) { - if (current_size < HumanUnitFormatter.KFACTOR) { - return GLib.Math.round(current_size).to_string() + HumanUnitFormatter.SIZE_UNITS[i]; - } - current_size = current_size / HumanUnitFormatter.KFACTOR; - } - - return current_size_formatted; - } - - public static string double_bytes_to_human(double bytes) { - string units = _ ("B"); - - // convert to MiB if needed - if (bytes > 1024.0) { - bytes /= 1024.0; - units = _ ("KiB"); - } - - // convert to GiB if needed - if (bytes > 1024.0) { - bytes /= 1024.0; - units = _ ("MiB"); - } + public static string string_bytes_to_human (string bytes) { + double current_size = double.parse (bytes); + string current_size_formatted = bytes.to_string () + HumanUnitFormatter.SIZE_UNITS[0]; - if (bytes > 1024.0) { - bytes /= 1024.0; - units = _ ("GiB"); + for (int i = 0; i<= HumanUnitFormatter.SIZE_UNITS.length; i++) { + if (current_size < HumanUnitFormatter.KFACTOR) { + return GLib.Math.round (current_size).to_string () + HumanUnitFormatter.SIZE_UNITS[i]; } + current_size = current_size / HumanUnitFormatter.KFACTOR; + } + + return current_size_formatted; + } + + public static string double_bytes_to_human (double bytes) { + string units = _ ("B"); - return "%.1f %s".printf (bytes, units); - } - } + // convert to MiB if needed + if (bytes > 1024.0) { + bytes /= 1024.0; + units = _ ("KiB"); + } + + // convert to GiB if needed + if (bytes > 1024.0) { + bytes /= 1024.0; + units = _ ("MiB"); + } + + if (bytes > 1024.0) { + bytes /= 1024.0; + units = _ ("GiB"); + } + + return "%.1f %s".printf (bytes, units); + } +} diff --git a/src/Views/ProcessView/ProcessInfoView/Preventor.vala b/src/Views/ProcessView/ProcessInfoView/Preventor.vala index f09f5673..df5e80bc 100644 --- a/src/Views/ProcessView/ProcessInfoView/Preventor.vala +++ b/src/Views/ProcessView/ProcessInfoView/Preventor.vala @@ -5,7 +5,7 @@ public class Monitor.Preventor : Gtk.Stack { private Gtk.Button confirm_button; private Gtk.Button deny_button; - private Gtk.Widget child; + private Gtk.Widget child_widget; public signal void confirmed (bool is_confirmed); @@ -33,19 +33,19 @@ public class Monitor.Preventor : Gtk.Stack { } public Preventor (Gtk.Widget _child, string name) { - child = _child; - add_named (child, name); + child_widget = _child; + add_named (child_widget, name); add_named (preventive_action_bar, "preventive_action_bar"); deny_button.clicked.connect (() => { set_transition_type(Gtk.StackTransitionType.SLIDE_UP); - set_visible_child (child); + set_visible_child (child_widget); confirmed(false); }); confirm_button.clicked.connect(() => { set_transition_type(Gtk.StackTransitionType.SLIDE_UP); - set_visible_child (child); + set_visible_child (child_widget); confirmed(true); }); } diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala index 70ca1541..755c321c 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoCPURAM.vala @@ -2,8 +2,8 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { private Gtk.Label cpu_label; private Gtk.Label ram_label; - private Chart cpu_chart; - private Chart ram_chart; + private ProcessChart cpu_chart; + private ProcessChart ram_chart; construct { column_spacing = 6; @@ -12,8 +12,8 @@ public class Monitor.ProcessInfoCPURAM : Gtk.Grid { column_homogeneous = true; row_homogeneous = false; - cpu_chart = new Chart (); - ram_chart = new Chart (); + cpu_chart = new ProcessChart (); + ram_chart = new ProcessChart (); var cpu_graph_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala index aa072fbf..1704d346 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoHeader.vala @@ -2,13 +2,13 @@ public class Monitor.ProcessInfoHeader : Gtk.Grid { private Gtk.Image icon; public Gtk.Label state; public Gtk.Label application_name; - public RoundyLabel pid; - public RoundyLabel ppid; - public RoundyLabel pgrp; - public RoundyLabel nice; - public RoundyLabel priority; - public RoundyLabel num_threads; - public RoundyLabel username; + public LabelRoundy pid; + public LabelRoundy ppid; + public LabelRoundy pgrp; + public LabelRoundy nice; + public LabelRoundy priority; + public LabelRoundy num_threads; + public LabelRoundy username; private Regex ? regex; @@ -36,15 +36,15 @@ public class Monitor.ProcessInfoHeader : Gtk.Grid { application_name.halign = Gtk.Align.START; application_name.valign = Gtk.Align.START; - pid = new RoundyLabel (_ ("PID")); - nice = new RoundyLabel (_ ("NI")); - priority = new RoundyLabel (_ ("PRI")); - num_threads = new RoundyLabel (_ ("THR")); - // ppid = new RoundyLabel (_("PPID")); - // pgrp = new RoundyLabel (_("PGRP")); + pid = new LabelRoundy (_ ("PID")); + nice = new LabelRoundy (_ ("NI")); + priority = new LabelRoundy (_ ("PRI")); + num_threads = new LabelRoundy (_ ("THR")); + // ppid = new LabelRoundy (_("PPID")); + // pgrp = new LabelRoundy (_("PGRP")); // TODO: tooltip_text UID - username = new RoundyLabel (""); + username = new LabelRoundy (""); var wrapper = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); wrapper.add (pid); diff --git a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala index 26929c1f..c0163bd7 100644 --- a/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala +++ b/src/Views/ProcessView/ProcessInfoView/ProcessInfoView.vala @@ -22,7 +22,6 @@ public class Monitor.ProcessInfoView : Gtk.Box { } } public string ? icon_name; - private Gtk.ScrolledWindow command_wrapper; private Gtk.InfoBar permission_error_infobar; private Gtk.Label permission_error_label; @@ -31,15 +30,9 @@ public class Monitor.ProcessInfoView : Gtk.Box { private ProcessInfoIOStats process_info_io_stats; private ProcessInfoCPURAM process_info_cpu_ram; - - private Regex ? regex; - private Gtk.Grid grid; - private Gtk.Button end_process_button; private Gtk.Button kill_process_button; - private Preventor preventor; - public ProcessInfoView () { orientation = Gtk.Orientation.VERTICAL; hexpand = true; diff --git a/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala b/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala index 149c910f..31ae9d01 100644 --- a/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala +++ b/src/Views/ProcessView/ProcessTreeView/CPUProcessTreeView.vala @@ -82,12 +82,12 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { try { Gdk.Pixbuf icon = new Gdk.Pixbuf.from_file_at_size (path, 16, -1); - (icon_cell as Gtk.CellRendererPixbuf).pixbuf = icon; + ((Gtk.CellRendererPixbuf)icon_cell).pixbuf = icon; } catch (Error e) { warning (e.message); } } else { - (icon_cell as Gtk.CellRendererPixbuf).icon_name = path; + ((Gtk.CellRendererPixbuf)icon_cell).icon_name = path; } } @@ -99,9 +99,9 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { // format the double into a string if (cpu_usage < 0.0) - (cell as Gtk.CellRendererText).text = Utils.NO_DATA; + ((Gtk.CellRendererText)cell).text = Utils.NO_DATA; else - (cell as Gtk.CellRendererText).text = "%.0f%%".printf (cpu_usage); + ((Gtk.CellRendererText)cell).text = "%.0f%%".printf (cpu_usage); } public void memory_usage_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { @@ -126,9 +126,9 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { // format the double into a string if (memory_usage == 0) - (cell as Gtk.CellRendererText).text = Utils.NO_DATA; + ((Gtk.CellRendererText)cell).text = Utils.NO_DATA; else - (cell as Gtk.CellRendererText).text = "%.1f %s".printf (memory_usage_double, units); + ((Gtk.CellRendererText)cell).text = "%.1f %s".printf (memory_usage_double, units); } private void pid_cell_layout (Gtk.CellLayout cell_layout, Gtk.CellRenderer cell, Gtk.TreeModel model, Gtk.TreeIter iter) { @@ -137,7 +137,7 @@ public class Monitor.CPUProcessTreeView : Gtk.TreeView { int pid = pid_value.get_int (); // format the double into a string if (pid == 0) { - (cell as Gtk.CellRendererText).text = Utils.NO_DATA; + ((Gtk.CellRendererText)cell).text = Utils.NO_DATA; } } diff --git a/src/Views/SystemView/SystemCPUInfoPopover.vala b/src/Views/SystemView/SystemCPUInfoPopover.vala new file mode 100644 index 00000000..3fa74028 --- /dev/null +++ b/src/Views/SystemView/SystemCPUInfoPopover.vala @@ -0,0 +1,54 @@ +public class Monitor.SystemCPUInfoPopover : Gtk.Popover { + private Gtk.Grid grid; + + private CPU cpu; + + construct { + grid = new Gtk.Grid (); + grid.margin = 12; + grid.column_spacing = 6; + + grid.attach (label(_("Model")), 0, 0, 1, 1); + grid.attach (label(_("Family")), 0, 1, 1, 1); + grid.attach (label(_("Microcode ver.")), 0, 2, 1, 1); + grid.attach (label(_("Bogomips")), 0, 3, 1, 1); + grid.attach (label(_("Cache size")), 0, 4, 1, 1); + grid.attach (label(_("Address sizes")), 0, 5, 1, 1); + grid.attach (label(_("Flags")), 0, 6, 1, 1); + grid.attach (label(_("Bugs")), 0, 7, 1, 1); + + for (int i; i <= 7; i++) { + grid.attach ( label (":"), 1, i, 1, 1); + } + + add (grid); + } + + + public SystemCPUInfoPopover(Gtk.ToggleButton? relative_to, CPU _cpu) { + Object (relative_to : relative_to); + + closed.connect (() => { relative_to.set_active(false); }); + + cpu = _cpu; + + grid.attach (label(cpu.model), 2, 0, 1, 1); + grid.attach (label(cpu.family), 2, 1, 1, 1); + grid.attach (label(cpu.microcode), 2, 2, 1, 1); + grid.attach (label(cpu.bogomips), 2, 3, 1, 1); + grid.attach (label(cpu.cache_size), 2, 4, 1, 1); + grid.attach (label(cpu.address_sizes), 2, 5, 1, 1); + grid.attach (label(cpu.flags), 2, 6, 1, 1); + grid.attach (label(cpu.bugs), 2, 7, 1, 1); + } + + private Gtk.Label label(string text) { + var label = new Gtk.Label (text); + label.halign = Gtk.Align.START; + label.valign = Gtk.Align.START; + label.wrap = true; + label.max_width_chars = 80; + + return label; + } +} \ No newline at end of file diff --git a/src/Views/SystemView/SystemCPUView.vala b/src/Views/SystemView/SystemCPUView.vala index 7914ffad..4187c1f4 100644 --- a/src/Views/SystemView/SystemCPUView.vala +++ b/src/Views/SystemView/SystemCPUView.vala @@ -1,15 +1,25 @@ -public class Monitor.SystemCPUView : Gtk.Grid { - private SystemCPUChart cpu_chart; +public class Monitor.SystemCPUView : Gtk.Box { + private Chart cpu_utilization_chart; + private Chart cpu_frequency_chart; + private Chart cpu_temperature_chart; private CPU cpu; - private Gtk.Label cpu_percentage_label; + private LabelVertical cpu_percentage_label; + private LabelRoundy cpu_frequency_label; + private LabelRoundy cpu_temperature_label; + private LabelH4 processor_name_label; + + private Gtk.Button view_threads_usage_button; + + private Gtk.Revealer cpu_threads_revealer; private Gee.ArrayList core_label_list; construct { margin = 12; - column_spacing = 12; + margin_top = 6; set_vexpand (false); + orientation = Gtk.Orientation.VERTICAL; core_label_list = new Gee.ArrayList (); } @@ -19,52 +29,178 @@ public class Monitor.SystemCPUView : Gtk.Grid { public SystemCPUView(CPU _cpu) { cpu = _cpu; - cpu_percentage_label = new Gtk.Label (_("CPU: ") + Utils.NO_DATA); - cpu_percentage_label.get_style_context ().add_class ("h2"); - cpu_percentage_label.valign = Gtk.Align.START; - cpu_percentage_label.halign = Gtk.Align.START; - cpu_percentage_label.margin_start = 6; + cpu_percentage_label = new LabelVertical (_("UTILIZATION")); + cpu_percentage_label.has_tooltip = true; + cpu_percentage_label.tooltip_text = (_("Show detailed info")); + + cpu_frequency_label = new LabelRoundy (_("FREQUENCY")); + cpu_frequency_label.margin = 6; + cpu_frequency_label.margin_top = 2; + + cpu_temperature_label = new LabelRoundy (_("TEMPERATURE")); + cpu_temperature_label.margin = 6; + cpu_temperature_label.margin_top = 2; + + processor_name_label = new LabelH4 (cpu.model_name); + + var processor_info_button = new Gtk.ToggleButton (); + processor_info_button.get_style_context ().add_class ("circular"); + // processor_info_button.get_style_context ().add_class ("popup"); + processor_info_button.has_focus = false; + var icon = new Gtk.Image (); + icon.gicon = new ThemedIcon ("dialog-information"); + icon.pixel_size = 16; + processor_info_button.set_image (icon); + processor_info_button.valign = Gtk.Align.START; + processor_info_button.halign = Gtk.Align.START; + + + var title_grid = new Gtk.Grid (); + title_grid.attach (processor_name_label, 0, 0, 1, 1); + title_grid.attach (processor_info_button, 1, 0, 1, 1); + title_grid.column_spacing = 6; + + var popover = new SystemCPUInfoPopover (processor_info_button, cpu); + + processor_info_button.clicked.connect(() => { popover.show_all(); }); + + cpu_utilization_chart = new Chart (cpu.core_list.size); + + var grid_utilization_info = new Gtk.Grid (); + grid_utilization_info.attach (grid_usage_labels(), 0, 0, 1, 1); + grid_utilization_info.attach (cpu_utilization_chart, 0, 0, 1, 1); - cpu_chart = new SystemCPUChart (cpu.core_list.size); - attach (grid_core_labels (), 0, 0, 1); - attach (cpu_percentage_label, 1, 0, 1, 1); - attach (cpu_chart, 1, 0, 1, 2); + cpu_frequency_chart = new Chart (1); + cpu_frequency_chart.height_request = -1; + cpu_frequency_chart.config.y_axis.fixed_max = 5.0; + cpu_temperature_chart = new Chart (1); + cpu_temperature_chart.height_request = -1; + + var grid_frequency_info = new Gtk.Grid (); + grid_frequency_info.attach (cpu_frequency_label, 0, 0, 1, 1); + grid_frequency_info.attach (cpu_frequency_chart, 0, 0, 1, 1); + + var grid_temperature_info = new Gtk.Grid (); + grid_temperature_info.attach (cpu_temperature_label, 0, 0, 1, 1); + grid_temperature_info.attach (cpu_temperature_chart, 0, 0, 1, 1); + + + cpu_percentage_label.clicked.connect(() => { + cpu_threads_revealer.reveal_child = !(cpu_threads_revealer.child_revealed); + + if (cpu_threads_revealer.child_revealed) { + cpu_percentage_label.tooltip_text = (_("Show detailed info")); + } else { + cpu_percentage_label.tooltip_text = (_("Hide detailed info")); + } + }); + + var smol_charts_container = new Gtk.Grid (); + smol_charts_container.width_request = 200; + smol_charts_container.hexpand = false; + smol_charts_container.halign = Gtk.Align.START; + smol_charts_container.attach (grid_frequency_info, 0, 0, 1, 1); + smol_charts_container.attach (grid_temperature_info, 0, 1, 1, 1); + smol_charts_container.row_spacing = 6; + smol_charts_container.margin_left = 6; + + // Thanks Goncalo + var charts_container = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); + charts_container.pack_start (grid_utilization_info, true, true, 0); + charts_container.pack_start(smol_charts_container, false, false, 0); + + add (title_grid); + add (charts_container); } public void update () { + cpu_frequency_chart.update (0, cpu.frequency); + cpu_temperature_chart.update (0, cpu.temperature); + for (int i = 0; i < cpu.core_list.size; i++) { double core_percentage = cpu.core_list[i].percentage_used; - cpu_chart.update(i, core_percentage); + cpu_utilization_chart.update(i, core_percentage); string percentage_formatted = ("% 3d%%").printf ( (int)core_percentage); - core_label_list[i].set_text (_("Thread %d: %s").printf (i, percentage_formatted)); + core_label_list[i].set_text (percentage_formatted); + + core_label_list[i].get_style_context ().remove_class ("core_badge-mild-warning"); + core_label_list[i].get_style_context ().remove_class ("core_badge-strong-warning"); + core_label_list[i].get_style_context ().remove_class ("core_badge-critical-warning"); + + + if (core_percentage > 75.0) { + core_label_list[i].get_style_context ().add_class ("core_badge-mild-warning"); + core_label_list[i].get_style_context ().remove_class ("core_badge-strong-warning"); + core_label_list[i].get_style_context ().remove_class ("core_badge-critical-warning"); + } + if (core_percentage > 85.0) { + core_label_list[i].get_style_context ().add_class ("core_badge-strong-warning"); + core_label_list[i].get_style_context ().remove_class ("core_badge-mild-warning"); + core_label_list[i].get_style_context ().remove_class ("core_badge-critical-warning"); + } + + if (core_percentage > 90.0) { + core_label_list[i].get_style_context ().add_class ("core_badge-critical-warning"); + core_label_list[i].get_style_context ().remove_class ("core_badge-mild-warning"); + core_label_list[i].get_style_context ().remove_class ("core_badge-strong-warning"); + } } - cpu_percentage_label.set_text ((_("CPU: % 3d%%")).printf (cpu.percentage)); + cpu_percentage_label.set_text ((_("%d%%")).printf (cpu.percentage)); + cpu_frequency_label.set_text (("%.2f %s").printf (cpu.frequency, _ ("GHz"))); + cpu_temperature_label.set_text (("%.2f %s").printf (cpu.temperature, _ ("℃"))); + } + + private Gtk.Grid grid_usage_labels () { + + Gtk.Grid grid = new Gtk.Grid (); + grid.column_spacing = 6; + grid.margin = 6; + grid.valign = Gtk.Align.START; + grid.halign = Gtk.Align.START; + grid.get_style_context ().add_class ("usage-label-container"); + + grid.attach(cpu_percentage_label, 0, 0, 1, 1); + grid.attach(grid_core_labels(), 1, 0, 1, 1); + + return grid; } - private Gtk.Grid grid_core_labels () { + private Gtk.Revealer grid_core_labels () { + cpu_threads_revealer = new Gtk.Revealer(); + cpu_threads_revealer.margin = 6; + cpu_threads_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_LEFT; + cpu_threads_revealer.valign = Gtk.Align.CENTER; + Gtk.Grid grid = new Gtk.Grid (); - grid.column_spacing = 12; - grid.width_request = 300; + grid.column_spacing = 8; + grid.row_spacing = 4; int column = 0; int row = 0; for (int i = 0; i < cpu.core_list.size; i++) { - var core_label = new Gtk.Label(_("Thread %d: ").printf (i) + Utils.NO_DATA); - core_label.halign = Gtk.Align.START; + var core_label = new Gtk.Label (Utils.NO_DATA); + core_label.set_width_chars (4); + core_label.get_style_context ().add_class ("core_badge"); + // core_label.set_text (Utils.NO_DATA); core_label_list.add (core_label); grid.attach(core_label, column, row, 1, 1); - column++; - if (column > 1) { - row++; - column = 0; + row++; + if (row > 1) { + column++; + row = 0; } } + cpu_threads_revealer.add (grid); - return grid; + var threads_label = new Gtk.Label ("THREADS"); + threads_label.get_style_context ().add_class ("small-text"); + grid.attach(threads_label, 0, -1, column, 1); + + return cpu_threads_revealer; } } \ No newline at end of file diff --git a/src/Views/SystemView/SystemMemoryView.vala b/src/Views/SystemView/SystemMemoryView.vala index 16cd0a72..8c08ad94 100644 --- a/src/Views/SystemView/SystemMemoryView.vala +++ b/src/Views/SystemView/SystemMemoryView.vala @@ -1,14 +1,16 @@ public class Monitor.SystemMemoryView : Gtk.Grid { - private SystemCPUChart memory_chart; + private Chart memory_chart; private Memory memory; - private Gtk.Label memory_percentage_label; + private LabelH4 memory_name_label; + private LabelVertical memory_percentage_label; private Gtk.Label memory_shared_label; private Gtk.Label memory_buffered_label; private Gtk.Label memory_cached_label; private Gtk.Label memory_locked_label; private Gtk.Label memory_total_label; private Gtk.Label memory_used_label; + private Gtk.Revealer memory_usage_revealer; construct { margin = 12; @@ -21,11 +23,20 @@ public class Monitor.SystemMemoryView : Gtk.Grid { public SystemMemoryView(Memory _memory) { memory = _memory; - memory_percentage_label = new Gtk.Label (_("Memory: ") + Utils.NO_DATA); - memory_percentage_label.get_style_context ().add_class ("h2"); - memory_percentage_label.halign = Gtk.Align.START; - memory_percentage_label.valign = Gtk.Align.START; - memory_percentage_label.margin_start = 6; + memory_name_label = new LabelH4 (_("Memory")); + + memory_percentage_label = new LabelVertical (_("UTILIZATION")); + memory_percentage_label.has_tooltip = true; + memory_percentage_label.tooltip_text = (_("Show detailed info")); + + memory_percentage_label.clicked.connect(() => { + memory_usage_revealer.reveal_child = !(memory_usage_revealer.child_revealed); + if (memory_usage_revealer.child_revealed) { + memory_percentage_label.tooltip_text = (_("Show detailed info")); + } else { + memory_percentage_label.tooltip_text = (_("Hide detailed info")); + } + }); memory_total_label = new Gtk.Label (_("Total: ") + Utils.NO_DATA); memory_total_label.halign = Gtk.Align.START; @@ -45,15 +56,29 @@ public class Monitor.SystemMemoryView : Gtk.Grid { memory_locked_label = new Gtk.Label (_("Locked: ") + Utils.NO_DATA); memory_locked_label.halign = Gtk.Align.START; - memory_chart = new SystemCPUChart (1); + memory_chart = new Chart (1); + + var lil_gridy = new Gtk.Grid (); + lil_gridy.margin = 6; + lil_gridy.column_spacing = 6; + lil_gridy.valign = Gtk.Align.START; + lil_gridy.halign = Gtk.Align.START; + lil_gridy.get_style_context ().add_class ("usage-label-container"); + lil_gridy.attach (memory_percentage_label, 0, 0, 1, 1); + lil_gridy.attach (memory_usage_grid (), 1, 0, 1, 1); - attach (memory_percentage_label, 1, 0, 1, 1); - attach (memory_usage_grid (), 0, 0, 1); - attach (memory_chart, 1, 0, 1, 2); + attach (memory_name_label, 0, 0, 1, 1); + attach (lil_gridy, 0, 1, 1, 1); + attach (memory_chart, 0, 1, 2, 2); } - private Gtk.Grid memory_usage_grid () { + private Gtk.Revealer memory_usage_grid () { + memory_usage_revealer = new Gtk.Revealer(); + memory_usage_revealer.margin = 6; + memory_usage_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_LEFT; + memory_usage_revealer.valign = Gtk.Align.CENTER; + Gtk.Grid grid = new Gtk.Grid (); grid.column_spacing = 12; grid.width_request = 300; @@ -65,12 +90,14 @@ public class Monitor.SystemMemoryView : Gtk.Grid { grid.attach (memory_cached_label, 0, 2, 1, 1); grid.attach (memory_locked_label, 1, 2, 1, 1); - return grid; + memory_usage_revealer.add (grid); + + return memory_usage_revealer; } public void update () { - memory_percentage_label.set_text ((_("Memory: % 3d%%")).printf (memory.percentage)); + memory_percentage_label.set_text ((_("%d%%")).printf (memory.percentage)); memory_chart.update (0, memory.percentage); memory_total_label.set_text ((_("Total: %s")).printf (Utils.HumanUnitFormatter.double_bytes_to_human(memory.total))); diff --git a/src/Views/SystemView/SystemNetworkView.vala b/src/Views/SystemView/SystemNetworkView.vala new file mode 100644 index 00000000..a89a3f86 --- /dev/null +++ b/src/Views/SystemView/SystemNetworkView.vala @@ -0,0 +1,48 @@ +public class Monitor.SystemNetworkView : Gtk.Grid { + private NetworkChart network_chart; + private Network network; + + private LabelH4 network_name_label; + private LabelRoundy network_upload_label; + private LabelRoundy network_download_label; + + construct { + margin = 12; + column_spacing = 12; + set_vexpand (false); + } + + public SystemNetworkView (Network _network) { + network = _network; + + network_name_label = new LabelH4 (_ ("Network")); + network_download_label = new LabelRoundy (_ ("DOWN")); + network_download_label.val.set_width_chars (7); + network_upload_label = new LabelRoundy (_ ("UP")); + network_upload_label.val.set_width_chars (7); + + network_chart = new NetworkChart (2); + + var labels_grid = new Gtk.Grid (); + labels_grid.row_spacing = 6; + labels_grid.column_spacing = 6; + labels_grid.margin = 6; + labels_grid.attach (network_download_label, 0, 0, 1, 1); + labels_grid.attach (network_upload_label, 1, 0, 1, 1); + + attach (network_name_label, 0, 0, 1, 1); + attach (labels_grid, 0, 1, 2, 2); + attach (network_chart, 0, 1, 2, 2); + } + + public void update () { + double up_bytes = network.get_bytes ()[0] / 2; + double down_bytes = network.get_bytes ()[1] / 2; + if (up_bytes >= 0 && down_bytes >= 0) { + network_download_label.set_text (("%s/s").printf (Utils.HumanUnitFormatter.string_bytes_to_human (down_bytes.to_string ()))); + network_upload_label.set_text (("%s/s").printf (Utils.HumanUnitFormatter.string_bytes_to_human (up_bytes.to_string ()))); + network_chart.update (0, up_bytes); + network_chart.update (1, down_bytes); + } + } +} \ No newline at end of file diff --git a/src/Views/SystemView/SystemView.vala b/src/Views/SystemView/SystemView.vala index 162d5467..c1dc8bee 100644 --- a/src/Views/SystemView/SystemView.vala +++ b/src/Views/SystemView/SystemView.vala @@ -3,6 +3,7 @@ public class Monitor.SystemView : Gtk.Box { private SystemCPUView cpu_view; private SystemMemoryView memory_view; + private SystemNetworkView network_view; construct { orientation = Gtk.Orientation.VERTICAL; @@ -14,13 +15,16 @@ public class Monitor.SystemView : Gtk.Box { cpu_view = new SystemCPUView (resources.cpu); memory_view = new SystemMemoryView (resources.memory); + network_view = new SystemNetworkView (resources.network); add (cpu_view); add (memory_view); + add (network_view); } public void update () { cpu_view.update(); memory_view.update(); + network_view.update (); } } \ No newline at end of file diff --git a/src/Views/SystemView/SystemCPUChart.vala b/src/Widgets/Chart/Chart.vala similarity index 50% rename from src/Views/SystemView/SystemCPUChart.vala rename to src/Widgets/Chart/Chart.vala index 492112c6..dfd85ec8 100644 --- a/src/Views/SystemView/SystemCPUChart.vala +++ b/src/Widgets/Chart/Chart.vala @@ -1,13 +1,8 @@ -public class Monitor.SystemCPUChart : Gtk.Box { - private LiveChart.Chart chart; - private LiveChart.Config config; - - // private Gee.ArrayList serie_list; - +public class Monitor.Chart : Gtk.Box { + private LiveChart.Chart live_chart; + public LiveChart.Config config; construct { - // serie_list = new Gee.ArrayList (); - get_style_context ().add_class ("graph"); vexpand = true; @@ -28,43 +23,43 @@ public class Monitor.SystemCPUChart : Gtk.Box { left = -1 }; - chart = new LiveChart.Chart (config); - chart.expand = true; - chart.legend.visible = false; - chart.grid.visible = true; - chart.background.main_color = Gdk.RGBA () { + live_chart = new LiveChart.Chart (config); + live_chart.expand = true; + live_chart.legend.visible = false; + live_chart.grid.visible = true; + live_chart.background.main_color = Gdk.RGBA () { red= 1, green= 1, blue= 1, alpha= 1 }; //White background - } - public SystemCPUChart (int cores_quantity) { - for (int i = 0; i < cores_quantity; i++) { + public Chart (int series_quantity) { + for (int i = 0; i < series_quantity; i++) { var renderer = new LiveChart.SmoothLineArea (new LiveChart.Values(1000)); - var serie = new LiveChart.Serie ("Core x", renderer); + var serie = new LiveChart.Serie (("Serie %d").printf(i), renderer); serie.set_main_color ({ 0.35 + i/20, 0.8, 0.1, 1.0}); - chart.add_serie (serie); - // serie_list.add (serie); - } + live_chart.add_serie (serie); - add (chart); + // workaround for `gee_collection_get_size: assertion 'self != NULL' failed` + // https://github.com/lcallarec/live-chart/issues/16 + live_chart.add_value (serie, 0); + } + add (live_chart); } public void update (int serie_number, double value) { - // debug("%f", value); - // chart.add_value (serie_list.get(serie_number), value); - chart.add_value_by_index (serie_number, value); + live_chart.add_value_by_index (serie_number, value); } - // public void set_data (Gee.ArrayList history) { + // public void set_data (int serie_number, Gee.ArrayList history) { // var refresh_rate_is_ms = 2000; //your own refresh rate in milliseconds - // chart.add_unaware_timestamp_collection(serie_list[0], history, refresh_rate_is_ms); + // live_chart.add_unaware_timestamp_collection(live_chart.series[serie_number], history, refresh_rate_is_ms); // } + public void clear () { - // var series = chart.series; - // foreach (var serie in serie_list) { + // var series = live_chart.series; + // foreach (var serie in series) { // serie.clear(); // } } diff --git a/src/Widgets/Chart/NetworkChart.vala b/src/Widgets/Chart/NetworkChart.vala new file mode 100644 index 00000000..ae8e8b1c --- /dev/null +++ b/src/Widgets/Chart/NetworkChart.vala @@ -0,0 +1,67 @@ +public class Monitor.NetworkChart : Gtk.Box { + private LiveChart.Chart live_chart; + public LiveChart.Config config; + + construct { + get_style_context ().add_class ("graph"); + + vexpand = true; + height_request = 120; + + config = new LiveChart.Config (); + // config.y_axis.unit = "%"; + // config.y_axis.tick_interval = 25; + // config.y_axis.fixed_max = 100.0; + config.y_axis.labels.visible = false; + config.x_axis.labels.visible = false; + + config.padding = LiveChart.Padding () { + smart = LiveChart.AutoPadding.NONE, + top = 0, + right = 0, + bottom = 0, + left = -1 + }; + + live_chart = new LiveChart.Chart (config); + live_chart.expand = true; + live_chart.legend.visible = false; + live_chart.grid.visible = true; + live_chart.background.main_color = Gdk.RGBA () { + red= 1, green= 1, blue= 1, alpha= 1 + }; //White background + + } + + public NetworkChart (int series_quantity) { + for (int i = 0; i < series_quantity; i++) { + var renderer = new LiveChart.SmoothLineArea (new LiveChart.Values(1000)); + var serie = new LiveChart.Serie (("Serie %d").printf(i), renderer); + serie.set_main_color ({ 0.35 + i/20, 0.8, 0.1, 1.0}); + live_chart.add_serie (serie); + + // workaround for `gee_collection_get_size: assertion 'self != NULL' failed` + // https://github.com/lcallarec/live-chart/issues/16 + // why 3? I don't know. + live_chart.add_value (serie, 3); + } + add (live_chart); + } + + public void update (int serie_number, double value) { + live_chart.add_value_by_index (serie_number, value); + } + + // public void set_data (int serie_number, Gee.ArrayList history) { + // var refresh_rate_is_ms = 2000; //your own refresh rate in milliseconds + // live_chart.add_unaware_timestamp_collection(live_chart.series[serie_number], history, refresh_rate_is_ms); + // } + + + public void clear () { + // var series = live_chart.series; + // foreach (var serie in series) { + // serie.clear(); + // } + } +} diff --git a/src/Views/ProcessView/ProcessInfoView/Chart.vala b/src/Widgets/Chart/ProcessChart.vala similarity index 93% rename from src/Views/ProcessView/ProcessInfoView/Chart.vala rename to src/Widgets/Chart/ProcessChart.vala index 3e320b5e..045c70b0 100644 --- a/src/Views/ProcessView/ProcessInfoView/Chart.vala +++ b/src/Widgets/Chart/ProcessChart.vala @@ -1,4 +1,4 @@ -public class Monitor.Chart : Gtk.Box { +public class Monitor.ProcessChart : Gtk.Box { private LiveChart.Serie serie; private LiveChart.SmoothLineArea renderer; private LiveChart.Chart chart; @@ -46,7 +46,7 @@ public class Monitor.Chart : Gtk.Box { chart.add_value (serie, value); } - public void set_data (Gee.ArrayList history) { + public new void set_data (Gee.ArrayList history) { var refresh_rate_is_ms = 2000; //your own refresh rate in milliseconds chart.add_unaware_timestamp_collection(serie, history, refresh_rate_is_ms); } @@ -54,4 +54,4 @@ public class Monitor.Chart : Gtk.Box { public void clear () { serie.clear(); } -} +} \ No newline at end of file diff --git a/src/Widgets/Labels/LabelH4.vala b/src/Widgets/Labels/LabelH4.vala new file mode 100644 index 00000000..55f1560b --- /dev/null +++ b/src/Widgets/Labels/LabelH4.vala @@ -0,0 +1,14 @@ +class LabelH4 : Gtk.Label { + + construct { + get_style_context ().add_class ("h4"); + valign = Gtk.Align.START; + halign = Gtk.Align.START; + margin_start = 6; + ellipsize = Pango.EllipsizeMode.END; + } + + public LabelH4 (string label) { + Object (label: label); + } +} \ No newline at end of file diff --git a/src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala b/src/Widgets/Labels/LabelRoundy.vala similarity index 69% rename from src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala rename to src/Widgets/Labels/LabelRoundy.vala index 7a8964d4..dd490cdd 100644 --- a/src/Views/ProcessView/ProcessInfoView/RoundyLabel.vala +++ b/src/Widgets/Labels/LabelRoundy.vala @@ -1,14 +1,14 @@ -public class Monitor.RoundyLabel : Gtk.Fixed { +public class Monitor.LabelRoundy : Gtk.Fixed { public Gtk.Label val; public Gtk.Label desc; - public RoundyLabel (string description) { + public LabelRoundy (string description) { val = new Gtk.Label (Utils.NO_DATA); val.get_style_context ().add_class ("roundy-label"); desc = new Gtk.Label (description); - desc.get_style_context ().add_class ("pid"); + desc.get_style_context ().add_class ("small-text"); put(val, 0, 12); put(desc, 6, 0); diff --git a/src/Widgets/Labels/LabelVertical.vala b/src/Widgets/Labels/LabelVertical.vala new file mode 100644 index 00000000..f7fa2546 --- /dev/null +++ b/src/Widgets/Labels/LabelVertical.vala @@ -0,0 +1,43 @@ +public class Monitor.LabelVertical : Gtk.EventBox { + + private Gtk.Grid grid; + + public signal void clicked (); + + public Gtk.Label val; + public Gtk.Label desc; + + construct { + grid = new Gtk.Grid (); + margin_start = 12; + margin_top = 6; + + get_style_context ().add_class ("label-vertical"); + } + + public LabelVertical (string description) { + val = new Gtk.Label (Utils.NO_DATA); + + val.get_style_context ().add_class ("label-vertical-val"); + + desc = new Gtk.Label (description); + desc.get_style_context ().add_class ("small-text"); + + grid.attach(desc, 0, 0, 1, 1); + grid.attach(val, 0, 1, 1, 1); + + add (grid); + + events |= Gdk.EventMask.BUTTON_RELEASE_MASK; + + button_release_event.connect ((event) => { + clicked (); + return false; + }); + + } + + public void set_text (string text) { + val.set_text (text); + } +} \ No newline at end of file diff --git a/src/Widgets/Statusbar/Statusbar.vala b/src/Widgets/Statusbar/Statusbar.vala index d30193e6..26fa62bd 100644 --- a/src/Widgets/Statusbar/Statusbar.vala +++ b/src/Widgets/Statusbar/Statusbar.vala @@ -14,15 +14,21 @@ public class Monitor.Statusbar : Gtk.ActionBar { swap_icon.tooltip_text = _ ("Swap"); cpu_usage_label = new Gtk.Label (_("Calculating…")); + cpu_usage_label.set_width_chars (4); + cpu_usage_label.xalign = 0; pack_start (cpu_icon); pack_start (cpu_usage_label); memory_usage_label = new Gtk.Label (_("Calculating…")); + memory_usage_label.set_width_chars (4); + memory_usage_label.xalign = 0; ram_icon.margin_start = 6; pack_start (ram_icon); pack_start (memory_usage_label); swap_usage_label = new Gtk.Label (_("Calculating…")); + swap_usage_label.set_width_chars (4); + swap_usage_label.xalign = 0; swap_icon.margin_start = 6; pack_start (swap_icon); pack_start (swap_usage_label); diff --git a/vapi/libgtop-2.0.vapi b/vapi/libgtop-2.0.vapi index e8db74b8..b69e634b 100644 --- a/vapi/libgtop-2.0.vapi +++ b/vapi/libgtop-2.0.vapi @@ -45,6 +45,7 @@ namespace GTop { public void get_msg_limits_s (out GTop.MsgLimits buf); public void get_netload_l (out GTop.NetLoad buf, string @interface); public void get_netload_s (out GTop.NetLoad buf, string @interface); + public string[] get_netlist (out GTop.NetList buf); public ulong get_parameter_l (uint parameter, void* data_ptr, ulong data_size); public void get_ppp_l (out GTop.Ppp buf, ushort device); public void get_ppp_s (out GTop.Ppp buf, ushort device); @@ -127,9 +128,9 @@ namespace GTop { [CCode (cheader_filename = "glibtop/sysinfo.h", cname = "glibtop_entry", has_type_id = false)] public struct Entry { - public weak GLib.GenericArray labels; - public weak GLib.HashTable values; - public weak GLib.HashTable descriptions; + public GLib.PtrArray labels; + public GLib.HashTable values; + public GLib.HashTable descriptions; } [CCode (cheader_filename = "glibtop/fsusage.h", cname = "glibtop_fsusage", has_type_id = false)] @@ -521,7 +522,7 @@ namespace GTop { public uint64 flags; public uint64 ncpu; [CCode (array_length = false, array_null_terminated = true)] - public weak GTop.Entry[] cpuinfo; + public unowned Entry[] cpuinfo; } [CCode (cheader_filename = "glibtop/union.h", cname = "glibtop_union")] @@ -1273,6 +1274,8 @@ namespace GTop { public static void get_msg_limits (out GTop.MsgLimits buf); [CCode (cheader_filename = "glibtop.h", cname = "glibtop_get_netload")] public static void get_netload (out GTop.NetLoad buf, string @interface); + [CCode (cheader_filename = "glibtop/netlist.h", cname = "glibtop_get_netlist", array_length = false, array_null_terminated = true)] + public static string[] get_netlist (out GTop.NetList buf); [CCode (cheader_filename = "glibtop.h", cname = "glibtop_get_ppp")] public static void get_ppp (out GTop.Ppp buf, ushort device); [CCode (cheader_filename = "glibtop.h", cname = "glibtop_get_proc_affinity")]