[gnome-usage/pstetka/gnome-usage-disk-io: 6/7] disk-subview: Add UI for disk-io monitoring



commit 836b83fa678775b91932d867f9d59a284e6eb3db
Author: Petr Štětka <pstetka redhat com>
Date:   Mon Sep 11 16:04:16 2017 +0200

    disk-subview: Add UI for disk-io monitoring
    
    Add subview and graph for disk-io monitoring.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=787549

 data/org.gnome.Usage.gresource.xml |   1 +
 data/ui/disk-sub-view.ui           |  90 ++++++++++++++++++++++++++++++
 src/application.vala               |  10 ++++
 src/disk-graph-model.vala          |  92 +++++++++++++++++++++++++++++++
 src/disk-graph.vala                | 109 +++++++++++++++++++++++++++++++++++++
 src/disk-sub-view.vala             |  53 ++++++++++++++++++
 src/graph-stack-switcher.vala      |   3 +-
 src/graph-switcher-button.vala     |   6 ++
 src/memory-sub-view.vala           |   3 +-
 src/meson.build                    |   3 +
 src/performance-view.vala          |   3 +-
 src/process-list-box.vala          |  37 ++++++++++---
 src/process-row.vala               |   3 +
 13 files changed, 402 insertions(+), 11 deletions(-)
---
diff --git a/data/org.gnome.Usage.gresource.xml b/data/org.gnome.Usage.gresource.xml
index e793a36..0887342 100644
--- a/data/org.gnome.Usage.gresource.xml
+++ b/data/org.gnome.Usage.gresource.xml
@@ -3,6 +3,7 @@
     <gresource prefix="/org/gnome/Usage">
         <file compressed="true">interface/adwaita.css</file>
         <file preprocess="xml-stripblanks">ui/primary-menu.ui</file>
+        <file preprocess="xml-stripblanks">ui/disk-sub-view.ui</file>
         <file preprocess="xml-stripblanks">ui/header-bar.ui</file>
         <file preprocess="xml-stripblanks">ui/memory-speedometer.ui</file>
         <file preprocess="xml-stripblanks">ui/no-results-found-view.ui</file>
diff --git a/data/ui/disk-sub-view.ui b/data/ui/disk-sub-view.ui
new file mode 100644
index 0000000..82d209f
--- /dev/null
+++ b/data/ui/disk-sub-view.ui
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="3.9"/>
+  <template class="UsageDiskSubView" parent="UsageView">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkBox">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <property name="halign">center</property>
+        <property name="margin_bottom">30</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Disk I/O</property>
+            <property name="use_markup">True</property>
+            <property name="margin_bottom">15</property>
+            <attributes>
+              <attribute name="scale" value="1.2"/>
+            </attributes>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">False</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="UsageGraphBox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="orientation">vertical</property>
+            <property name="height_request">225</property>
+            <property name="width_request">600</property>
+            <property name="valign">start</property>
+            <style>
+              <class name="graph-box"/>
+            </style>
+            <child>
+              <object class="UsageDiskGraphBig">
+                <property name="visible">True</property>
+              </object>
+              <packing>
+                <property name="expand">true</property>
+                <property name="fill">true</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkSpinner" id="spinner">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="active">True</property>
+            <property name="margin_top">30</property>
+            <property name="height_request">250</property>
+          </object>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="UsageNoResultsFoundView" id="no_process_view"></object>
+          <packing>
+            <property name="expand">True</property>
+            <property name="fill">True</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="UsageProcessListBox" id="process_list_box">
+            <property name="margin_top">30</property>
+          </object>
+          <packing>
+            <property name="position">4</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/src/application.vala b/src/application.vala
index 4d2579a..d478ee2 100644
--- a/src/application.vala
+++ b/src/application.vala
@@ -49,6 +49,7 @@ namespace Usage
             if (window != null)
                 return;
 
+            ensure_types();
             window = new Window(this);
 
             set_accels_for_action("app.quit", {"<Primary>q"});
