[Xfce4-commits] [panel-plugins/xfce4-hardware-monitor-plugin] 06/18: Implement Generic Monitor

noreply at xfce.org noreply at xfce.org
Tue Jun 28 21:33:28 CEST 2016


This is an automated email from the git hooks/post-receive script.

omegaphil pushed a commit to branch omegaphil/graph-disk-io
in repository panel-plugins/xfce4-hardware-monitor-plugin.

commit 16a0c6a23721c9e38e0a7a1c7e24839b7d7de36b
Author: OmegaPhil <OmegaPhil at startmail.com>
Date:   Thu Jun 16 21:06:58 2016 +0100

    Implement Generic Monitor
---
 src/choose-monitor-window.cpp | 276 ++++++++++++++++++++++-
 src/choose-monitor-window.hpp |  26 ++-
 src/monitor-impls.cpp         | 260 +++++++++++++++++++++-
 src/monitor-impls.hpp         |  48 +++-
 src/ui.glade                  | 494 ++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 1074 insertions(+), 30 deletions(-)

diff --git a/src/choose-monitor-window.cpp b/src/choose-monitor-window.cpp
index 501359c..e9041bc 100644
--- a/src/choose-monitor-window.cpp
+++ b/src/choose-monitor-window.cpp
@@ -62,6 +62,7 @@ ChooseMonitorWindow::ChooseMonitorWindow(XfcePanelPlugin* panel_applet_local,
   ui->get_widget("network_load_radiobutton", network_load_radiobutton);
   ui->get_widget("temperature_radiobutton", temperature_radiobutton);
   ui->get_widget("fan_speed_radiobutton", fan_speed_radiobutton);
+  ui->get_widget("generic_radiobutton", generic_radiobutton);
 
   ui->get_widget("cpu_usage_options", cpu_usage_options);
   ui->get_widget("load_average_options", load_average_options);
@@ -113,6 +114,32 @@ ChooseMonitorWindow::ChooseMonitorWindow(XfcePanelPlugin* panel_applet_local,
   ui->get_widget("fan_speed_combobox", fan_speed_combobox);
   ui->get_widget("fan_speed_tag_entry", fan_speed_tag);
 
+  ui->get_widget("generic_box", generic_box);
+  ui->get_widget("generic_options", generic_options);
+  ui->get_widget("generic_file_path_entry", generic_file_path_entry);
+  ui->get_widget("generic_number_regex_hbox", generic_number_regex_hbox);
+  ui->get_widget("generic_read_all_contents_radiobutton",
+                 generic_read_all_contents_radiobutton);
+  ui->get_widget("generic_extract_via_regex_radiobutton",
+                 generic_extract_via_regex_radiobutton);
+  ui->get_widget("generic_regex_entry", generic_regex_entry);
+  ui->get_widget("generic_change_in_value_checkbutton",
+                 generic_change_in_value_checkbutton);
+  ui->get_widget("generic_change_in_value_hbox", generic_change_in_value_hbox);
+  ui->get_widget("generic_change_in_value_positive_radiobutton",
+                 generic_change_in_value_positive_radiobutton);
+  ui->get_widget("generic_change_in_value_negative_radiobutton",
+                 generic_change_in_value_negative_radiobutton);
+  ui->get_widget("generic_change_in_value_both_radiobutton",
+                 generic_change_in_value_both_radiobutton);
+  ui->get_widget("generic_data_source_name_long_entry",
+                 generic_data_source_name_long_entry);
+  ui->get_widget("generic_data_source_name_short_entry",
+                 generic_data_source_name_short_entry);
+  ui->get_widget("generic_units_long_entry", generic_units_long_entry);
+  ui->get_widget("generic_units_short_entry", generic_units_short_entry);
+  ui->get_widget("generic_tag_entry", generic_tag);
+
   cpu_usage_radiobutton->signal_toggled()
     .connect(sigc::mem_fun(*this, &ChooseMonitorWindow::
                         on_cpu_usage_radiobutton_toggled));
@@ -153,6 +180,18 @@ ChooseMonitorWindow::ChooseMonitorWindow(XfcePanelPlugin* panel_applet_local,
     .connect(sigc::mem_fun(*this, &ChooseMonitorWindow::
                         on_fan_speed_radiobutton_toggled));
 
+  generic_radiobutton->signal_toggled()
+    .connect(sigc::mem_fun(*this, &ChooseMonitorWindow::
+                        on_generic_radiobutton_toggled));
+
+  generic_extract_via_regex_radiobutton->signal_toggled()
+    .connect(sigc::mem_fun(*this, &ChooseMonitorWindow::
+                        on_generic_extract_via_regex_radiobutton_toggled));
+
+  generic_change_in_value_checkbutton->signal_toggled()
+    .connect(sigc::mem_fun(*this, &ChooseMonitorWindow::
+                        on_generic_change_in_value_checkbutton_toggled));
+
   // Note 1 off to avoid counting from zero in the interface
   cpu_no_spinbutton->set_range(1, CpuUsageMonitor::max_no_cpus);
 
@@ -358,6 +397,15 @@ Monitor *ChooseMonitorWindow::run(const Glib::ustring &mon_dir)
         temperature_radiobutton->set_active();
         temperature_tag->set_text(tag);
       }
+
+      // TODO: When I start supporting it, why no fan stuff here?
+
+      else if (type == "generic")
+      {
+        device_notebook->set_current_page(4);
+        generic_radiobutton->set_active();
+        generic_tag->set_text(tag);
+      }
       else
       {
         device_notebook->set_current_page(0);
@@ -488,10 +536,61 @@ Monitor *ChooseMonitorWindow::run(const Glib::ustring &mon_dir)
           network_direction_combobox->set_active(0);
       }
 
-      int temperature_no = xfce_rc_read_int_entry(settings_ro,
-          "temperature_no", 0);
+      // Fill in temperature info
+      if (xfce_rc_has_entry(settings_ro, "temperature_no"))
+      {
+        int temperature_no = xfce_rc_read_int_entry(settings_ro,
+                                                    "temperature_no", 0);
+        temperature_combobox->set_active(temperature_no);
+      }
 
-      temperature_combobox->set_active(temperature_no);
+      // Fill in generic info
+      if (xfce_rc_has_entry(settings_ro, "file_path"))
+      {
+        Glib::ustring file_path = xfce_rc_read_entry(settings_ro, "file_path",
+                                                 ""),
+            regex_string = xfce_rc_read_entry(settings_ro, "regex", ""),
+            data_source_name_long = xfce_rc_read_entry(settings_ro,
+                                                   "data_source_name_long",  ""),
+            data_source_name_short = xfce_rc_read_entry(settings_ro,
+                                                    "data_source_name_short", ""),
+            units_long = xfce_rc_read_entry(settings_ro, "units_long",  ""),
+            units_short = xfce_rc_read_entry(settings_ro, "units_short", "");
+        bool value_from_contents = xfce_rc_read_bool_entry(settings_ro,
+                                                           "value_from_contents",
+                                                           false),
+            follow_change = xfce_rc_read_bool_entry(settings_ro, "follow_change",
+                                                    false);
+        int direction = xfce_rc_read_int_entry(settings_ro,
+                                               "value_change_direction",
+                                               GenericMonitor::positive);
+
+        generic_file_path_entry->set_text(file_path);
+
+        if (!value_from_contents)
+          generic_extract_via_regex_radiobutton->set_active();
+
+        generic_regex_entry->set_text(regex_string);
+        generic_change_in_value_checkbutton->set_active(follow_change);
+
+        switch (direction)
+        {
+        case GenericMonitor::positive:
+          generic_change_in_value_positive_radiobutton->activate();
+          break;
+        case GenericMonitor::negative:
+          generic_change_in_value_negative_radiobutton->activate();
+          break;
+        case GenericMonitor::both:
+          generic_change_in_value_both_radiobutton->activate();
+          break;
+        }
+
+        generic_data_source_name_long_entry->set_text(data_source_name_long);
+        generic_data_source_name_short_entry->set_text(data_source_name_short);
+        generic_units_long_entry->set_text(units_long);
+        generic_units_short_entry->set_text(units_short);
+      }
 
       xfce_rc_close(settings_ro);
     }
@@ -683,6 +782,141 @@ Monitor *ChooseMonitorWindow::run(const Glib::ustring &mon_dir)
       else if (fan_speed_radiobutton->get_active())
         mon = new FanSpeedMonitor(fan_speed_combobox->get_active_row_number(),
                                   fan_speed_tag->get_text());
+      else if (generic_radiobutton->get_active())
+      {
+        Glib::ustring file_path = generic_file_path_entry->get_text(),
+            regex_string = generic_regex_entry->get_text(),
+            data_source_name_long = generic_data_source_name_long_entry->get_text(),
+            data_source_name_short = generic_data_source_name_short_entry->get_text(),
+            units_long = generic_units_long_entry->get_text(),
+            units_short = generic_units_short_entry->get_text();
+        bool value_from_contents = generic_read_all_contents_radiobutton->get_active(),
+            follow_change = generic_change_in_value_checkbutton->get_active();
+        GenericMonitor::ValueChangeDirection dir;
+        if (generic_change_in_value_positive_radiobutton->get_active())
+          dir = GenericMonitor::positive;
+        else if (generic_change_in_value_negative_radiobutton->get_active())
+          dir = GenericMonitor::negative;
+        else if (generic_change_in_value_both_radiobutton->get_active())
+          dir = GenericMonitor::both;
+
+        // Making sure that the path passed is valid
+        if (!Glib::file_test(file_path, Glib::FileTest::FILE_TEST_EXISTS))
+        {
+          /* Making sure the user is OK with specifying a non-existent file
+           * (i.e. it may appear later) */
+          Glib::ustring msg = Glib::ustring::
+              compose(_("Specified file '%1' does not currently exist - do "
+                        "you still want to proceed?"), file_path);
+
+          /* See helpers.hpp - tried to host a generic warning dialog
+           * implementation there but got endless include bullshit */
+          Gtk::MessageDialog d(msg, false, Gtk::MESSAGE_WARNING,
+                               Gtk::BUTTONS_YES_NO);
+          d.set_modal();
+          d.set_title(_("Generic Monitor"));
+          d.set_icon(window->get_icon());
+          if (d.run() != Gtk::RESPONSE_YES)
+          {
+            generic_file_path_entry->grab_focus();
+            response = Gtk::RESPONSE_HELP;
+            continue;
+          }
+        }
+
+        // Validating regex if necessary
+        if (!value_from_contents)
+        {
+          if (regex_string == "")
+          {
+            Glib::ustring msg = _("When 'number from regex' is specified, you "
+                                  "must provide a regex to use.");
+
+            /* See helpers.hpp - tried to host a generic warning dialog
+             * implementation there but got endless include bullshit */
+            Gtk::MessageDialog d(msg, false, Gtk::MESSAGE_WARNING,
+                                 Gtk::BUTTONS_OK);
+            d.set_modal();
+            d.set_title(_("Generic Monitor"));
+            d.set_icon(window->get_icon());
+            d.run();
+            generic_regex_entry->grab_focus();
+            response = Gtk::RESPONSE_HELP;
+            continue;
+          }
+
+          Glib::RefPtr<Glib::Regex> regex;
+          try
+          {
+            regex = Glib::Regex::create(regex_string);
+          }
+          catch (Glib::Error &e)
+          {
+            /* Regex validation failed - informing the user - error message
+             * already includes the regex */
+            Glib::ustring msg = Glib::ustring::compose(
+                  _("The regex provided is not a valid:\n\n%1"), e.what());
+
+            /* See helpers.hpp - tried to host a generic warning dialog
+             * implementation there but got endless include bullshit */
+            Gtk::MessageDialog d(msg, false, Gtk::MESSAGE_WARNING,
+                                 Gtk::BUTTONS_OK);
+            d.set_modal();
+            d.set_title(_("Generic Monitor"));
+            d.set_icon(window->get_icon());
+            d.run();
+            generic_regex_entry->grab_focus();
+            response = Gtk::RESPONSE_HELP;
+            continue;
+          }
+
+          // Making sure there is at least one capture group
+          if (regex->get_capture_count() == 0)
+          {
+            Glib::ustring msg = _("Please ensure the regex provided has one "
+                                  "capture group to use to extract the number.");
+
+            /* See helpers.hpp - tried to host a generic warning dialog
+             * implementation there but got endless include bullshit */
+            Gtk::MessageDialog d(msg, false, Gtk::MESSAGE_WARNING,
+                                 Gtk::BUTTONS_OK);
+            d.set_modal();
+            d.set_title(_("Generic Monitor"));
+            d.set_icon(window->get_icon());
+            d.run();
+            generic_regex_entry->grab_focus();
+            response = Gtk::RESPONSE_HELP;
+            continue;
+          }
+        }
+
+        // Ensuring mandatory fields have been filled in
+        if (data_source_name_long == "" || data_source_name_short == "")
+        {
+          Glib::ustring msg = _("Data source name (long and short forms) must be"
+                                " specified to create this monitor.");
+
+          /* See helpers.hpp - tried to host a generic warning dialog
+           * implementation there but got endless include bullshit */
+          Gtk::MessageDialog d(msg, false, Gtk::MESSAGE_WARNING,
+                               Gtk::BUTTONS_OK);
+          d.set_modal();
+          d.set_title(_("Generic Monitor"));
+          d.set_icon(window->get_icon());
+          d.run();
+          if (data_source_name_long == "")
+            generic_data_source_name_long_entry->grab_focus();
+          else
+            generic_data_source_name_short_entry->grab_focus();
+          response = Gtk::RESPONSE_HELP;
+          continue;
+        }
+
+        mon = new GenericMonitor(file_path, value_from_contents, regex_string,
+                                 follow_change, dir, data_source_name_long,
+                                 data_source_name_short, units_long, units_short,
+                                 generic_tag->get_text());
+      }
 
       return mon;
     }
@@ -719,22 +953,16 @@ void ChooseMonitorWindow::on_disk_stats_radiobutton_toggled()
     = disk_stats_radiobutton->get_active();
 }
 
-void ChooseMonitorWindow::on_memory_usage_radiobutton_toggled()
-{
-  memory_usage_options->property_sensitive()
-    = memory_usage_radiobutton->get_active();
-}
-
 void ChooseMonitorWindow::on_swap_usage_radiobutton_toggled()
 {
   swap_usage_options->property_sensitive()
     = swap_usage_radiobutton->get_active();
 }
 
-void ChooseMonitorWindow::on_fan_speed_radiobutton_toggled()
+void ChooseMonitorWindow::on_memory_usage_radiobutton_toggled()
 {
-  fan_speed_options->property_sensitive()
-    = fan_speed_radiobutton->get_active();
+  memory_usage_options->property_sensitive()
+    = memory_usage_radiobutton->get_active();
 }
 
 /* Triggered when user edits a network interface name after revealing the
@@ -852,6 +1080,30 @@ void ChooseMonitorWindow::on_temperature_radiobutton_toggled()
     = temperature_radiobutton->get_active();
 }
 
+void ChooseMonitorWindow::on_fan_speed_radiobutton_toggled()
+{
+  fan_speed_options->property_sensitive()
+    = fan_speed_radiobutton->get_active();
+}
+
+void ChooseMonitorWindow::on_generic_radiobutton_toggled()
+{
+  generic_options->property_sensitive()
+    = generic_radiobutton->get_active();
+}
+
+void ChooseMonitorWindow::on_generic_extract_via_regex_radiobutton_toggled()
+{
+  generic_number_regex_hbox->property_sensitive()
+    = generic_extract_via_regex_radiobutton->get_active();
+}
+
+void ChooseMonitorWindow::on_generic_change_in_value_checkbutton_toggled()
+{
+  generic_change_in_value_hbox->property_sensitive()
+    = generic_change_in_value_checkbutton->get_active();
+}
+
 bool ChooseMonitorWindow::on_closed(GdkEventAny *)
 {
   window->hide();
diff --git a/src/choose-monitor-window.hpp b/src/choose-monitor-window.hpp
index 05396c0..cb9b86a 100644
--- a/src/choose-monitor-window.hpp
+++ b/src/choose-monitor-window.hpp
@@ -69,7 +69,7 @@ private:
   Gtk::RadioButton *cpu_usage_radiobutton, *memory_usage_radiobutton,
     *swap_usage_radiobutton, *load_average_radiobutton, *disk_usage_radiobutton,
     *disk_stats_radiobutton, *network_load_radiobutton, *temperature_radiobutton,
-    *fan_speed_radiobutton;
+    *fan_speed_radiobutton, *generic_radiobutton;
 
   Gtk::Box *cpu_usage_options, *load_average_options;
   Gtk::RadioButton *all_cpus_radiobutton, *one_cpu_radiobutton;
@@ -95,6 +95,19 @@ private:
   Gtk::ComboBox *temperature_combobox, *fan_speed_combobox;
   Gtk::Entry *temperature_tag, *fan_speed_tag;
 
+  Gtk::Box  *generic_box, *generic_options, *generic_change_in_value_hbox,
+            *generic_number_regex_hbox;
+  Gtk::Entry *generic_file_path_entry, *generic_regex_entry,
+             *generic_data_source_name_long_entry,
+             *generic_data_source_name_short_entry, *generic_units_long_entry,
+             *generic_units_short_entry, *generic_tag;
+  Gtk::CheckButton *generic_change_in_value_checkbutton;
+  Gtk::RadioButton *generic_read_all_contents_radiobutton,
+                   *generic_extract_via_regex_radiobutton,
+                   *generic_change_in_value_positive_radiobutton,
+                   *generic_change_in_value_negative_radiobutton,
+                   *generic_change_in_value_both_radiobutton;
+
   XfcePanelPlugin* panel_applet;
 
   // For disk statistics device name combobox
@@ -176,14 +189,17 @@ private:
   void on_load_average_radiobutton_toggled();
   void on_disk_usage_radiobutton_toggled();
   void on_disk_stats_radiobutton_toggled();
-  void on_memory_usage_radiobutton_toggled();
   void on_swap_usage_radiobutton_toggled();
-  void on_fan_speed_radiobutton_toggled();
-  void on_network_load_radiobutton_toggled();
+  void on_memory_usage_radiobutton_toggled();
   void on_network_interfaces_restore_defaults_button_clicked();
-  void on_temperature_radiobutton_toggled();
   void on_network_interface_name_edited(const Glib::ustring& path,
                                         const Glib::ustring& new_text);
+  void on_network_load_radiobutton_toggled();
+  void on_temperature_radiobutton_toggled();
+  void on_fan_speed_radiobutton_toggled();
+  void on_generic_radiobutton_toggled();
+  void on_generic_extract_via_regex_radiobutton_toggled();
+  void on_generic_change_in_value_checkbutton_toggled();
   bool on_closed(GdkEventAny *);
 };
 
diff --git a/src/monitor-impls.cpp b/src/monitor-impls.cpp
index 510f4c2..1059bd2 100644
--- a/src/monitor-impls.cpp
+++ b/src/monitor-impls.cpp
@@ -20,8 +20,10 @@
  */
 
 #include <algorithm>