@@ -63,6 +64,15 @@ namespace Usage
             set_accels_for_action ("app.search", {"<Primary>f"});
         }
 
+        private void ensure_types()
+        {
+            var disk_graph = typeof (Usage.DiskGraphBig);
+            disk_graph.ensure();
+
+            var disk_sub_view = typeof (Usage.DiskSubView);
+            disk_sub_view.ensure();
+        }
+
         private void on_about(GLib.SimpleAction action, GLib.Variant? parameter)
         {
             string[] authors = {
diff --git a/src/disk-graph-model.vala b/src/disk-graph-model.vala
new file mode 100644
index 0000000..3d6891f
--- /dev/null
+++ b/src/disk-graph-model.vala
@@ -0,0 +1,92 @@
+/* disk-graph-model.vala
+ *
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Petr Štětka <pstetka redhat com>
+ */
+
+using Dazzle;
+
+namespace Usage {
+
+    public class DiskGraphModel : GraphModel {
+        public const int COLUMN_READ_ID = 0;
+        public const int COLUMN_WRITE_ID = 1;
+
+        private const double MIN_VALUE = 10;
+        private const double GROW_UP_FACTOR = 1.5;
+        private const double GROW_DOWN_LIMIT = 4;
+
+        private double max_value = MIN_VALUE;
+
+        construct {
+            var settings = Settings.get_default();
+            set_timespan (settings.graph_timespan * 1000);
+            set_max_samples (settings.graph_max_samples);
+
+            var column_download = new GraphColumn("READ", Type.from_name("gdouble"));
+            add_column(column_download);
+            var column_upload = new GraphColumn("WRITE", Type.from_name("gdouble"));
+            add_column(column_upload);
+
+            Timeout.add(settings.graph_update_interval, update_data);
+        }
+
+        bool update_data() {
+            GraphModelIter iter;
+            push (out iter, get_monotonic_time ());
+
+            SystemMonitor monitor = SystemMonitor.get_default();
+
+            double disk_read = monitor.disk_read;
+            double disk_write = monitor.disk_write;
+
+            iter_set_value(iter, COLUMN_READ_ID, disk_read);
+            iter_set_value(iter, COLUMN_WRITE_ID, disk_write);
+
+            double max_iter_value_read = get_max_iter_val(COLUMN_READ_ID);
+            double max_iter_value_write = get_max_iter_val(COLUMN_WRITE_ID);
+            double max_actual_iter_value = max_iter_value_read > max_iter_value_write ? max_iter_value_read 
: max_iter_value_write;
+
+            if(max_actual_iter_value > max_value || max_actual_iter_value < (max_value / GROW_DOWN_LIMIT))
+                max_value = max_actual_iter_value * GROW_UP_FACTOR;
+
+            if(max_value < MIN_VALUE)
+                max_value = MIN_VALUE;
+
+            this.value_max = max_value;
+
+            return true;
+        }
+
+        double get_max_iter_val (uint column_index) {
+            double max_value = 0.0;
+            GraphModelIter iter;
+
+            if (get_iter_first (out iter)) {
+                var val = iter_get_value(iter, column_index);
+                max_value = val.get_double();
+
+                while (iter_next (ref iter)) {
+                    var val_next = iter_get_value(iter, column_index);
+                    max_value = val_next.get_double() > max_value ? val_next.get_double() : max_value;
+                }
+            }
+
+            return max_value;
+        }
+    }
+}
diff --git a/src/disk-graph.vala b/src/disk-graph.vala
new file mode 100644
index 0000000..fdd377b
--- /dev/null
+++ b/src/disk-graph.vala
@@ -0,0 +1,109 @@
+/* disk-graph.vala
+ *
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Petr Štětka <pstetka redhat com>
+ */
+
+using Dazzle;
+
+namespace Usage
+{
+    public class DiskGraph : GraphView
+    {
+        private const double LINE_WIDTH = 1.2;
+        private static DiskGraphModel graph_model;
+
+        class construct {
+            set_css_name("rg-graph");
+        }
+
+        construct {
+            get_style_context().add_class("line");
+            var color_line_read = get_style_context().get_color(get_style_context().get_state());
+            get_style_context().remove_class("line");
+
+            get_style_context().add_class("stacked");
+            var color_read = get_style_context().get_color(get_style_context().get_state());
+            get_style_context().remove_class("stacked");
+
+            get_style_context().add_class("line_orange");
+            var color_line_write = get_style_context().get_color(get_style_context().get_state());
+            get_style_context().remove_class("line_orange");
+
+            get_style_context().add_class("stacked_orange");
+            var color_write = get_style_context().get_color(get_style_context().get_state());
+            get_style_context().remove_class("stacked_orange");
+
+            if(graph_model == null)
+                graph_model = new DiskGraphModel();
+
+            set_model(graph_model);
+
+            var renderer_read = new GraphStackedRenderer();
+            renderer_read.column = DiskGraphModel.COLUMN_READ_ID;
+            renderer_read.stroke_color_rgba = color_line_read;
+            renderer_read.stacked_color_rgba = color_read;
+            renderer_read.line_width = LINE_WIDTH;
+            add_renderer(renderer_read);
+
+            var renderer_write = new GraphStackedRenderer();
+            renderer_write.column = DiskGraphModel.COLUMN_WRITE_ID;
+            renderer_write.stroke_color_rgba = color_line_write;
+            renderer_write.stacked_color_rgba = color_write;
+            renderer_write.line_width = LINE_WIDTH;
+            add_renderer(renderer_write);
+        }
+    }
+
+    public class DiskGraphBig : GraphView {
+        private static DiskGraphModel graph_model;
+        private const double LINE_WIDTH = 1.5;
+
+        class construct {
+            set_css_name("rg-graph");
+        }
+
+        construct {
+            get_style_context().add_class("line");
+            var color_read = get_style_context().get_color(get_style_context().get_state());
+            get_style_context().remove_class("line");
+
+            get_style_context().add_class("line_orange");
+            var color_write = get_style_context().get_color(get_style_context().get_state());
+            get_style_context().remove_class("line_orange");
+
+            get_style_context().add_class("big");
+
+            if(graph_model == null)
+                graph_model = new DiskGraphModel();
+
+            set_model(graph_model);
+
+            var renderer_read = new GraphLineRenderer();
+            renderer_read.column = DiskGraphModel.COLUMN_READ_ID;
+            renderer_read.stroke_color_rgba = color_read;
+            renderer_read.line_width = LINE_WIDTH;
+            add_renderer(renderer_read);
+
+            var renderer_write = new GraphLineRenderer();
+            renderer_write.column = DiskGraphModel.COLUMN_WRITE_ID;
+            renderer_write.stroke_color_rgba = color_write;
+            renderer_write.line_width = LINE_WIDTH;
+            add_renderer(renderer_write);
+        }
+    }
+}
diff --git a/src/disk-sub-view.vala b/src/disk-sub-view.vala
new file mode 100644
index 0000000..cc5eccf
--- /dev/null
+++ b/src/disk-sub-view.vala
@@ -0,0 +1,53 @@
+/* disk-sub-view.vala
+ *
+ * Copyright (C) 2019 Red Hat, Inc.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Petr Štětka <pstetka redhat com>
+ */
+
+namespace Usage
+{
+    [GtkTemplate (ui = "/org/gnome/Usage/ui/disk-sub-view.ui")]
+    public class DiskSubView : View, SubView {
+        [GtkChild]
+        private Gtk.Spinner spinner;
+
+        [GtkChild]
+        private NoResultsFoundView no_process_view;
+
+        [GtkChild]
+        private Usage.ProcessListBox process_list_box;
+
+        construct {
+            process_list_box.type = ProcessListBoxType.DISK;
+
+            var system_monitor = SystemMonitor.get_default();
+
+           system_monitor.notify["disk-process-list-ready"].connect ((sender, property) => {
+                if(system_monitor.disk_process_list_ready) {
+                    spinner.active = false;
+                    spinner.visible = false;
+                }
+            });
+
+            process_list_box.bind_property ("visible", no_process_view, "visible", 
BindingFlags.INVERT_BOOLEAN);
+        }
+
+        public void search_in_processes(string text) {
+            process_list_box.search_text = text;
+        }
+    }
+}
diff --git a/src/graph-stack-switcher.vala b/src/graph-stack-switcher.vala
index 3423648..a1fba7b 100644
--- a/src/graph-stack-switcher.vala
+++ b/src/graph-stack-switcher.vala
@@ -43,7 +43,8 @@ namespace Usage
 
             buttons = {
                 new GraphSwitcherButton.processor(_("Processor")),
-                new GraphSwitcherButton.memory(_("Memory"))
+                new GraphSwitcherButton.memory(_("Memory")),
+                new GraphSwitcherButton.disk(_("Disk I/O"))
             };
 
             foreach(GraphSwitcherButton button in buttons)
diff --git a/src/graph-switcher-button.vala b/src/graph-switcher-button.vala
index f0863c4..42ca431 100644
--- a/src/graph-switcher-button.vala
+++ b/src/graph-switcher-button.vala
@@ -36,6 +36,12 @@ namespace Usage
             child = createContent(memory_graph, label);
         }
 
+        public GraphSwitcherButton.disk(string label)
+        {
+            var disk_graph = new DiskGraph();
+            child = createContent(disk_graph, label);
+        }
+
         private Gtk.Box createContent(Dazzle.GraphView graph, string label_text)
         {
             graph.height_request = 80;
diff --git a/src/memory-sub-view.vala b/src/memory-sub-view.vala
index bc5bbf9..b020b85 100644
--- a/src/memory-sub-view.vala
+++ b/src/memory-sub-view.vala
@@ -34,8 +34,7 @@ namespace Usage
             label.margin_top = 25;
             label.margin_bottom = 15;
 
-            process_list_box = new ProcessListBox();
-            process_list_box.type = ProcessListBoxType.MEMORY;
+            process_list_box = new ProcessListBox.with_type(ProcessListBox.MEMORY);
             process_list_box.margin_bottom = 20;
             process_list_box.margin_top = 30;
 
diff --git a/src/meson.build b/src/meson.build
index 0a754f1..c01b2d8 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -7,7 +7,10 @@ vala_sources = [
   'cpu-graph.vala',
   'cpu-monitor.vala',
   'cpu-sub-view.vala',
+  'disk-graph.vala',
+  'disk-graph-model.vala',
   'disk-monitor.vala',
+  'disk-sub-view.vala',
   'gnome-usage.vala',
   'graph-box.vala',
   'graph-stacked-renderer.vala',
diff --git a/src/performance-view.vala b/src/performance-view.vala
index 4253964..4399168 100644
--- a/src/performance-view.vala
+++ b/src/performance-view.vala
@@ -50,7 +50,8 @@ namespace Usage
             sub_views = new View[]
             {
                 new ProcessorSubView(),
-                new MemorySubView()
+                new MemorySubView(),
+                new DiskSubView()
             };
 
             foreach(var sub_view in sub_views)
diff --git a/src/process-list-box.vala b/src/process-list-box.vala
index 90322d6..9e08fa1 100644
--- a/src/process-list-box.vala
+++ b/src/process-list-box.vala
@@ -21,26 +21,33 @@
 namespace Usage
 {
     public enum ProcessListBoxType {
+        NONE,
         PROCESSOR,
-        MEMORY
+        MEMORY,
+        DISK
     }
 
     public class ProcessListBox : Gtk.ListBox
     {
         public bool empty { get; set; default = true; }
         public string search_text { get; set; default = ""; }
-        public ProcessListBoxType type = ProcessListBoxType.PROCESSOR;
+        public ProcessListBoxType type = ProcessListBoxType.NONE;
 
         private const double APP_CPU_MIN_LOAD_LIMIT = 1;
         private const double APP_MEM_MIN_USAGE_LIMIT = 0;
+        private const double APP_DISK_MIN_USAGE_LIMIT = 0;
         private ListStore model;
 
+        public ProcessListBox.with_type(ProcessListBoxType type) {
+            this.type = type;
+            update();
+        }
+
         construct
         {
             set_selection_mode (Gtk.SelectionMode.NONE);
             set_header_func (update_header);
 
-            this.type = type;
             model = new ListStore(typeof(AppItem));
             bind_model(model, on_row_created);
 
@@ -53,15 +60,18 @@ namespace Usage
                 update();
             });
 
+            var settings = Settings.get_default();
             var system_monitor = SystemMonitor.get_default();
-            system_monitor.notify["process-list-ready"].connect (() => {
-                if(system_monitor.process_list_ready)
+            system_monitor.notify["cpu-process-list-ready"].connect (() => {
+                if(type == ProcessListBoxType.PROCESSOR && system_monitor.cpu_process_list_ready)
+                    update();
+            });
+            system_monitor.notify["disk-process-list-ready"].connect (() => {
+                if(type == ProcessListBoxType.DISK && system_monitor.disk_process_list_ready)
                     update();
             });
 
-            var settings = Settings.get_default();
             Timeout.add(settings.list_update_interval_UI, update);
-
             bind_property ("empty", this, "visible", BindingFlags.INVERT_BOOLEAN);
         }
 
@@ -69,6 +79,9 @@ namespace Usage
         {
             model.remove_all();
 
+            if(type == ProcessListBoxType.NONE)
+                return true;
+
             CompareDataFunc<AppItem> app_cmp = (a, b) => {
                 AppItem app_a = (AppItem) a;
                 AppItem app_b = (AppItem) b;
@@ -79,6 +92,10 @@ namespace Usage
                         return (int) ((uint64) (app_a.cpu_load < app_b.cpu_load) - (uint64) (app_a.cpu_load 
app_b.cpu_load));
                     case ProcessListBoxType.MEMORY:
                         return (int) ((uint64) (app_a.mem_usage < app_b.mem_usage) - (uint64) 
(app_a.mem_usage > app_b.mem_usage));
+                    case ProcessListBoxType.DISK:
+                        var app_a_disk = app_a.disk_read + app_a.disk_write;
+                        var app_b_disk = app_b.disk_read + app_b.disk_write;
+                        return (int) ((uint64) (app_a_disk < app_b_disk) - (uint64) (app_a_disk > 
app_b_disk));
                 }
             };
 
@@ -98,6 +115,12 @@ namespace Usage
                             if(app.mem_usage > APP_MEM_MIN_USAGE_LIMIT)
                                 model.insert_sorted(app, app_cmp);
                         break;
+                    case ProcessListBoxType.DISK:
+                        foreach(unowned AppItem app in system_monitor.get_apps()) {
+                            if((app.disk_read + app.disk_write) > APP_DISK_MIN_USAGE_LIMIT)
+                                model.insert_sorted(app, app_cmp);
+                        }
+                        break;
                 }
             }
             else {
diff --git a/src/process-row.vala b/src/process-row.vala
index b9de945..ed501c3 100644
--- a/src/process-row.vala
+++ b/src/process-row.vala
@@ -73,6 +73,9 @@ namespace Usage
                 case ProcessListBoxType.MEMORY:
                     load_label.label = Utils.format_size_values(app.mem_usage);
                     break;
+                case ProcessListBoxType.DISK:
+                    load_label.label = Utils.format_size_speed_values(app.disk_read) + " / " + 
Utils.format_size_speed_values(app.disk_write);
+                    break;
             }
         }
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]