+#include <cmath>  // For fabs
 #include <iomanip>  // Needed for Precision helper
 #include <iostream>
+#include <limits>  // Used for sentinel value in Generic Monitor
 #include <string>
 #include <vector>
 
@@ -187,6 +189,7 @@ load_monitors(XfceRc *settings_ro, XfcePanelPlugin *panel_plugin)
           "interface_direction", NetworkLoadMonitor::all_data);
 
         // Converting direction setting into dedicated type
+        // TODO: I think I need to standardise my enum loading/dealing with code
         NetworkLoadMonitor::Direction dir;
 
         if (inter_direction == NetworkLoadMonitor::incoming_data)
@@ -218,6 +221,36 @@ load_monitors(XfceRc *settings_ro, XfcePanelPlugin *panel_plugin)
         monitors.push_back(new FanSpeedMonitor(fan_no, tag));
       }
 
+      else if (type == "generic")
+      {
+        // Fetching settings
+        Glib::ustring file_path = xfce_rc_read_entry(settings_ro, "file_path",
+                                                 ""),
+            regex_string = xfce_rc_read_entry(settings_ro, "regex", ""),
+            data_source_name_long = xfce_rc_read_entry(settings_ro,
+                                                   "data_source_name_long",  ""),
+            data_source_name_short = xfce_rc_read_entry(settings_ro,
+                                                    "data_source_name_short", ""),
+            units_long = xfce_rc_read_entry(settings_ro, "units_long",  ""),
+            units_short = xfce_rc_read_entry(settings_ro, "units_short", "");
+        bool value_from_contents = xfce_rc_read_bool_entry(settings_ro,
+                                                           "value_from_contents",
+                                                           false),
+            follow_change = xfce_rc_read_bool_entry(settings_ro, "follow_change",
+                                                    false);
+        GenericMonitor::ValueChangeDirection dir =
+            static_cast<GenericMonitor::ValueChangeDirection>(
+              xfce_rc_read_int_entry(settings_ro, "value_change_direction",
+                                     GenericMonitor::positive));
+
+        // Creating generic monitor
+        monitors.push_back(new GenericMonitor(file_path, value_from_contents,
+                                              regex_string, follow_change, dir,
+                                              data_source_name_long,
+                                              data_source_name_short, units_long,
+                                              units_short, tag));
+      }
+
       // Saving the monitor's settings root
       monitors.back()->set_settings_dir(settings_monitors[i]);
     }
@@ -226,7 +259,7 @@ load_monitors(XfceRc *settings_ro, XfcePanelPlugin *panel_plugin)
     g_strfreev(settings_monitors);
   }
 
-  // Always start with a CpuUsageMonitor - FIXME: use schema?
+  // Always start with a CpuUsageMonitor
   if (monitors.empty())
     monitors.push_back(new CpuUsageMonitor(""));
 
@@ -728,7 +761,7 @@ DiskStatsMonitor::DiskStatsMonitor(const Glib::ustring &device_name,
 double DiskStatsMonitor::do_measure()
 {
   // Making sure stats file is available
-  if (!stats_available())
+  if (!Glib::file_test(diskstats_path, Glib::FileTest::FILE_TEST_EXISTS))
   {
     std::cerr << Glib::ustring::compose(_("The file '%1' is not available - "
                                           "unable to obtain %2 for device '%3'!"
@@ -835,15 +868,6 @@ void DiskStatsMonitor::save(XfceRc *settings_w)
   xfce_rc_write_entry(settings_w, "tag", tag.c_str());
 }
 
-bool DiskStatsMonitor::stats_available()
-{
-  // Make sure file exists
-  return Glib::file_test(diskstats_path, Glib::FileTest::FILE_TEST_EXISTS);
-
-  /* The contents of the file will be validated as it is processed, so not
-   * duplicating this here */
-}
-
 std::map<Glib::ustring, std::vector<unsigned long int>>
 DiskStatsMonitor::parse_disk_stats()
 {
@@ -1952,3 +1976,217 @@ void FanSpeedMonitor::save(XfceRc *settings_w)
   xfce_rc_write_entry(settings_w, "max", setting.c_str());
 }
 
+
+//
+// class GenericMonitor
+//
+
+GenericMonitor::GenericMonitor(const Glib::ustring &file_path,
+                               const bool value_from_contents,
+                               const Glib::ustring &regex_string,
+                               const bool follow_change,
+                               const ValueChangeDirection dir,
+                               const Glib::ustring &data_source_name_long,
+                               const Glib::ustring &data_source_name_short,
+                               const Glib::ustring &units_long,
+                               const Glib::ustring &units_short,
+                               const Glib::ustring &tag_string)
+  : Monitor(tag_string), max_value(0),
+    previous_value(std::numeric_limits<double>::min()),
+    file_path(file_path), value_from_contents(value_from_contents),
+    follow_change(follow_change), dir(dir),
+    data_source_name_long(data_source_name_long),
+    data_source_name_short(data_source_name_short), units_long(units_long),
+    units_short(units_short)
+{
+  // Compiling regex if provided (at this stage its already been validated)
+  if (regex_string != "")
+    regex = Glib::Regex::create(regex_string);
+}
+
+double GenericMonitor::do_measure()
+{
+  // Making sure stats file is available
+  if (!Glib::file_test(file_path, Glib::FileTest::FILE_TEST_EXISTS))
+  {
+    std::cerr << Glib::ustring::compose(_("The file '%1' for the Generic Monitor"
+                                          " data source '%2' is not available!\n"),
+                                        file_path, data_source_name_long);
+    return 0;
+  }
+
+  // Attempting to read contents of provided file
+  Glib::ustring file_contents;
+  try
+  {
+    file_contents = Glib::file_get_contents(file_path);
+  }
+  catch (Glib::FileError const &e)
+  {
+    std::cerr << Glib::ustring::compose(_("Unable read the contents of '%1' for "
+                                          "the Generic Monitor data source '%2' "
+                                          "due to error '%3'\n"),
+                                        file_path, data_source_name_long,
+                                        e.what());
+    return 0;
+  }
+
+  // Removing trailing newline if present
+  if (file_contents.substr(file_contents.length() - 1,
+                           file_contents.length() - 1) == "\n")
+      file_contents = file_contents.substr(0, file_contents.length() - 1);
+
+  // Obtaining number
+  double val;
+  std::stringstream data;
+  if (value_from_contents)
+  {
+    // Obtain number from the entire contents of the file
+    data.str(file_contents);
+    if (!(data >> val))
+    {
+      std::cerr << Glib::ustring::compose(_("Unable to convert data '%1' from file "
+                                            "'%2' associated with Generic Monitor "
+                                            "data source '%3' into a number to "
+                                            "process! Defaulting to 0\n"),
+                                          file_contents, file_path,
+                                          data_source_name_long);
+      return 0;
+    }
+  }
+  else
+  {
+    /* Obtain number via a regex - the regex has already been validated with one
+     * matching group */
+    Glib::MatchInfo match_info;
+    if (!regex->match(file_contents, match_info))
+    {
+      // Unable to extract the number - warning user
+      std::cerr << Glib::ustring::compose(_("Unable extract number from file "
+                                          "contents '%1' from '%2' associated "
+                                          "with Generic Monitor data source '%3'"
+                                          " using the regex '%4'! Defaulting to "
+                                          "0\n"), file_contents, file_path,
+                                          data_source_name_long,
+                                          regex->get_pattern());
+      return 0;
+    }
+
+    // Fetching matching group results and attempting to convert to number
+    data.str(match_info.fetch(0));
+    if (!(data >> val))
+    {
+      std::cerr << Glib::ustring::compose(_("Unable to convert data '%1' from file "
+                                            "'%2' associated with Generic Monitor "
+                                            "data source '%3' into a number to "
+                                            "process! Defaulting to 0\n"),
+                                          file_contents, file_path,
+                                          data_source_name_long);
+      return 0;
+    }
+  }
+
+  double return_value;
+  if (follow_change)
+  {
+    /* User has requested to diff the data to make a rate of change
+     * Dealing with the first value to be processed */
+    if (previous_value == std::numeric_limits<double>::min())
+      previous_value = val;
+
+    /* Returning desired stat, based on whether the user wants only positive
+     * changes, negative changes, or both reported (these are intended for views
+     * that don't have a negative axis) */
+    switch (dir)
+    {
+      case positive:
+        return_value = val - previous_value;
+        if (return_value <0)
+          return_value = 0;
+        break;
+
+      case negative:
+        return_value = previous_value - val;
+        if (return_value <0)
+          return_value = 0;
+        break;
+
+      case both:
+        return_value = fabs(val - previous_value);
+    }
+    previous_value = val;
+  }
+  else
+    return_value = val;
+
+  // TODO: How do negative values affect this?
+  /* Note - max_value is no longer used to determine the graph max for
+   * Curves - the actual maxima stored in the ValueHistories are used */
+  if (val != 0)     // Reduce scale gradually
+    max_value = guint64(max_value * max_decay);
+
+  if (val > max_value)
+    max_value = guint64(val * 1.05);
+
+  // Debug code
+  /*std::cerr << Glib::ustring::compose("Generic Monitor '%1' data: %2, previous "
+                                      "data: %3\n", data_source_name_long, val,
+                                      previous_value);*/
+
+  return return_value;
+}
+
+double GenericMonitor::max()
+{
+  return max_value;
+}
+
+bool GenericMonitor::fixed_max()
+{
+  return false;
+}
+
+Glib::ustring GenericMonitor::format_value(double val, bool compact)
+{
+  return Glib::ustring::compose("%1%2", val,
+                                (compact) ? units_short : units_long);
+}
+
+Glib::ustring GenericMonitor::get_name()
+{
+  return data_source_name_long;
+}
+
+
+Glib::ustring GenericMonitor::get_short_name()
+{
+  return data_source_name_short;
+}
+
+int GenericMonitor::update_interval()
+{
+  return 1000;
+}
+
+void GenericMonitor::save(XfceRc *settings_w)
+{
+  // Fetching assigned settings group
+  Glib::ustring directory = get_settings_dir();
+
+  // Saving settings
+  xfce_rc_set_group(settings_w, directory.c_str());
+  xfce_rc_write_entry(settings_w, "type", "generic");
+  xfce_rc_write_entry(settings_w, "file_path", file_path.c_str());
+  xfce_rc_write_bool_entry(settings_w, "value_from_contents", value_from_contents);
+  xfce_rc_write_entry(settings_w, "regex", regex->get_pattern().c_str());
+  xfce_rc_write_bool_entry(settings_w, "follow_change", follow_change);
+  xfce_rc_write_int_entry(settings_w, "value_change_direction", dir);
+  xfce_rc_write_entry(settings_w, "data_source_name_long",
+                      data_source_name_long.c_str());
+  xfce_rc_write_entry(settings_w, "data_source_name_short",
+                      data_source_name_short.c_str());
+  xfce_rc_write_entry(settings_w, "units_long", units_long.c_str());
+  xfce_rc_write_entry(settings_w, "units_short", units_short.c_str());
+  xfce_rc_write_entry(settings_w, "tag", tag.c_str());
+}
+
diff --git a/src/monitor-impls.hpp b/src/monitor-impls.hpp
index 89ed4bd..2c17ff7 100644
--- a/src/monitor-impls.hpp
+++ b/src/monitor-impls.hpp
@@ -29,6 +29,7 @@
 #include <vector>
 
 #include <glib/gtypes.h>
+#include <glibmm/regex.h>
 
 #if HAVE_LIBSENSORS
 #include <sensors/sensors.h>
@@ -184,13 +185,12 @@ public:
 
   virtual double max();
   virtual bool fixed_max();
-  virtual Glib::ustring format_value(double val, bool compact= false);
+  virtual Glib::ustring format_value(double val, bool compact=false);
   virtual Glib::ustring get_name();
   virtual Glib::ustring get_short_name();
   virtual int update_interval();
   virtual void save(XfceRc *settings_w);
 
-  static bool stats_available();
   static std::vector<Glib::ustring> current_device_names();
   static Glib::ustring stat_to_string(
       const DiskStatsMonitor::Stat &stat, const bool short_ver);
@@ -357,6 +357,50 @@ private:
 };
 
 
+class GenericMonitor: public Monitor
+{
+public:
+
+  // Used for the 'follow change in value' implementation setting
+  enum ValueChangeDirection {
+     positive,
+     negative,
+     both,
+     NUM_DIRECTIONS
+  };
+
+  GenericMonitor(const Glib::ustring &file_path,
+                 const bool value_from_contents,
+                 const Glib::ustring &regex_string,
+                 const bool follow_change,
+                 const ValueChangeDirection dir,
+                 const Glib::ustring &data_source_name_long,
+                 const Glib::ustring &data_source_name_short,
+                 const Glib::ustring &units_long,
+                 const Glib::ustring &units_short,
+                 const Glib::ustring &tag_string);
+
+  virtual double max();
+  virtual bool fixed_max();
+  virtual Glib::ustring format_value(double val, bool compact=false);
+  virtual Glib::ustring get_name();
+  virtual Glib::ustring get_short_name();
+  virtual int update_interval();
+  virtual void save(XfceRc *settings_w);
+
+private:
+  virtual double do_measure();
+
+  double max_value, previous_value;
+
+  Glib::ustring file_path, data_source_name_long,
+                data_source_name_short, units_long, units_short, tag;
+  bool value_from_contents, follow_change;
+  ValueChangeDirection dir;
+  Glib::RefPtr<Glib::Regex> regex;
+};
+
+
 // a singleton for initializing the sensors library
 class Sensors: noncopyable
 {
diff --git a/src/ui.glade b/src/ui.glade
index c96a540..9a27b47 100644
--- a/src/ui.glade
+++ b/src/ui.glade
@@ -1375,6 +1375,500 @@ view</property>
                 <property name="tab_fill">False</property>
               </packing>
             </child>
+            <child>
+              <object class="GtkVBox" id="generic_vbox">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">12</property>
+                <property name="spacing">12</property>
+                <child>
+                  <object class="GtkVBox" id="generic_box">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="spacing">12</property>
+                    <child>
+                      <object class="GtkRadioButton" id="generic_radiobutton">
+                        <property name="label" translatable="yes">_Generic</property>
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="receives_default">False</property>
+                        <property name="tooltip_text" translatable="yes">Data/numbers read from a user-defined file</property>
+                        <property name="use_underline">True</property>
+                        <property name="draw_indicator">True</property>
+                        <property name="group">cpu_usage_radiobutton</property>
+                      </object>
+                      <packing>
+                        <property name="expand">False</property>
+                        <property name="fill">False</property>
+                        <property name="position">0</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkHBox" id="generic_options">
+                        <property name="visible">True</property>
+                        <property name="sensitive">False</property>
+                        <property name="can_focus">False</property>
+                        <property name="spacing">12</property>
+                        <child>
+                          <object class="GtkVBox" id="generic_options_vbox">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkHBox" id="generic_file_path_hbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">12</property>
+                                <child>
+                                  <object class="GtkLabel" id="file_path_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">File to read from:</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="generic_file_path_entry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="tooltip_text" translatable="yes">Enter the path to the file to read a number from</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="generic_number_reading_hbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkRadioButton" id="generic_read_all_contents_radiobutton">
+                                    <property name="label" translatable="yes">Number from entire contents</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="generic_extract_via_regex_radiobutton">
+                                    <property name="label" translatable="yes">Number from regex</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="draw_indicator">True</property>
+                                    <property name="group">generic_read_all_contents_radiobutton</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="generic_number_regex_hbox">
+                                <property name="visible">True</property>
+                                <property name="sensitive">False</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">12</property>
+                                <child>
+                                  <object class="GtkLabel" id="regex_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">Regex to use:</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="generic_regex_entry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="tooltip_text" translatable="yes">Regex to extract the number from the file contents with (must have one capture group for the number)</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkCheckButton" id="generic_change_in_value_checkbutton">
+                                <property name="label" translatable="yes">Follow _change in value</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="tooltip_text" translatable="yes">When visualised, rather than plotting the data direct, the difference between the current and previous measurement will be used</property>
+                                <property name="use_underline">True</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="expand">False</property>
+                                <property name="fill">False</property>
+                                <property name="position">3</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="generic_change_in_value_hbox">
+                                <property name="visible">True</property>
+                                <property name="sensitive">False</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkRadioButton" id="generic_change_in_value_positive_radiobutton">
+                                    <property name="label" translatable="yes">Positive change</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="tooltip_text" translatable="yes">Return absolute difference between current value and previous value, when change is positive</property>
+                                    <property name="active">True</property>
+                                    <property name="draw_indicator">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="generic_change_in_value_negative_radiobutton">
+                                    <property name="label" translatable="yes">Negative change</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="tooltip_text" translatable="yes">Return absolute difference between current value and previous value, when change is negative</property>
+                                    <property name="draw_indicator">True</property>
+                                    <property name="group">generic_change_in_value_positive_radiobutton</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkRadioButton" id="generic_change_in_value_both_radiobutton">
+                                    <property name="label" translatable="yes">Both</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="receives_default">False</property>
+                                    <property name="tooltip_text" translatable="yes">Return absolute difference between current value and previous value in either case</property>
+                                    <property name="draw_indicator">True</property>
+                                    <property name="group">generic_change_in_value_positive_radiobutton</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">2</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">4</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="data_source_name_long_hbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">12</property>
+                                <child>
+                                  <object class="GtkLabel" id="data_source_name_long_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">Data source name (long):</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="generic_data_source_name_long_entry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="tooltip_text" translatable="yes">The full name of your data source</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">5</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="data_source_name_short_hbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">12</property>
+                                <child>
+                                  <object class="GtkLabel" id="data_source_name_short_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">Data source name (short):</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="generic_data_source_name_short_entry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="tooltip_text" translatable="yes">A short version of your data source name for display in crampt areas</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">6</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="units_long_hbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">12</property>
+                                <child>
+                                  <object class="GtkLabel" id="units_long_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">Units (long):</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="generic_units_long_entry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="tooltip_text" translatable="yes">Units the data source is in</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">7</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="units_short_hbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="spacing">12</property>
+                                <child>
+                                  <object class="GtkLabel" id="units_short_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">Units (short):</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="generic_units_short_entry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="tooltip_text" translatable="yes">Units the data source is in for display in crampt areas</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">8</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkHBox" id="generic_tag_hbox">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkLabel" id="generic_tag_label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="label" translatable="yes">Tag:  </property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="generic_tag_entry">
+                                    <property name="width_request">80</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="tooltip_text" translatable="yes">Tag to display along with monitor data
+in the optional text overlay in a curve
+view</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                              <packing>
+                                <property name="expand">True</property>
+                                <property name="fill">True</property>
+                                <property name="position">9</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">False</property>
+                            <property name="padding">18</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="expand">True</property>
+                        <property name="fill">True</property>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="position">4</property>
+              </packing>
+            </child>
+            <child type="tab">
+              <object class="GtkLabel" id="generic_label">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="label" translatable="yes">Generic</property>
+              </object>
+              <packing>
+                <property name="position">4</property>
+                <property name="tab_fill">False</property>
+              </packing>
+            </child>
           </object>
           <packing>
             <property name="expand">True</property>

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the Xfce4-commits mailing list