summaryrefslogtreecommitdiff
path: root/multiload/src
diff options
context:
space:
mode:
authorrbuj <[email protected]>2020-12-02 09:54:00 +0100
committerraveit65 <[email protected]>2020-12-13 15:45:33 +0100
commit61e25238728dd5cb9922932a5b7279eb6cdb15da (patch)
tree07c73bb9d083054c0d71d0a19e019d6f5ab5c710 /multiload/src
parent3cf85cb5229c3e87fed2f926004fed724e94e8cb (diff)
downloadmate-applets-61e25238728dd5cb9922932a5b7279eb6cdb15da.tar.bz2
mate-applets-61e25238728dd5cb9922932a5b7279eb6cdb15da.tar.xz
multiload: Use common subdirs - src, data
Diffstat (limited to 'multiload/src')
-rw-r--r--multiload/src/Makefile.am29
-rw-r--r--multiload/src/autoscaler.c51
-rw-r--r--multiload/src/autoscaler.h26
-rw-r--r--multiload/src/global.h164
-rw-r--r--multiload/src/linux-proc.c442
-rw-r--r--multiload/src/linux-proc.h13
-rw-r--r--multiload/src/load-graph.c501
-rw-r--r--multiload/src/load-graph.h24
-rw-r--r--multiload/src/main.c573
-rw-r--r--multiload/src/netspeed.c70
-rw-r--r--multiload/src/netspeed.h15
-rw-r--r--multiload/src/properties.c868
12 files changed, 2776 insertions, 0 deletions
diff --git a/multiload/src/Makefile.am b/multiload/src/Makefile.am
new file mode 100644
index 00000000..ab0ab6fd
--- /dev/null
+++ b/multiload/src/Makefile.am
@@ -0,0 +1,29 @@
+AM_CPPFLAGS = \
+ -I$(srcdir) \
+ -DMULTILOAD_MENU_UI_DIR=\""$(datadir)/mate/ui/"\" \
+ $(MATE_APPLETS4_CFLAGS) \
+ $(GTOP_APPLETS_CFLAGS) \
+ $(GIO_CFLAGS) \
+ ${WARN_CFLAGS}
+
+libexec_PROGRAMS = mate-multiload-applet
+
+mate_multiload_applet_SOURCES = \
+ global.h \
+ linux-proc.h \
+ load-graph.h \
+ linux-proc.c \
+ load-graph.c \
+ main.c \
+ properties.c \
+ netspeed.c netspeed.h \
+ autoscaler.c \
+ autoscaler.h
+
+mate_multiload_applet_LDADD = \
+ $(MATE_APPLETS4_LIBS) \
+ $(GTOP_APPLETS_LIBS) \
+ $(GIO_LIBS) \
+ -lm
+
+-include $(top_srcdir)/git.mk
diff --git a/multiload/src/autoscaler.c b/multiload/src/autoscaler.c
new file mode 100644
index 00000000..735b2713
--- /dev/null
+++ b/multiload/src/autoscaler.c
@@ -0,0 +1,51 @@
+#include <time.h>
+#include <glib.h>
+
+#include "autoscaler.h"
+
+/* i wish i could have used C99 initializers instead of writing this function */
+void autoscaler_init(AutoScaler *that, unsigned interval, unsigned floor)
+{
+ that->update_interval = interval;
+ that->floor = floor;
+ that->max = 0;
+ that->count = 0;
+ that->last_update = 0;
+ that->sum = 0.0f;
+ that->last_average = 0.0f;
+}
+
+
+unsigned autoscaler_get_max(AutoScaler *that, unsigned current)
+{
+ time_t now;
+
+ that->sum += current;
+ that->count++;
+ time(&now);
+
+ if((float)difftime(now, that->last_update) > that->update_interval)
+ {
+ float new_average = that->sum / that->count;
+ float average;
+
+ if(new_average < that->last_average)
+ average = ((that->last_average * 0.5f) + new_average) / 1.5f;
+ else
+ average = new_average;
+
+ that->max = average * 1.2f;
+
+ that->sum = 0.0f;
+ that->count = 0;
+ that->last_update = now;
+ that->last_average = average;
+ }
+
+ that->max = MAX(that->max, current);
+ that->max = MAX(that->max, that->floor);
+#if 0
+ printf("%p max = %u, current = %u, last_average = %f\n", that, that->max, current, that->last_average);
+#endif
+ return that->max;
+}
diff --git a/multiload/src/autoscaler.h b/multiload/src/autoscaler.h
new file mode 100644
index 00000000..d0ae4cd6
--- /dev/null
+++ b/multiload/src/autoscaler.h
@@ -0,0 +1,26 @@
+#ifndef MATE_APPLETS_MULTILOAD_AUTOSCALER_H
+#define MATE_APPLETS_MULTILOAD_AUTOSCALER_H
+
+#include <glib.h>
+#include <time.h>
+
+typedef struct _AutoScaler AutoScaler;
+
+struct _AutoScaler
+{
+ /* const */ unsigned update_interval;
+ /* const */ unsigned floor;
+ unsigned max;
+ unsigned count;
+ time_t last_update;
+ float sum;
+ float last_average;
+};
+
+
+G_GNUC_INTERNAL void autoscaler_init(AutoScaler *that, unsigned interval, unsigned floor);
+
+G_GNUC_INTERNAL unsigned autoscaler_get_max(AutoScaler *that, unsigned current);
+
+
+#endif /* MATE_APPLETS_MULTILOAD_AUTOSCALER_H */
diff --git a/multiload/src/global.h b/multiload/src/global.h
new file mode 100644
index 00000000..da3383c4
--- /dev/null
+++ b/multiload/src/global.h
@@ -0,0 +1,164 @@
+#ifndef __GLOBAL_H__
+#define __GLOBAL_H__
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+#include <mate-panel-applet.h>
+
+G_BEGIN_DECLS
+
+#define MIN_NET_THRESHOLD1 10
+#define MIN_NET_THRESHOLD2 11
+#define MIN_NET_THRESHOLD3 12
+#define MAX_NET_THRESHOLD1 999999998
+#define MAX_NET_THRESHOLD2 999999999
+#define MAX_NET_THRESHOLD3 1000000000
+
+#define VIEW_CPULOAD_KEY "view-cpuload"
+#define VIEW_MEMLOAD_KEY "view-memload"
+#define VIEW_NETLOAD_KEY "view-netload"
+#define VIEW_SWAPLOAD_KEY "view-swapload"
+#define VIEW_LOADAVG_KEY "view-loadavg"
+#define VIEW_DISKLOAD_KEY "view-diskload"
+
+typedef struct _MultiloadApplet MultiloadApplet;
+typedef struct _LoadGraph LoadGraph;
+typedef void (*LoadGraphDataFunc) (int, int [], LoadGraph *);
+
+#include "netspeed.h"
+
+typedef enum {
+ graph_cpuload = 0,
+ graph_memload,
+ graph_netload2,
+ graph_swapload,
+ graph_loadavg,
+ graph_diskload,
+ graph_n,
+} E_graph;
+
+typedef enum {
+ memload_user = 0,
+ memload_shared,
+ memload_buffer,
+ memload_cached,
+ memload_free,
+ memload_n
+} E_memload;
+
+typedef enum {
+ cpuload_usr = 0,
+ cpuload_sys,
+ cpuload_nice,
+ cpuload_iowait,
+ cpuload_free,
+ cpuload_n
+} E_cpuload;
+
+typedef enum {
+ diskload_read = 0,
+ diskload_write,
+ diskload_free,
+ diskload_n
+} E_diskload;
+
+typedef enum {
+ swapload_used = 0,
+ swapload_free,
+ swapload_n
+} E_swapload;
+
+struct _LoadGraph {
+ MultiloadApplet *multiload;
+
+ guint n, id;
+ guint speed, size;
+ guint orient, pixel_size;
+ guint draw_width, draw_height;
+ LoadGraphDataFunc get_data;
+
+ guint allocated;
+
+ GdkRGBA *colors;
+ gint **data;
+ guint data_size;
+ guint *pos;
+
+ GtkWidget *main_widget;
+ GtkWidget *frame, *box, *disp;
+ cairo_surface_t *surface;
+ int timer_index;
+
+ gboolean visible;
+ gboolean tooltip_update;
+ const gchar *name;
+};
+
+struct _MultiloadApplet
+{
+ MatePanelApplet *applet;
+
+ GSettings *settings;
+
+ LoadGraph *graphs [graph_n];
+
+ GtkWidget *box;
+
+ gboolean view_cpuload;
+ gboolean view_memload;
+ gboolean view_netload;
+ gboolean view_swapload;
+ gboolean view_loadavg;
+ gboolean view_diskload;
+
+ GtkWidget *about_dialog;
+ GtkWidget *check_boxes [graph_n];
+ GtkWidget *prop_dialog;
+ GtkWidget *notebook;
+ int last_clicked;
+
+ float cpu_used_ratio;
+ long cpu_time [cpuload_n];
+ long cpu_last [cpuload_n];
+ int cpu_initialized;
+
+ double loadavg1;
+
+ guint64 memload_user;
+ guint64 memload_cache;
+ guint64 memload_total;
+
+ float swapload_used_ratio;
+
+ float diskload_used_ratio;
+ gboolean nvme_diskstats;
+
+ NetSpeed *netspeed_in;
+ NetSpeed *netspeed_out;
+ guint net_threshold1;
+ guint net_threshold2;
+ guint net_threshold3;
+};
+
+#include "load-graph.h"
+#include "linux-proc.h"
+
+/* show properties dialog */
+G_GNUC_INTERNAL void
+multiload_properties_cb (GtkAction *action,
+ MultiloadApplet *ma);
+
+/* remove the old graphs and rebuild them */
+G_GNUC_INTERNAL void
+multiload_applet_refresh (MultiloadApplet *ma);
+
+/* update the tooltip to the graph's current "used" percentage */
+G_GNUC_INTERNAL void
+multiload_applet_tooltip_update (LoadGraph *g);
+
+G_END_DECLS
+
+#endif
diff --git a/multiload/src/linux-proc.c b/multiload/src/linux-proc.c
new file mode 100644
index 00000000..6059e9e3
--- /dev/null
+++ b/multiload/src/linux-proc.c
@@ -0,0 +1,442 @@
+/* From wmload.c, v0.9.2, licensed under the GPL. */
+#include <config.h>
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#include <math.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <glibtop.h>
+#include <glibtop/cpu.h>
+#include <glibtop/mem.h>
+#include <glibtop/swap.h>
+#include <glibtop/loadavg.h>
+#include <glibtop/netload.h>
+#include <glibtop/netlist.h>
+#include <glibtop/mountlist.h>
+#include <glibtop/fsusage.h>
+
+#include "linux-proc.h"
+#include "autoscaler.h"
+
+static const unsigned needed_cpu_flags =
+(1 << GLIBTOP_CPU_USER) +
+(1 << GLIBTOP_CPU_IDLE) +
+(1 << GLIBTOP_CPU_SYS) +
+(1 << GLIBTOP_CPU_NICE);
+
+#if 0
+static const unsigned needed_page_flags =
+(1 << GLIBTOP_SWAP_PAGEIN) +
+(1 << GLIBTOP_SWAP_PAGEOUT);
+#endif
+
+static const unsigned needed_mem_flags =
+(1 << GLIBTOP_MEM_USED) +
+(1 << GLIBTOP_MEM_FREE);
+
+static const unsigned needed_swap_flags =
+(1 << GLIBTOP_SWAP_USED) +
+(1 << GLIBTOP_SWAP_FREE);
+
+static const unsigned needed_loadavg_flags =
+(1 << GLIBTOP_LOADAVG_LOADAVG);
+
+static const unsigned needed_netload_flags =
+(1 << GLIBTOP_NETLOAD_IF_FLAGS) +
+(1 << GLIBTOP_NETLOAD_BYTES_TOTAL);
+
+void
+GetLoad (int Maximum,
+ int data [cpuload_n],
+ LoadGraph *g)
+{
+ MultiloadApplet *multiload;
+ glibtop_cpu cpu;
+ long cpu_aux [cpuload_n], used = 0, total = 0;
+ int current_scaled, used_scaled = 0;
+ int i;
+
+ glibtop_get_cpu (&cpu);
+
+ g_return_if_fail ((cpu.flags & needed_cpu_flags) == needed_cpu_flags);
+
+ multiload = g->multiload;
+
+ multiload->cpu_time [cpuload_usr] = cpu.user;
+ multiload->cpu_time [cpuload_nice] = cpu.nice;
+ multiload->cpu_time [cpuload_sys] = cpu.sys;
+ multiload->cpu_time [cpuload_iowait] = cpu.iowait + cpu.irq + cpu.softirq;
+ multiload->cpu_time [cpuload_free] = cpu.idle;
+
+ if (!multiload->cpu_initialized) {
+ memcpy (multiload->cpu_last, multiload->cpu_time, sizeof (multiload->cpu_last));
+ multiload->cpu_initialized = 1;
+ }
+
+ for (i = 0; i < cpuload_n; i++) {
+ cpu_aux [i] = multiload->cpu_time [i] - multiload->cpu_last [i];
+ total += cpu_aux [i];
+ }
+
+ for (i = 0; i < cpuload_free; i++) {
+ used += cpu_aux [i];
+ current_scaled = rint ((float)(cpu_aux [i] * Maximum) / (float)total);
+ used_scaled += current_scaled;
+ data [i] = current_scaled;
+ }
+ data [cpuload_free] = Maximum - used_scaled;
+
+ multiload->cpu_used_ratio = (float)(used) / (float)total;
+
+ memcpy (multiload->cpu_last, multiload->cpu_time, sizeof multiload->cpu_last);
+}
+
+void
+GetDiskLoad (int Maximum,
+ int data [diskload_n],
+ LoadGraph *g)
+{
+ static gboolean first_call = TRUE;
+ static guint64 lastread = 0, lastwrite = 0;
+ static AutoScaler scaler;
+
+ guint i;
+ int max;
+
+ guint64 read, write;
+ guint64 readdiff, writediff;
+
+ MultiloadApplet *multiload;
+
+ multiload = g->multiload;
+
+
+ if(first_call)
+ {
+ autoscaler_init(&scaler, 60, 500);
+ }
+
+ read = write = 0;
+
+ if (multiload->nvme_diskstats)
+ {
+ FILE *fdr;
+ char line[255];
+ guint64 s_read, s_write;
+
+ fdr = fopen("/proc/diskstats", "r");
+ if (!fdr)
+ {
+ multiload->nvme_diskstats = FALSE;
+ g_settings_set_boolean (multiload->settings, "diskload-nvme-diskstats", FALSE);
+ return;
+ }
+
+ while (fgets(line, 255, fdr))
+ {
+ /* Match main device, rather than individual partitions (e.g. nvme0n1) */
+ if (!g_regex_match_simple("\\snvme\\d+\\w+\\d+\\s", line, 0, 0))
+ {
+ continue;
+ }
+
+ /*
+ 6 - sectors read
+ 10 - sectors written
+ */
+ if (sscanf(line, "%*d %*d %*s %*d %*d %ld %*d %*d %*d %ld", &s_read, &s_write) == 2)
+ {
+ read += 512 * s_read;
+ write += 512 * s_write;
+ }
+ }
+ fclose(fdr);
+ }
+ else
+ {
+ glibtop_mountlist mountlist;
+ glibtop_mountentry *mountentries;
+
+ mountentries = glibtop_get_mountlist (&mountlist, FALSE);
+
+ for (i = 0; i < mountlist.number; i++)
+ {
+ struct statvfs statresult;
+ glibtop_fsusage fsusage;
+
+ if (strstr (mountentries[i].devname, "/dev/") == NULL)
+ continue;
+
+ if (strstr (mountentries[i].mountdir, "/media/") != NULL)
+ continue;
+
+ if (statvfs (mountentries[i].mountdir, &statresult) < 0)
+ {
+ g_debug ("Failed to get statistics for mount entry: %s. Reason: %s. Skipping entry.",
+ mountentries[i].mountdir, strerror(errno));
+ continue;
+ }
+
+ glibtop_get_fsusage(&fsusage, mountentries[i].mountdir);
+ read += fsusage.read; write += fsusage.write;
+ }
+
+ g_free(mountentries);
+ }
+
+ readdiff = read - lastread;
+ writediff = write - lastwrite;
+
+ lastread = read;
+ lastwrite = write;
+
+ if(first_call)
+ {
+ first_call = FALSE;
+ memset(data, 0, 3 * sizeof data[0]);
+ return;
+ }
+
+ max = autoscaler_get_max(&scaler, readdiff + writediff);
+
+ multiload->diskload_used_ratio = (float)(readdiff + writediff) / (float)max;
+
+ data [diskload_read] = rint ((float)Maximum * (float)readdiff / (float)max);
+ data [diskload_write] = rint ((float)Maximum * (float)writediff / (float)max);
+ data [diskload_free] = Maximum - (data [0] + data[1]);
+}
+
+/* GNU/Linux:
+ * aux [memload_user] = (mem.total - mem.free) - (mem.cached + mem.buffer)
+ * aux [memload_shared] = mem.shared;
+ * aux [memload_cached] = mem.cached - mem.shared;
+ * aux [memload_buffer] = mem.buffer;
+ *
+ * Other operating systems:
+ * aux [memload_user] = mem.user;
+ * aux [memload_shared] = mem.shared;
+ * aux [memload_cached] = mem.cached;
+ * aux [memload_buffer] = mem.buffer;
+ */
+void
+GetMemory (int Maximum,
+ int data [memload_n],
+ LoadGraph *g)
+{
+ MultiloadApplet *multiload;
+ glibtop_mem mem;
+ guint64 aux [memload_n], cache = 0;
+ int current_scaled, used_scaled = 0;
+ int i;
+
+ glibtop_get_mem (&mem);
+
+ g_return_if_fail ((mem.flags & needed_mem_flags) == needed_mem_flags);
+
+#ifndef __linux__
+ aux [memload_user] = mem.user;
+ aux [memload_cached] = mem.cached;
+#else
+ aux [memload_user] = mem.total - mem.free - mem.buffer - mem.cached;;
+ aux [memload_cached] = mem.cached - mem.shared;
+#endif /* __linux__ */
+ aux [memload_shared] = mem.shared;
+ aux [memload_buffer] = mem.buffer;
+
+ for (i = 0; i < memload_free; i++) {
+ current_scaled = rint ((float)(aux [i] * Maximum) / (float)mem.total);
+ if (i != memload_user) {
+ cache += aux [i];
+ }
+ used_scaled += current_scaled;
+ data [i] = current_scaled;
+ }
+ data [memload_free] = MAX (Maximum - used_scaled, 0);
+
+ multiload = g->multiload;
+ multiload->memload_user = aux [memload_user];
+ multiload->memload_cache = cache;
+ multiload->memload_total = mem.total;
+}
+
+void
+GetSwap (int Maximum,
+ int data [swapload_n],
+ LoadGraph *g)
+{
+ int used;
+ MultiloadApplet *multiload;
+ glibtop_swap swap;
+
+ glibtop_get_swap (&swap);
+ g_return_if_fail ((swap.flags & needed_swap_flags) == needed_swap_flags);
+
+ multiload = g->multiload;
+
+ if (swap.total == 0) {
+ used = 0;
+ multiload->swapload_used_ratio = 0.0f;
+ }
+ else {
+ float ratio;
+
+ ratio = (float)swap.used / (float)swap.total;
+ used = rint ((float) Maximum * ratio);
+ multiload->swapload_used_ratio = ratio;
+ }
+
+ data [0] = used;
+ data [1] = Maximum - used;
+}
+
+void
+GetLoadAvg (int Maximum,
+ int data [2],
+ LoadGraph *g)
+{
+ glibtop_loadavg loadavg;
+ MultiloadApplet *multiload;
+
+ glibtop_get_loadavg (&loadavg);
+
+ g_return_if_fail ((loadavg.flags & needed_loadavg_flags) == needed_loadavg_flags);
+
+ multiload = g->multiload;
+ multiload->loadavg1 = loadavg.loadavg[0];
+
+ data [0] = rint ((float) Maximum * loadavg.loadavg[0]);
+ data [1] = Maximum - data[0];
+}
+
+/*
+ * Return true if a network device (identified by its name) is virtual
+ * (ie: not corresponding to a physical device). In case it is a physical
+ * device or unknown, returns false.
+ */
+static gboolean
+is_net_device_virtual(char *device)
+{
+ /*
+ * There is not definitive way to find out. On some systems (Linux
+ * kernels ≳ 2.19 without option SYSFS_DEPRECATED), there exist a
+ * directory /sys/devices/virtual/net which only contains virtual
+ * devices. It's also possible to detect by the fact that virtual
+ * devices do not have a symlink "device" in
+ * /sys/class/net/name-of-dev/ . This second method is more complex
+ * but more reliable.
+ */
+ gboolean ret = FALSE;
+ char *path = malloc (strlen (device) + strlen ("/sys/class/net//device") + 1);
+
+ if (path == NULL)
+ return FALSE;
+
+ /* Check if /sys/class/net/name-of-dev/ exists (may be old linux kernel
+ * or not linux at all). */
+ do {
+ if (sprintf(path, "/sys/class/net/%s", device) < 0)
+ break;
+ if (access(path, F_OK) != 0)
+ break; /* unknown */
+
+ if (sprintf(path, "/sys/class/net/%s/device", device) < 0)
+ break;
+ if (access(path, F_OK) != 0)
+ ret = TRUE;
+ } while (0);
+
+ free (path);
+ return ret;
+}
+
+void
+GetNet (int Maximum,
+ int data [4],
+ LoadGraph *g)
+{
+ enum Types {
+ IN_COUNT = 0,
+ OUT_COUNT = 1,
+ LOCAL_COUNT = 2,
+ COUNT_TYPES = 3
+ };
+
+ static int ticks = 0;
+ static gulong past[COUNT_TYPES] = {0};
+ static AutoScaler scaler;
+
+ gulong present[COUNT_TYPES] = {0};
+
+ guint i;
+ gchar **devices;
+ glibtop_netlist netlist;
+
+ MultiloadApplet *multiload;
+
+ multiload = g->multiload;
+
+ if(ticks == 0)
+ {
+ autoscaler_init(&scaler, 60, 501);
+ }
+
+ devices = glibtop_get_netlist(&netlist);
+
+ for(i = 0; i < netlist.number; ++i)
+ {
+ glibtop_netload netload;
+
+ glibtop_get_netload(&netload, devices[i]);
+
+ g_return_if_fail((netload.flags & needed_netload_flags) == needed_netload_flags);
+
+ if (!(netload.if_flags & (1L << GLIBTOP_IF_FLAGS_UP)))
+ continue;
+
+ if (netload.if_flags & (1L << GLIBTOP_IF_FLAGS_LOOPBACK)) {
+ /* for loopback in and out are identical, so only count in */
+ present[LOCAL_COUNT] += netload.bytes_in;
+ continue;
+ }
+
+ /*
+ * Do not include virtual devices (VPN, PPPOE...) to avoid
+ * counting the same throughput several times.
+ */
+ if (is_net_device_virtual(devices[i]))
+ continue;
+
+ present[IN_COUNT] += netload.bytes_in;
+ present[OUT_COUNT] += netload.bytes_out;
+ }
+
+ g_strfreev(devices);
+ netspeed_add (multiload->netspeed_in, present[IN_COUNT]);
+ netspeed_add (multiload->netspeed_out, present[OUT_COUNT]);
+
+ if(ticks < 2) /* avoid initial spike */
+ {
+ ticks++;
+ memset(data, 0, COUNT_TYPES * sizeof data[0]);
+ }
+ else
+ {
+ int delta[COUNT_TYPES];
+
+ for (i = 0; i < COUNT_TYPES; i++)
+ {
+ /* protect against weirdness */
+ if (present[i] >= past[i])
+ delta[i] = (present[i] - past[i]);
+ else
+ delta[i] = 0;
+ }
+
+ for (i = 0; i < COUNT_TYPES; i++)
+ data[i] = delta[i];
+
+ }
+
+ memcpy(past, present, sizeof past);
+}
diff --git a/multiload/src/linux-proc.h b/multiload/src/linux-proc.h
new file mode 100644
index 00000000..0aba1a0e
--- /dev/null
+++ b/multiload/src/linux-proc.h
@@ -0,0 +1,13 @@
+#ifndef LINUX_PROC_H__
+#define LINUX_PROC_H__
+
+#include <load-graph.h>
+
+G_GNUC_INTERNAL void GetLoad (int Maximum, int data [cpuload_n], LoadGraph *g);
+G_GNUC_INTERNAL void GetDiskLoad (int Maximum, int data [diskload_n], LoadGraph *g);
+G_GNUC_INTERNAL void GetMemory (int Maximum, int data [memload_n], LoadGraph *g);
+G_GNUC_INTERNAL void GetSwap (int Maximum, int data [swapload_n], LoadGraph *g);
+G_GNUC_INTERNAL void GetLoadAvg (int Maximum, int data [2], LoadGraph *g);
+G_GNUC_INTERNAL void GetNet (int Maximum, int data [4], LoadGraph *g);
+
+#endif
diff --git a/multiload/src/load-graph.c b/multiload/src/load-graph.c
new file mode 100644
index 00000000..953dc5b2
--- /dev/null
+++ b/multiload/src/load-graph.c
@@ -0,0 +1,501 @@
+#include <config.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <signal.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+#include <glib.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+#include <gio/gio.h>
+#include <mate-panel-applet.h>
+#include <mate-panel-applet-gsettings.h>
+#include <math.h>
+
+#include "global.h"
+
+/*
+ Shifts data right
+
+ data[i+1] = data[i]
+
+ data[i] are int*, so we just move the pointer, not the data.
+ But moving data loses data[n-1], so we save data[n-1] and reuse
+ it as new data[0]. In fact, we rotate data[].
+
+*/
+
+static void
+shift_right(LoadGraph *g)
+{
+ unsigned i;
+ int* last_data;
+
+ /* data[g->draw_width - 1] becomes data[0] */
+ last_data = g->data[g->draw_width - 1];
+
+ /* data[i+1] = data[i] */
+ for(i = g->draw_width - 1; i != 0; --i)
+ g->data[i] = g->data[i - 1];
+
+ g->data[0] = last_data;
+}
+
+
+/* Redraws the backing pixmap for the load graph and updates the window */
+static void
+load_graph_draw (LoadGraph *g)
+{
+ guint i, j, k;
+ cairo_t *cr;
+ int load;
+ MultiloadApplet *multiload;
+
+ multiload = g->multiload;
+
+ /* we might get called before the configure event so that
+ * g->disp->allocation may not have the correct size
+ * (after the user resized the applet in the prop dialog). */
+
+ if (!g->surface)
+ g->surface = gdk_window_create_similar_surface (gtk_widget_get_window (g->disp),
+ CAIRO_CONTENT_COLOR,
+ g->draw_width, g->draw_height);
+
+ cr = cairo_create (g->surface);
+ cairo_set_line_width (cr, 1.0);
+ cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
+ cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
+
+ /* all graphs except Load and Net go this path */
+ if (g->id != graph_loadavg && g->id != graph_netload2)
+ {
+ for (i = 0; i < g->draw_width; i++)
+ g->pos [i] = g->draw_height - 1;
+
+ for (j = 0; j < g->n; j++)
+ {
+ gdk_cairo_set_source_rgba (cr, &(g->colors [j]));
+
+ for (i = 0; i < g->draw_width; i++)
+ {
+ if (g->data [i][j] != 0)
+ {
+ cairo_move_to (cr, g->draw_width - i - 0.5, g->pos[i] + 0.5);
+ cairo_line_to (cr, g->draw_width - i - 0.5, g->pos[i] - (g->data [i][j] - 0.5));
+ }
+ g->pos [i] -= g->data [i][j];
+ }
+ cairo_stroke (cr);
+ }
+ }
+ /* This is for network graph */
+ else if (g->id == graph_netload2)
+ {
+ guint maxnet = 1;
+ gint segments = 1;
+ gint combined;
+ guint net_threshold;
+
+ for (i = 0; i < g->draw_width; i++)
+ {
+ g->pos [i] = g->draw_height - 1;
+ combined = g->data[i][0] +
+ g->data[i][1] +
+ g->data[i][2];
+ if (combined > maxnet)
+ maxnet = combined;
+ }
+ //printf("max = %d ", maxnet);
+ guint level = 0;
+ if (maxnet > multiload->net_threshold3) {
+ net_threshold = multiload->net_threshold3;
+ level = 3;
+ }
+ else
+ if (maxnet > multiload->net_threshold2) {
+ net_threshold = multiload->net_threshold2;
+ level = 2;
+ }
+ else {
+ net_threshold = multiload->net_threshold1;
+ level = 1;
+ if (maxnet < multiload->net_threshold1)
+ level = 0;
+ }
+
+ //printf("level %d maxnet = %d ", level, maxnet);
+ maxnet = maxnet/net_threshold;
+ segments = MAX (maxnet+1,1);
+ float ratio = (float)g->draw_height/net_threshold/segments;
+ //printf("segments %d ratio = %f t1=%ld t2=%ld t3=%ld t=%ld\n", segments, ratio, multiload->net_threshold1, multiload->net_threshold2, multiload->net_threshold3, multiload->net_threshold);
+
+ for (j = 0; j < g->n-1; j++)
+ {
+ gdk_cairo_set_source_rgba (cr, &(g->colors [j]));
+
+ for (i = 0; i < g->draw_width; i++)
+ {
+ cairo_move_to (cr, g->draw_width - i - 0.5, g->pos[i] + 0.5);
+ cairo_line_to (cr, g->draw_width - i - 0.5, g->pos[i] - 0.5 - ((g->data [i][j] * ratio)));
+ g->pos [i] -= ((g->data [i][j] * ratio));
+ }
+ cairo_stroke (cr);
+ }
+
+ for (j = g->n-1; j < g->n; j++)
+ {
+ gdk_cairo_set_source_rgba (cr, &(g->colors [j]));
+ for (i = 0; i < g->draw_width; i++)
+ {
+ cairo_move_to (cr, g->draw_width - i - 0.5, g->pos[i] + 0.5);
+ cairo_line_to (cr, g->draw_width - i - 0.5, 0.5);
+ }
+ cairo_stroke (cr);
+ }
+
+ /* draw grid lines if needed */
+ gdk_cairo_set_source_rgba (cr, &(g->colors [4]));
+ double spacing;
+ for (k = 0; k < segments -1; k++)
+ {
+ spacing = ((double) g->draw_height/segments) * (k+1);
+ cairo_move_to (cr, 0.5, spacing);
+ cairo_line_to (cr, g->draw_width-0.5, spacing);
+ }
+ cairo_stroke (cr);
+ /* draw indicator if needed */
+ if (level > 0)
+ {
+ gdk_cairo_set_source_rgba (cr, &(g->colors [5]));
+ for (k = 0; k< level; k++ )
+ cairo_rectangle(cr, 0.5, (k*2) * g->draw_height/5, 5, g->draw_height/5);
+ cairo_fill(cr);
+ }
+ cairo_stroke (cr);
+ }
+ /* this is Load graph */
+ else
+ {
+ guint maxload = 1;
+ for (i = 0; i < g->draw_width; i++)
+ {
+ g->pos [i] = g->draw_height - 1;
+ /* find maximum value */
+ if (g->data[i][0] > maxload)
+ maxload = g->data[i][0];
+ }
+ load = ceil ((double) (maxload/g->draw_height)) + 1;
+ load = MAX (load,1);
+
+ for (j = 0; j < g->n; j++)
+ {
+ gdk_cairo_set_source_rgba (cr, &(g->colors [j]));
+
+ for (i = 0; i < g->draw_width; i++)
+ {
+ cairo_move_to (cr, g->draw_width - i - 0.5, g->pos[i] + 0.5);
+ if (j == 0)
+ {
+ cairo_line_to (cr, g->draw_width - i - 0.5, g->pos[i] - ((g->data [i][j] - 0.5)/load));
+ }
+ else
+ {
+ cairo_line_to (cr, g->draw_width - i - 0.5, 0.5);
+ }
+ g->pos [i] -= g->data [i][j] / load;
+ }
+ cairo_stroke (cr);
+ }
+
+ /* draw grid lines in Load graph if needed */
+ gdk_cairo_set_source_rgba (cr, &(g->colors [2]));
+
+ double spacing;
+ for (k = 0; k < load - 1; k++)
+ {
+ spacing = ((double) g->draw_height/load) * (k+1);
+ cairo_move_to (cr, 0.5, spacing);
+ cairo_line_to (cr, g->draw_width-0.5, spacing);
+ }
+
+ cairo_stroke (cr);
+ }
+ gtk_widget_queue_draw (g->disp);
+
+ cairo_destroy (cr);
+}
+
+/* Updates the load graph when the timeout expires */
+static gboolean
+load_graph_update (LoadGraph *g)
+{
+ if (g->data == NULL)
+ return TRUE;
+
+ shift_right(g);
+
+ if (g->tooltip_update)
+ multiload_applet_tooltip_update(g);
+
+ g->get_data (g->draw_height, g->data [0], g);
+
+ load_graph_draw (g);
+ return TRUE;
+}
+
+void
+load_graph_unalloc (LoadGraph *g)
+{
+ guint i;
+
+ if (!g->allocated)
+ return;
+
+ for (i = 0; i < g->draw_width; i++)
+ {
+ g_free (g->data [i]);
+ }
+
+ g_free (g->data);
+ g_free (g->pos);
+
+ g->pos = NULL;
+ g->data = NULL;
+
+ g->size = g_settings_get_int(g->multiload->settings, "size");
+ g->size = MAX (g->size, 10);
+
+ if (g->surface) {
+ cairo_surface_destroy (g->surface);
+ g->surface = NULL;
+ }
+
+ g->allocated = FALSE;
+}
+
+static void
+load_graph_alloc (LoadGraph *g)
+{
+ guint i;
+
+ if (g->allocated)
+ return;
+
+ g->data = g_new0 (gint *, g->draw_width);
+ g->pos = g_new0 (guint, g->draw_width);
+
+ g->data_size = sizeof (guint) * g->n;
+
+ for (i = 0; i < g->draw_width; i++) {
+ g->data [i] = g_malloc0 (g->data_size);
+ }
+
+ g->allocated = TRUE;
+}
+
+static gint
+load_graph_configure (GtkWidget *widget, GdkEventConfigure *event,
+ gpointer data_ptr)
+{
+ GtkAllocation allocation;
+ LoadGraph *c = (LoadGraph *) data_ptr;
+
+ load_graph_unalloc (c);
+
+ gtk_widget_get_allocation (c->disp, &allocation);
+
+ c->draw_width = allocation.width;
+ c->draw_height = allocation.height;
+ c->draw_width = MAX (c->draw_width, 1);
+ c->draw_height = MAX (c->draw_height, 1);
+
+ load_graph_alloc (c);
+
+ if (!c->surface)
+ c->surface = gdk_window_create_similar_surface (gtk_widget_get_window (c->disp),
+ CAIRO_CONTENT_COLOR,
+ c->draw_width, c->draw_height);
+ gtk_widget_queue_draw (widget);
+
+ return TRUE;
+}
+
+static gint
+load_graph_expose (GtkWidget *widget,
+ cairo_t *cr,
+ gpointer data_ptr)
+{
+ LoadGraph *g = (LoadGraph *) data_ptr;
+
+ cairo_set_source_surface (cr, g->surface, 0, 0);
+ cairo_paint (cr);
+
+ return FALSE;
+}
+
+static void
+load_graph_destroy (GtkWidget *widget, gpointer data_ptr)
+{
+ LoadGraph *g = (LoadGraph *) data_ptr;
+
+ load_graph_stop (g);
+
+ gtk_widget_destroy(widget);
+}
+
+static gboolean
+load_graph_clicked (GtkWidget *widget, GdkEventButton *event, LoadGraph *load)
+{
+ load->multiload->last_clicked = load->id;
+
+ return FALSE;
+}
+
+static gboolean
+load_graph_enter_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data)
+{
+ LoadGraph *graph;
+ graph = (LoadGraph *)data;
+
+ graph->tooltip_update = TRUE;
+ multiload_applet_tooltip_update(graph);
+
+ return TRUE;
+}
+
+static gboolean
+load_graph_leave_cb(GtkWidget *widget, GdkEventCrossing *event, gpointer data)
+{
+ LoadGraph *graph;
+ graph = (LoadGraph *)data;
+
+ graph->tooltip_update = FALSE;
+
+ return TRUE;
+}
+
+static void
+load_graph_load_config (LoadGraph *g)
+{
+ gchar *name, *temp;
+ guint i;
+
+ if (!g->colors)
+ g->colors = g_new0(GdkRGBA, g->n);
+
+ for (i = 0; i < g->n; i++)
+ {
+ name = g_strdup_printf ("%s-color%u", g->name, i);
+ temp = g_settings_get_string(g->multiload->settings, name);
+ if (!temp)
+ temp = g_strdup ("#000000");
+ gdk_rgba_parse(&(g->colors[i]), temp);
+ g_free(temp);
+ g_free(name);
+ }
+}
+
+LoadGraph *
+load_graph_new (MultiloadApplet *ma, guint n, const gchar *label,
+ guint id, guint speed, guint size, gboolean visible,
+ const gchar *name, LoadGraphDataFunc get_data)
+{
+ LoadGraph *g;
+ MatePanelAppletOrient orient;
+
+ g = g_new0 (LoadGraph, 1);
+ g->visible = visible;
+ g->name = name;
+ g->n = n;
+ g->id = id;
+ g->speed = MAX (speed, 50);
+ g->size = MAX (size, 10);
+ g->pixel_size = mate_panel_applet_get_size (ma->applet);
+ g->tooltip_update = FALSE;
+ g->multiload = ma;
+
+ g->main_widget = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+
+ g->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+
+ orient = mate_panel_applet_get_orient (g->multiload->applet);
+ switch (orient)
+ {
+ case MATE_PANEL_APPLET_ORIENT_UP:
+ case MATE_PANEL_APPLET_ORIENT_DOWN:
+ {
+ g->orient = FALSE;
+ break;
+ }
+ case MATE_PANEL_APPLET_ORIENT_LEFT:
+ case MATE_PANEL_APPLET_ORIENT_RIGHT:
+ {
+ g->orient = TRUE;
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+
+ g->frame = gtk_frame_new (NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (g->frame), GTK_SHADOW_IN);
+ gtk_container_add (GTK_CONTAINER (g->frame), g->box);
+ gtk_box_pack_start (GTK_BOX (g->main_widget), g->frame, TRUE, TRUE, 0);
+
+ load_graph_load_config (g);
+
+ g->get_data = get_data;
+
+ g->timer_index = -1;
+
+ if (g->orient)
+ gtk_widget_set_size_request (g->main_widget, -1, g->size);
+ else
+ gtk_widget_set_size_request (g->main_widget, g->size, -1);
+
+ g->disp = gtk_drawing_area_new ();
+ gtk_widget_set_events (g->disp, GDK_EXPOSURE_MASK |
+ GDK_ENTER_NOTIFY_MASK |
+ GDK_LEAVE_NOTIFY_MASK |
+ GDK_BUTTON_PRESS_MASK);
+
+ g_signal_connect (G_OBJECT (g->disp), "draw",
+ G_CALLBACK (load_graph_expose), g);
+ g_signal_connect (G_OBJECT(g->disp), "configure_event",
+ G_CALLBACK (load_graph_configure), g);
+ g_signal_connect (G_OBJECT(g->disp), "destroy",
+ G_CALLBACK (load_graph_destroy), g);
+ g_signal_connect (G_OBJECT(g->disp), "button-press-event",
+ G_CALLBACK (load_graph_clicked), g);
+ g_signal_connect (G_OBJECT(g->disp), "enter-notify-event",
+ G_CALLBACK(load_graph_enter_cb), g);
+ g_signal_connect (G_OBJECT(g->disp), "leave-notify-event",
+ G_CALLBACK(load_graph_leave_cb), g);
+
+ gtk_box_pack_start (GTK_BOX (g->box), g->disp, TRUE, TRUE, 0);
+ gtk_widget_show_all(g->box);
+
+ return g;
+}
+
+void
+load_graph_start (LoadGraph *g)
+{
+ if (g->timer_index != -1)
+ g_source_remove (g->timer_index);
+
+ g->timer_index = g_timeout_add (g->speed,
+ (GSourceFunc) load_graph_update, g);
+}
+
+void
+load_graph_stop (LoadGraph *g)
+{
+ if (g->timer_index != -1)
+ g_source_remove (g->timer_index);
+
+ g->timer_index = -1;
+}
diff --git a/multiload/src/load-graph.h b/multiload/src/load-graph.h
new file mode 100644
index 00000000..76effcd6
--- /dev/null
+++ b/multiload/src/load-graph.h
@@ -0,0 +1,24 @@
+#ifndef LOAD_GRAPH_H__
+#define LOAD_GRAPH_H__
+
+#include "global.h"
+
+/* Create new load graph. */
+G_GNUC_INTERNAL LoadGraph *
+load_graph_new (MultiloadApplet *multiload, guint n, const gchar *label,
+ guint id, guint speed, guint size, gboolean visible,
+ const gchar *name, LoadGraphDataFunc get_data);
+
+/* Start load graph. */
+G_GNUC_INTERNAL void
+load_graph_start (LoadGraph *g);
+
+/* Stop load graph. */
+G_GNUC_INTERNAL void
+load_graph_stop (LoadGraph *g);
+
+/* free load graph */
+G_GNUC_INTERNAL void
+load_graph_unalloc (LoadGraph *g);
+
+#endif
diff --git a/multiload/src/main.c b/multiload/src/main.c
new file mode 100644
index 00000000..50732e01
--- /dev/null
+++ b/multiload/src/main.c
@@ -0,0 +1,573 @@
+/* MATE multiload panel applet
+ * (C) 1997 The Free Software Foundation
+ *
+ * Authors: Tim P. Gerla
+ * Martin Baulig
+ * Todd Kulesza
+ *
+ * With code from wmload.c, v0.9.2, apparently by Ryan Land, [email protected].
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <signal.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+
+#include <glibtop.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gio/gio.h>
+#include <gio/gdesktopappinfo.h>
+#include <mate-panel-applet.h>
+#include <mate-panel-applet-gsettings.h>
+
+#include "global.h"
+
+static void
+about_cb (GtkAction *action,
+ MultiloadApplet *ma)
+{
+ const gchar * const authors[] =
+ {
+ "Martin Baulig <[email protected]>",
+ "Todd Kulesza <[email protected]>",
+ "Benoît Dejean <[email protected]>",
+ "Davyd Madeley <[email protected]>",
+ NULL
+ };
+
+ const gchar* documenters[] =
+ {
+ "Chee Bin HOH <[email protected]>",
+ N_("Sun GNOME Documentation Team <[email protected]>"),
+ N_("MATE Documentation Team"),
+ NULL
+ };
+
+#ifdef ENABLE_NLS
+ const char **p;
+ for (p = documenters; *p; ++p)
+ *p = _(*p);
+#endif
+
+ gtk_show_about_dialog (NULL,
+ "title", _("About System Monitor"),
+ "version", VERSION,
+ "copyright", _("Copyright \xc2\xa9 1999-2005 Free Software Foundation and others\n"
+ "Copyright \xc2\xa9 2012-2020 MATE developers"),
+ "comments", _("A system load monitor capable of displaying graphs "
+ "for CPU, ram, and swap space use, plus network "
+ "traffic."),
+ "authors", authors,
+ "documenters", documenters,
+ "translator-credits", _("translator-credits"),
+ "logo-icon-name", "utilities-system-monitor",
+ NULL);
+}
+
+static void
+help_cb (GtkAction *action,
+ MultiloadApplet *ma)
+{
+ GError *error = NULL;
+
+ gtk_show_uri_on_window (NULL,
+ "help:mate-multiload",
+ gtk_get_current_event_time (),
+ &error);
+
+ if (error) { /* FIXME: the user needs to see this */
+ g_warning ("help error: %s\n", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+}
+
+/* run the full-scale system process monitor */
+
+static void
+start_procman (MultiloadApplet *ma)
+{
+ GError *error = NULL;
+ GDesktopAppInfo *appinfo;
+ gchar *monitor;
+ GdkAppLaunchContext *launch_context;
+ GdkDisplay *display;
+ GAppInfo *app_info;
+ GdkScreen *screen;
+
+ g_return_if_fail (ma != NULL);
+
+ monitor = g_settings_get_string (ma->settings, "system-monitor");
+ if (monitor == NULL)
+ monitor = g_strdup ("mate-system-monitor.desktop");
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (ma->applet));
+ appinfo = g_desktop_app_info_new (monitor);
+ if (appinfo) {
+ GdkAppLaunchContext *context;
+ display = gdk_screen_get_display (screen);
+ context = gdk_display_get_app_launch_context (display);
+ gdk_app_launch_context_set_screen (context, screen);
+ g_app_info_launch (G_APP_INFO (appinfo), NULL, G_APP_LAUNCH_CONTEXT (context), &error);
+ g_object_unref (context);
+ g_object_unref (appinfo);
+ }
+ else {
+ app_info = g_app_info_create_from_commandline ("mate-system-monitor",
+ _("Start system-monitor"),
+ G_APP_INFO_CREATE_NONE,
+ &error);
+
+ if (!error) {
+ display = gdk_screen_get_display (screen);
+ launch_context = gdk_display_get_app_launch_context (display);
+ gdk_app_launch_context_set_screen (launch_context, screen);
+ g_app_info_launch (app_info, NULL, G_APP_LAUNCH_CONTEXT (launch_context), &error);
+
+ g_object_unref (launch_context);
+ }
+ }
+ g_free (monitor);
+
+ if (error) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("There was an error executing '%s': %s"),
+ "mate-system-monitor",
+ error->message);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gtk_widget_destroy),
+ NULL);
+
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_window_set_screen (GTK_WINDOW (dialog), screen);
+
+ gtk_widget_show (dialog);
+
+ g_error_free (error);
+ }
+}
+
+static void
+start_procman_cb (GtkAction *action,
+ MultiloadApplet *ma)
+{
+ start_procman (ma);
+}
+
+static void
+multiload_change_size_cb(MatePanelApplet *applet, gint size, gpointer data)
+{
+ MultiloadApplet *ma = (MultiloadApplet *)data;
+
+ multiload_applet_refresh(ma);
+
+ return;
+}
+
+static void
+multiload_change_orient_cb(MatePanelApplet *applet, gint arg1, gpointer data)
+{
+ MultiloadApplet *ma = data;
+ multiload_applet_refresh((MultiloadApplet *)data);
+ gtk_widget_show (GTK_WIDGET (ma->applet));
+ return;
+}
+
+static void
+multiload_destroy_cb(GtkWidget *widget, gpointer data)
+{
+ gint i;
+ MultiloadApplet *ma = data;
+
+ for (i = 0; i < graph_n; i++)
+ {
+ load_graph_stop(ma->graphs[i]);
+ if (ma->graphs[i]->colors)
+ {
+ g_free (ma->graphs[i]->colors);
+ ma->graphs[i]->colors = NULL;
+ }
+ gtk_widget_destroy(ma->graphs[i]->main_widget);
+
+ load_graph_unalloc(ma->graphs[i]);
+ g_free(ma->graphs[i]);
+ }
+
+ netspeed_delete (ma->netspeed_in);
+ netspeed_delete (ma->netspeed_out);
+
+ if (ma->about_dialog)
+ gtk_widget_destroy (ma->about_dialog);
+
+ if (ma->prop_dialog)
+ gtk_widget_destroy (ma->prop_dialog);
+
+ gtk_widget_destroy(GTK_WIDGET(ma->applet));
+
+ g_free (ma);
+
+ return;
+}
+
+
+static gboolean
+multiload_button_press_event_cb (GtkWidget *widget, GdkEventButton *event, MultiloadApplet *ma)
+{
+ g_return_val_if_fail (event != NULL, FALSE);
+ g_return_val_if_fail (ma != NULL, FALSE);
+
+ if (event->button == 1 && event->type == GDK_BUTTON_PRESS) {
+ start_procman (ma);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+multiload_key_press_event_cb (GtkWidget *widget, GdkEventKey *event, MultiloadApplet *ma)
+{
+ g_return_val_if_fail (event != NULL, FALSE);
+ g_return_val_if_fail (ma != NULL, FALSE);
+
+ switch (event->keyval) {
+ /* this list of keyvals taken from mixer applet, which seemed to have
+ a good list of keys to use */
+ case GDK_KEY_KP_Enter:
+ case GDK_KEY_ISO_Enter:
+ case GDK_KEY_3270_Enter:
+ case GDK_KEY_Return:
+ case GDK_KEY_space:
+ case GDK_KEY_KP_Space:
+ /* activate */
+ start_procman (ma);
+ return TRUE;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+/* update the tooltip to the graph's current "used" percentage */
+void
+multiload_applet_tooltip_update(LoadGraph *g)
+{
+ gchar *tooltip_text;
+ MultiloadApplet *multiload;
+ const char *tooltip_label [graph_n] = {
+ [graph_cpuload] = N_("Processor"),
+ [graph_memload] = N_("Memory"),
+ [graph_netload2] = N_("Network"),
+ [graph_swapload] = N_("Swap Space"),
+ [graph_loadavg] = N_("Load Average"),
+ [graph_diskload] = N_("Disk")
+ };
+ const char *name;
+
+ g_assert(g);
+
+ multiload = g->multiload;
+
+ /* label the tooltip intuitively */
+ name = gettext (tooltip_label [g->id]);
+
+ switch (g->id) {
+ case graph_memload: {
+ float user_percent, cache_percent;
+
+ user_percent = MIN ((float)(100 * multiload->memload_user) / (float)(multiload->memload_total), 100.0f);
+ cache_percent = MIN ((float)(100 * multiload->memload_cache) / (float)(multiload->memload_total), 100.0f);
+ tooltip_text = g_strdup_printf (_("%s:\n"
+ "%.01f%% in use by programs\n"
+ "%.01f%% in use as cache"),
+ name,
+ user_percent,
+ cache_percent);
+ break;
+ }
+ case graph_loadavg: {
+ tooltip_text = g_strdup_printf (_("The system load average is %0.02f"),
+ multiload->loadavg1);
+ break;
+ }
+ case graph_netload2: {
+ char *tx_in, *tx_out;
+
+ tx_in = netspeed_get(multiload->netspeed_in);
+ tx_out = netspeed_get(multiload->netspeed_out);
+ /* xgettext: same as in graphic tab of g-s-m */
+ tooltip_text = g_strdup_printf(_("%s:\n"
+ "Receiving %s\n"
+ "Sending %s"),
+ name, tx_in, tx_out);
+ g_free(tx_in);
+ g_free(tx_out);
+ break;
+ }
+ default: {
+ float ratio;
+ float percent;
+
+ if (g->id == graph_cpuload)
+ ratio = multiload->cpu_used_ratio;
+ else if (g->id == graph_swapload)
+ ratio = multiload->swapload_used_ratio;
+ else if (g->id == graph_diskload)
+ ratio = multiload->diskload_used_ratio;
+ else
+ g_assert_not_reached ();
+
+ percent = CLAMP (ratio * 100.0f, 0.0f, 100.0f);
+ tooltip_text = g_strdup_printf(_("%s:\n"
+ "%.01f%% in use"),
+ name,
+ percent);
+ }
+ }
+
+ gtk_widget_set_tooltip_text(g->disp, tooltip_text);
+
+ g_free(tooltip_text);
+}
+
+static void
+multiload_create_graphs(MultiloadApplet *ma)
+{
+ struct { const char *label;
+ const char *visibility_key;
+ const char *name;
+ int num_colours;
+ LoadGraphDataFunc callback;
+ } graph_types [graph_n] = {
+ [graph_cpuload] = { _("CPU Load"), VIEW_CPULOAD_KEY, "cpuload", cpuload_n, GetLoad },
+ [graph_memload] = { _("Memory Load"), VIEW_MEMLOAD_KEY, "memload", memload_n, GetMemory },
+ [graph_netload2] = { _("Net Load"), VIEW_NETLOAD_KEY, "netload2", 6, GetNet },
+ [graph_swapload] = { _("Swap Load"), VIEW_SWAPLOAD_KEY, "swapload", swapload_n, GetSwap },
+ [graph_loadavg] = { _("Load Average"), VIEW_LOADAVG_KEY, "loadavg", 3, GetLoadAvg },
+ [graph_diskload] = { _("Disk Load"), VIEW_DISKLOAD_KEY, "diskload", diskload_n, GetDiskLoad }
+ };
+
+ gint speed, size;
+ guint net_threshold1;
+ guint net_threshold2;
+ guint net_threshold3;
+ gint i;
+
+ speed = g_settings_get_int (ma->settings, "speed");
+ size = g_settings_get_int (ma->settings, "size");
+ net_threshold1 = CLAMP (g_settings_get_uint (ma->settings, "netthreshold1"), MIN_NET_THRESHOLD1, MAX_NET_THRESHOLD1);
+ net_threshold2 = CLAMP (g_settings_get_uint (ma->settings, "netthreshold2"), MIN_NET_THRESHOLD2, MAX_NET_THRESHOLD2);
+ net_threshold3 = CLAMP (g_settings_get_uint (ma->settings, "netthreshold3"), MIN_NET_THRESHOLD3, MAX_NET_THRESHOLD3);
+ if (net_threshold1 >= net_threshold2)
+ {
+ net_threshold1 = net_threshold2 - 1;
+ }
+ if (net_threshold2 >= net_threshold3)
+ {
+ net_threshold3 = net_threshold2 + 1;
+ }
+ speed = MAX (speed, 50);
+ size = CLAMP (size, 10, 400);
+
+ for (i = 0; i < graph_n; i++)
+ {
+ ma->graphs[i] = load_graph_new (ma,
+ graph_types[i].num_colours,
+ graph_types[i].label,
+ i,
+ speed,
+ size,
+ g_settings_get_boolean (ma->settings, graph_types[i].visibility_key),
+ graph_types[i].name,
+ graph_types[i].callback);
+ }
+ ma->nvme_diskstats = g_settings_get_boolean (ma->settings, "diskload-nvme-diskstats");
+ /* for Network graph, colors[4] is grid line color, it should not be used in loop in load-graph.c */
+ /* for Network graph, colors[5] is indicator color, it should not be used in loop in load-graph.c */
+ ma->graphs[graph_netload2]->n = 4;
+ ma->net_threshold1 = net_threshold1;
+ ma->net_threshold2 = net_threshold2;
+ ma->net_threshold3 = net_threshold3;
+ ma->netspeed_in = netspeed_new (ma->graphs [graph_netload2]);
+ ma->netspeed_out = netspeed_new (ma->graphs [graph_netload2]);
+ /* for Load graph, colors[2] is grid line color, it should not be used in loop in load-graph.c */
+ ma->graphs[graph_loadavg]->n = 2;
+}
+
+/* remove the old graphs and rebuild them */
+void
+multiload_applet_refresh(MultiloadApplet *ma)
+{
+ gint i;
+ MatePanelAppletOrient orientation;
+
+ /* stop and free the old graphs */
+ for (i = 0; i < graph_n; i++)
+ {
+ if (!ma->graphs[i])
+ continue;
+
+ load_graph_stop(ma->graphs[i]);
+ gtk_widget_destroy(ma->graphs[i]->main_widget);
+
+ load_graph_unalloc(ma->graphs[i]);
+ g_free(ma->graphs[i]);
+ }
+
+ if (ma->box)
+ gtk_widget_destroy(ma->box);
+
+ orientation = mate_panel_applet_get_orient(ma->applet);
+
+ if ( (orientation == MATE_PANEL_APPLET_ORIENT_UP) ||
+ (orientation == MATE_PANEL_APPLET_ORIENT_DOWN) ) {
+ ma->box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ }
+ else
+ ma->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+
+ gtk_container_add(GTK_CONTAINER(ma->applet), ma->box);
+
+ /* create the N graphs, passing in their user-configurable properties with gsettings. */
+ multiload_create_graphs (ma);
+
+ /* only start and display the graphs the user has turned on */
+
+ for (i = 0; i < graph_n; i++) {
+ gtk_box_pack_start(GTK_BOX(ma->box),
+ ma->graphs[i]->main_widget,
+ TRUE, TRUE, 1);
+ if (ma->graphs[i]->visible) {
+ gtk_widget_show_all (ma->graphs[i]->main_widget);
+ load_graph_start(ma->graphs[i]);
+ }
+ }
+ gtk_widget_show (ma->box);
+
+ return;
+}
+
+static const GtkActionEntry multiload_menu_actions [] = {
+ { "MultiLoadProperties", "document-properties", N_("_Preferences"),
+ NULL, NULL,
+ G_CALLBACK (multiload_properties_cb) },
+ { "MultiLoadRunProcman", "system-run", N_("_Open System Monitor"),
+ NULL, NULL,
+ G_CALLBACK (start_procman_cb) },
+ { "MultiLoadHelp", "help-browser", N_("_Help"),
+ NULL, NULL,
+ G_CALLBACK (help_cb) },
+ { "MultiLoadAbout", "help-about", N_("_About"),
+ NULL, NULL,
+ G_CALLBACK (about_cb) }
+};
+
+/* create a box and stuff the load graphs inside of it */
+static gboolean
+multiload_applet_new(MatePanelApplet *applet, const gchar *iid, gpointer data)
+{
+ GtkStyleContext *context;
+ MultiloadApplet *ma;
+ GSettings *lockdown_settings;
+ GtkActionGroup *action_group;
+
+ context = gtk_widget_get_style_context (GTK_WIDGET (applet));
+ gtk_style_context_add_class (context, "multiload-applet");
+
+ ma = g_new0(MultiloadApplet, 1);
+
+ ma->applet = applet;
+
+ ma->about_dialog = NULL;
+ ma->prop_dialog = NULL;
+ ma->last_clicked = 0;
+
+ g_set_application_name (_("System Monitor"));
+
+ gtk_window_set_default_icon_name ("utilities-system-monitor");
+
+ ma->settings = mate_panel_applet_settings_new (applet, "org.mate.panel.applet.multiload");
+ mate_panel_applet_set_flags (applet, MATE_PANEL_APPLET_EXPAND_MINOR);
+
+ action_group = gtk_action_group_new ("Multiload Applet Actions");
+ gtk_action_group_set_translation_domain (action_group, GETTEXT_PACKAGE);
+ gtk_action_group_add_actions (action_group,
+ multiload_menu_actions,
+ G_N_ELEMENTS (multiload_menu_actions),
+ ma);
+ mate_panel_applet_setup_menu_from_file (applet,
+ MULTILOAD_MENU_UI_DIR "multiload-applet-menu.xml",
+ action_group);
+
+ if (mate_panel_applet_get_locked_down (applet)) {
+ GtkAction *action;
+
+ action = gtk_action_group_get_action (action_group, "MultiLoadProperties");
+ gtk_action_set_visible (action, FALSE);
+ }
+
+ lockdown_settings = g_settings_new ("org.mate.lockdown");
+ if (g_settings_get_boolean (lockdown_settings, "disable-command-line") ||
+ mate_panel_applet_get_locked_down (applet)) {
+ GtkAction *action;
+
+ /* When the panel is locked down or when the command line is inhibited,
+ it seems very likely that running the procman would be at least harmful */
+ action = gtk_action_group_get_action (action_group, "MultiLoadRunProcman");
+ gtk_action_set_visible (action, FALSE);
+ }
+ g_object_unref (lockdown_settings);
+
+ g_object_unref (action_group);
+
+ g_signal_connect(G_OBJECT(applet), "change_size",
+ G_CALLBACK(multiload_change_size_cb), ma);
+ g_signal_connect(G_OBJECT(applet), "change_orient",
+ G_CALLBACK(multiload_change_orient_cb), ma);
+ g_signal_connect(G_OBJECT(applet), "destroy",
+ G_CALLBACK(multiload_destroy_cb), ma);
+ g_signal_connect(G_OBJECT(applet), "button_press_event",
+ G_CALLBACK(multiload_button_press_event_cb), ma);
+ g_signal_connect(G_OBJECT(applet), "key_press_event",
+ G_CALLBACK(multiload_key_press_event_cb), ma);
+
+ multiload_applet_refresh (ma);
+
+ gtk_widget_show(GTK_WIDGET(applet));
+
+ return TRUE;
+}
+
+static gboolean
+multiload_factory (MatePanelApplet *applet,
+ const gchar *iid,
+ gpointer data)
+{
+ gboolean retval = FALSE;
+
+ glibtop_init();
+
+ retval = multiload_applet_new(applet, iid, data);
+
+ return retval;
+}
+
+MATE_PANEL_APPLET_OUT_PROCESS_FACTORY ("MultiLoadAppletFactory",
+ PANEL_TYPE_APPLET,
+ "multiload",
+ multiload_factory,
+ NULL)
diff --git a/multiload/src/netspeed.c b/multiload/src/netspeed.c
new file mode 100644
index 00000000..3e889c8f
--- /dev/null
+++ b/multiload/src/netspeed.c
@@ -0,0 +1,70 @@
+#include <config.h>
+#include <glib.h>
+#include <time.h>
+
+#include "netspeed.h"
+
+enum { N_STATES = 4 };
+
+struct _NetSpeed
+{
+ LoadGraph *graph;
+ gulong states[N_STATES];
+ size_t cur;
+};
+
+NetSpeed* netspeed_new(LoadGraph *g)
+{
+ NetSpeed *ns = g_new0(NetSpeed, 1);
+ ns->graph = g;
+ return ns;
+}
+
+void netspeed_delete(NetSpeed *ns)
+{
+ g_free(ns);
+}
+
+void netspeed_add(NetSpeed *ns, gulong tx)
+{
+ ns->cur = (ns->cur + 1) % N_STATES;
+ ns->states[ns->cur] = tx;
+}
+
+/* Something very similar to g_format_size() but for rates.
+ * This should give the same display as in g-s-m */
+static char*
+format_rate_for_display(guint rate)
+{
+ char *bytes;
+ char *text;
+
+ bytes = g_format_size (rate);
+ text = g_strdup_printf (_("%s/s"), bytes);
+ g_free (bytes);
+
+ return text;
+}
+
+char* netspeed_get(NetSpeed *ns)
+{
+ gulong older, newer;
+ guint rate;
+
+ newer = ns->states[ns->cur];
+ older = ns->states[(ns->cur + 1) % N_STATES];
+
+ if ((older != 0) && (newer > older))
+ rate = (newer - older) * 1000 / ((N_STATES - 1) * ns->graph->speed);
+ else
+ /* We end up here if we haven't got enough data yet or the
+ network interface has jumped back (or there has never
+ been any activity on any interface). A value of 0 is
+ likely to be accurate, but if it is wrong it will be
+ clearly wrong. In any event, it should fix itself in a
+ few seconds. */
+ rate = 0;
+
+ return format_rate_for_display(rate);
+}
+
diff --git a/multiload/src/netspeed.h b/multiload/src/netspeed.h
new file mode 100644
index 00000000..5bc19cf1
--- /dev/null
+++ b/multiload/src/netspeed.h
@@ -0,0 +1,15 @@
+#ifndef H_MULTILOAD_NETSPEED_
+#define H_MULTILOAD_NETSPEED_
+
+#include <glib.h>
+
+typedef struct _NetSpeed NetSpeed;
+
+#include "global.h"
+
+NetSpeed* netspeed_new(LoadGraph *graph);
+void netspeed_delete(NetSpeed *ns);
+void netspeed_add(NetSpeed *ns, gulong tx);
+char* netspeed_get(NetSpeed *ns);
+
+#endif /* H_MULTILOAD_NETSPEED_ */
diff --git a/multiload/src/properties.c b/multiload/src/properties.c
new file mode 100644
index 00000000..c1ee09b6
--- /dev/null
+++ b/multiload/src/properties.c
@@ -0,0 +1,868 @@
+/* MATE cpuload/memload panel applet
+ * (C) 2002 The Free Software Foundation
+ *
+ * Authors:
+ * Todd Kulesza
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include <gio/gio.h>
+#include <mate-panel-applet.h>
+#include <mate-panel-applet-gsettings.h>
+
+#include "global.h"
+
+#define PROP_CPU 0
+#define PROP_MEM 1
+#define PROP_NET 2
+#define PROP_SWAP 3
+#define PROP_AVG 4
+#define PROP_DISK 5
+
+#define PROP_SPEED 6
+#define PROP_SIZE 7
+#define PROP_NET_THRESHOLD1 8
+#define PROP_NET_THRESHOLD2 9
+#define PROP_NET_THRESHOLD3 10
+#define HIG_IDENTATION " "
+#define NEVER_SENSITIVE "never_sensitive"
+
+/* set sensitive and setup NEVER_SENSITIVE appropriately */
+static void
+hard_set_sensitive (GtkWidget *w, gboolean sensitivity)
+{
+ gtk_widget_set_sensitive (w, sensitivity);
+ g_object_set_data (G_OBJECT (w), NEVER_SENSITIVE,
+ GINT_TO_POINTER ( ! sensitivity));
+}
+
+
+/* set sensitive, but always insensitive if NEVER_SENSITIVE is set */
+static void
+soft_set_sensitive (GtkWidget *w, gboolean sensitivity)
+{
+ if (g_object_get_data (G_OBJECT (w), NEVER_SENSITIVE))
+ gtk_widget_set_sensitive (w, FALSE);
+ else
+ gtk_widget_set_sensitive (w, sensitivity);
+}
+
+static void
+properties_set_insensitive(MultiloadApplet *ma)
+{
+ gint i, total_graphs, last_graph;
+
+ total_graphs = 0;
+ last_graph = 0;
+
+ for (i = 0; i < graph_n; i++)
+ if (ma->graphs[i]->visible)
+ {
+ last_graph = i;
+ total_graphs++;
+ }
+
+ if (total_graphs < 2)
+ soft_set_sensitive(ma->check_boxes[last_graph], FALSE);
+
+ return;
+}
+
+static void
+properties_close_cb (GtkWidget *widget, gint arg, MultiloadApplet *ma)
+{
+ GError *error = NULL;
+
+ switch (arg)
+ {
+ case GTK_RESPONSE_HELP:
+
+ gtk_show_uri_on_window (NULL,
+ "help:mate-multiload/multiload-prefs",
+ gtk_get_current_event_time (),
+ &error);
+
+ if (error) { /* FIXME: the user needs to see this */
+ g_warning ("help error: %s\n", error->message);
+ g_error_free (error);
+ error = NULL;
+ }
+ break;
+
+ case GTK_RESPONSE_CLOSE:
+ default:
+ gtk_widget_destroy (widget);
+ ma->prop_dialog = NULL;
+ }
+}
+
+static void
+property_toggled_cb(GtkWidget *widget, gpointer name)
+{
+ MultiloadApplet *ma;
+ gint prop_type, i;
+ gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+
+ ma = g_object_get_data(G_OBJECT(widget), "MultiloadApplet");
+ prop_type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "prop_type"));
+
+ /* FIXME: the first toggle button to be checked/dechecked does not work, but after that everything is cool. what gives? */
+ /* FIXME: check if this is still valid for gsettings */
+ g_settings_set_boolean (ma->settings, (gchar *)name, active);
+ g_settings_set_boolean (ma->settings, (gchar *)name, active);
+
+ if (active)
+ {
+ for (i = 0; i < graph_n; i++)
+ soft_set_sensitive(ma->check_boxes[i], TRUE);
+ gtk_widget_show_all (ma->graphs[prop_type]->main_widget);
+ ma->graphs[prop_type]->visible = TRUE;
+ load_graph_start(ma->graphs[prop_type]);
+ }
+ else
+ {
+ load_graph_stop(ma->graphs[prop_type]);
+ gtk_widget_hide (ma->graphs[prop_type]->main_widget);
+ ma->graphs[prop_type]->visible = FALSE;
+ properties_set_insensitive(ma);
+ }
+
+ return;
+}
+
+static void
+spin_button_changed_cb(GtkWidget *widget, gpointer name)
+{
+ MultiloadApplet *ma;
+ gint value;
+ gint prop_type, i;
+
+ ma = g_object_get_data(G_OBJECT(widget), "MultiloadApplet");
+ prop_type = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(widget), "prop_type"));
+ value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+
+ switch(prop_type)
+ {
+ case PROP_SPEED:
+ g_settings_set_int (ma->settings, (gchar *)name, value);
+ for (i = 0; i < graph_n; i++)
+ {
+ load_graph_stop(ma->graphs[i]);
+ ma->graphs[i]->speed = value;
+ if (ma->graphs[i]->visible)
+ load_graph_start(ma->graphs[i]);
+ }
+
+ break;
+
+ case PROP_SIZE:
+ for (i = 0; i < graph_n; i++)
+ {
+ g_settings_set_int (ma->settings, (gchar *)name, value);
+ ma->graphs[i]->size = value ;
+
+ if (ma->graphs[i]->orient)
+ gtk_widget_set_size_request (
+ ma->graphs[i]->main_widget,
+ ma->graphs[i]->pixel_size,
+ ma->graphs[i]->size);
+ else
+ gtk_widget_set_size_request (
+ ma->graphs[i]->main_widget,
+ ma->graphs[i]->size,
+ ma->graphs[i]->pixel_size);
+ }
+ break;
+
+ case PROP_NET_THRESHOLD1:
+ g_settings_set_uint (ma->settings, (gchar *)name, value);
+ if (value >= ma->net_threshold2)
+ {
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),
+ (gdouble)g_settings_get_uint (ma->settings,
+ "netthreshold2") - 1);
+ ma->net_threshold1 = g_settings_get_uint (ma->settings,
+ "netthreshold2") - 1;
+ }
+ else
+ ma->net_threshold1 = value;
+ break;
+
+ case PROP_NET_THRESHOLD2:
+ g_settings_set_uint (ma->settings, (gchar *)name, value);
+ if (value >= ma->net_threshold3)
+ {
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),
+ (gdouble)g_settings_get_uint (ma->settings,
+ "netthreshold3") - 1);
+ ma->net_threshold2 = g_settings_get_uint (ma->settings,
+ "netthreshold3") - 1;
+ }
+ else if (value <= ma->net_threshold1)
+ {
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),
+ (gdouble)g_settings_get_uint (ma->settings,
+ "netthreshold1") + 1);
+ ma->net_threshold2 = g_settings_get_uint (ma->settings,
+ "netthreshold1") + 1;
+ }
+ else
+ ma->net_threshold2 = value;
+ break;
+
+ case PROP_NET_THRESHOLD3:
+ g_settings_set_uint (ma->settings, (gchar *)name, value);
+ if (value <= ma->net_threshold2)
+ {
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget),
+ (gdouble)g_settings_get_uint (ma->settings,
+ "netthreshold2") + 1);
+ ma->net_threshold3 = g_settings_get_uint (ma->settings,
+ "netthreshold2") + 1;
+ }
+ else
+ ma->net_threshold3 = value;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ return;
+}
+
+/* create a new page in the notebook widget, add it, and return a pointer to it */
+static GtkWidget *
+add_page(GtkWidget *notebook, gchar *label)
+{
+ GtkWidget *page;
+ GtkWidget *page_label;
+
+ page = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_set_homogeneous (GTK_BOX (page), TRUE);
+ page_label = gtk_label_new(label);
+ gtk_container_set_border_width(GTK_CONTAINER(page), 6);
+
+ gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, page_label);
+
+ return page;
+}
+
+/* save the selected color to gsettings and apply it on the applet */
+static void
+color_picker_set_cb(GtkColorChooser *color_picker, gchar *key)
+{
+ gchar *color_string;
+ guint8 prop_type;
+ GdkRGBA color;
+ MultiloadApplet *ma;
+
+ ma = g_object_get_data (G_OBJECT (color_picker), "MultiloadApplet");
+
+ if (strstr(key, "cpuload"))
+ prop_type = PROP_CPU;
+ else if (strstr(key, "memload"))
+ prop_type = PROP_MEM;
+ else if (strstr(key, "netload2"))
+ prop_type = PROP_NET;
+ else if (strstr(key, "swapload"))
+ prop_type = PROP_SWAP;
+ else if (strstr(key, "loadavg"))
+ prop_type = PROP_AVG;
+ else if (strstr(key, "diskload"))
+ prop_type = PROP_DISK;
+ else
+ g_assert_not_reached();
+
+ gtk_color_chooser_get_rgba(color_picker, &color);
+
+ color_string = gdk_rgba_to_string (&color);
+ g_settings_set_string(ma->settings, key, color_string);
+
+ gdk_rgba_parse(&(ma->graphs[prop_type]->colors[g_ascii_digit_value(key[strlen(key) - 1]) ]),
+ color_string);
+
+ return;
+}
+
+/* create a color selector */
+static void
+add_color_selector(GtkWidget *page, gchar *name, gchar *key, MultiloadApplet *ma)
+{
+ GtkWidget *vbox;
+ GtkWidget *label;
+ GtkWidget *color_picker;
+ GdkRGBA color;
+ gchar *color_string;
+
+ color_string = g_settings_get_string (ma->settings, key);
+ if (!color_string)
+ color_string = g_strdup ("#000000");
+ gdk_rgba_parse (&color, color_string);
+ g_free (color_string);
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ label = gtk_label_new_with_mnemonic(name);
+ color_picker = gtk_color_button_new();
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), color_picker);
+
+ gtk_box_pack_start(GTK_BOX(vbox), color_picker, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+
+ gtk_box_pack_start(GTK_BOX(page), vbox, FALSE, FALSE, 0);
+
+ g_object_set_data (G_OBJECT (color_picker), "MultiloadApplet", ma);
+
+ gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(color_picker), &color);
+
+ g_signal_connect(G_OBJECT(color_picker), "color_set", G_CALLBACK(color_picker_set_cb), key);
+
+ if ( ! g_settings_is_writable (ma->settings, key))
+ hard_set_sensitive (vbox, FALSE);
+
+ return;
+}
+
+/* save the checkbox option to gsettings and apply it on the applet */
+static void
+nvme_checkbox_toggled_cb (GtkCheckButton *checkbox,
+ MultiloadApplet *ma)
+{
+ gboolean option;
+
+ option = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (checkbox));
+ ma->nvme_diskstats = option;
+ g_settings_set_boolean (ma->settings, "diskload-nvme-diskstats", option);
+
+ return;
+}
+
+/* creates the properties dialog using up-to-the-minute info from gsettings */
+static void
+fill_properties(GtkWidget *dialog, MultiloadApplet *ma)
+{
+ GtkWidget *page;
+ GtkWidget *hbox, *vbox;
+ GtkWidget *categories_vbox;
+ GtkWidget *category_vbox;
+ GtkWidget *control_vbox;
+ GtkWidget *control_hbox;
+ GtkWidget *check_box;
+ GtkWidget *indent;
+ GtkWidget *spin_button;
+ GtkWidget *label;
+ MatePanelAppletOrient orient;
+ GtkSizeGroup *label_size;
+ GtkSizeGroup *spin_size;
+ gchar *label_text;
+ gchar *title;
+
+ vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
+ gtk_widget_show (vbox);
+
+ gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
+ vbox, TRUE, TRUE, 0);
+
+ categories_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 18);
+ gtk_box_pack_start (GTK_BOX (vbox), categories_vbox, TRUE, TRUE, 0);
+ gtk_widget_show (categories_vbox);
+
+ category_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (categories_vbox), category_vbox, TRUE, TRUE, 0);
+ gtk_widget_show (category_vbox);
+
+ title = g_strconcat ("<span weight=\"bold\">", _("Monitored Resources"), "</span>", NULL);
+ label = gtk_label_new_with_mnemonic (_(title));
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_box_pack_start (GTK_BOX (category_vbox), label, FALSE, FALSE, 0);
+ g_free (title);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_pack_start (GTK_BOX (category_vbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ indent = gtk_label_new (HIG_IDENTATION);
+ gtk_label_set_justify (GTK_LABEL (indent), GTK_JUSTIFY_LEFT);
+ gtk_box_pack_start (GTK_BOX (hbox), indent, FALSE, FALSE, 0);
+ gtk_widget_show (indent);
+
+ control_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), control_vbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_vbox);
+
+ control_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (control_vbox), control_hbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_hbox);
+
+ check_box = gtk_check_button_new_with_mnemonic(_("_Processor"));
+ ma->check_boxes[0] = check_box;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box),
+ g_settings_get_boolean (ma->settings,
+ VIEW_CPULOAD_KEY));
+ g_object_set_data(G_OBJECT(check_box), "MultiloadApplet", ma);
+ g_object_set_data(G_OBJECT(check_box), "prop_type", GINT_TO_POINTER(PROP_CPU));
+ g_signal_connect(G_OBJECT(check_box), "toggled",
+ G_CALLBACK(property_toggled_cb), VIEW_CPULOAD_KEY);
+ gtk_box_pack_start (GTK_BOX (control_hbox), check_box, FALSE, FALSE, 0);
+
+ if ( ! g_settings_is_writable (ma->settings, VIEW_CPULOAD_KEY))
+ hard_set_sensitive (check_box, FALSE);
+
+ check_box = gtk_check_button_new_with_mnemonic(_("_Memory"));
+ ma->check_boxes[1] = check_box;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box),
+ g_settings_get_boolean (ma->settings, VIEW_MEMLOAD_KEY));
+ g_object_set_data(G_OBJECT(check_box), "MultiloadApplet", ma);
+ g_object_set_data(G_OBJECT(check_box), "prop_type", GINT_TO_POINTER(PROP_MEM));
+ g_signal_connect(G_OBJECT(check_box), "toggled",
+ G_CALLBACK(property_toggled_cb), VIEW_MEMLOAD_KEY);
+ gtk_box_pack_start (GTK_BOX (control_hbox), check_box, FALSE, FALSE, 0);
+
+ if ( ! g_settings_is_writable (ma->settings, VIEW_MEMLOAD_KEY))
+ hard_set_sensitive (check_box, FALSE);
+
+ check_box = gtk_check_button_new_with_mnemonic(_("_Network"));
+ ma->check_boxes[2] = check_box;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box),
+ g_settings_get_boolean (ma->settings, VIEW_NETLOAD_KEY));
+ g_object_set_data(G_OBJECT(check_box), "MultiloadApplet", ma);
+ g_object_set_data(G_OBJECT(check_box), "prop_type", GINT_TO_POINTER(PROP_NET));
+ g_signal_connect(G_OBJECT(check_box), "toggled",
+ G_CALLBACK(property_toggled_cb), VIEW_NETLOAD_KEY);
+ gtk_box_pack_start (GTK_BOX (control_hbox), check_box, FALSE, FALSE, 0);
+
+ if ( ! g_settings_is_writable (ma->settings, VIEW_NETLOAD_KEY))
+ hard_set_sensitive (check_box, FALSE);
+
+ check_box = gtk_check_button_new_with_mnemonic (_("S_wap Space"));
+ ma->check_boxes[3] = check_box;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box),
+ g_settings_get_boolean (ma->settings, VIEW_SWAPLOAD_KEY));
+ g_object_set_data(G_OBJECT(check_box), "MultiloadApplet", ma);
+ g_object_set_data(G_OBJECT(check_box), "prop_type", GINT_TO_POINTER(PROP_SWAP));
+ g_signal_connect(G_OBJECT(check_box), "toggled",
+ G_CALLBACK(property_toggled_cb), VIEW_SWAPLOAD_KEY);
+ gtk_box_pack_start (GTK_BOX (control_hbox), check_box, FALSE, FALSE, 0);
+
+ if ( ! g_settings_is_writable (ma->settings, VIEW_SWAPLOAD_KEY))
+ hard_set_sensitive (check_box, FALSE);
+
+ check_box = gtk_check_button_new_with_mnemonic(_("_Load"));
+ ma->check_boxes[4] = check_box;
+ gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check_box),
+ g_settings_get_boolean (ma->settings, VIEW_LOADAVG_KEY));
+ g_object_set_data(G_OBJECT(check_box), "MultiloadApplet", ma);
+ g_object_set_data(G_OBJECT(check_box), "prop_type", GINT_TO_POINTER(PROP_AVG));
+ g_signal_connect(G_OBJECT(check_box), "toggled",
+ G_CALLBACK(property_toggled_cb), VIEW_LOADAVG_KEY);
+ gtk_box_pack_start(GTK_BOX(control_hbox), check_box, FALSE, FALSE, 0);
+
+ if ( ! g_settings_is_writable (ma->settings, VIEW_LOADAVG_KEY))
+ hard_set_sensitive (check_box, FALSE);
+
+ check_box = gtk_check_button_new_with_mnemonic(_("_Harddisk"));
+ ma->check_boxes[5] = check_box;
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_box),
+ g_settings_get_boolean (ma->settings, VIEW_DISKLOAD_KEY));
+ g_object_set_data (G_OBJECT (check_box), "MultiloadApplet", ma);
+ g_object_set_data (G_OBJECT (check_box), "prop_type",
+ GINT_TO_POINTER (PROP_DISK));
+ g_signal_connect (G_OBJECT (check_box), "toggled",
+ G_CALLBACK (property_toggled_cb), VIEW_DISKLOAD_KEY);
+ gtk_box_pack_start (GTK_BOX (control_hbox), check_box, FALSE, FALSE, 0);
+
+ if ( ! g_settings_is_writable (ma->settings, VIEW_DISKLOAD_KEY))
+ hard_set_sensitive (check_box, FALSE);
+
+ category_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (categories_vbox), category_vbox, TRUE, TRUE, 0);
+ gtk_widget_show (category_vbox);
+
+ title = g_strconcat ("<span weight=\"bold\">", _("Options"), "</span>", NULL);
+ label = gtk_label_new (title);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_box_pack_start (GTK_BOX (category_vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+ g_free (title);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_pack_start (GTK_BOX (category_vbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ indent = gtk_label_new (HIG_IDENTATION);
+ gtk_label_set_justify (GTK_LABEL (indent), GTK_JUSTIFY_LEFT);
+ gtk_box_pack_start (GTK_BOX (hbox), indent, FALSE, FALSE, 0);
+ gtk_widget_show (indent);
+
+ control_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), control_vbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_vbox);
+
+ control_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (control_vbox), control_hbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_hbox);
+
+ label_size = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ orient = mate_panel_applet_get_orient(ma->applet);
+ if ( (orient == MATE_PANEL_APPLET_ORIENT_UP) || (orient == MATE_PANEL_APPLET_ORIENT_DOWN) )
+ label_text = g_strdup(_("System m_onitor width: "));
+ else
+ label_text = g_strdup(_("System m_onitor height: "));
+
+ label = gtk_label_new_with_mnemonic(label_text);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
+ gtk_size_group_add_widget (label_size, label);
+ gtk_box_pack_start (GTK_BOX (control_hbox), label, FALSE, FALSE, 0);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (control_hbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ spin_size = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ spin_button = gtk_spin_button_new_with_range(10, 1000, 5);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);
+ g_object_set_data(G_OBJECT(spin_button), "MultiloadApplet", ma);
+ g_object_set_data(G_OBJECT(spin_button), "prop_type",
+ GINT_TO_POINTER(PROP_SIZE));
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button),
+ (gdouble)g_settings_get_int(ma->settings, "size"));
+ g_signal_connect(G_OBJECT(spin_button), "value_changed",
+ G_CALLBACK(spin_button_changed_cb), "size");
+
+ if ( ! g_settings_is_writable (ma->settings, "size")) {
+ hard_set_sensitive (label, FALSE);
+ hard_set_sensitive (hbox, FALSE);
+ }
+
+ gtk_size_group_add_widget (spin_size, spin_button);
+ gtk_box_pack_start (GTK_BOX (hbox), spin_button, FALSE, FALSE, 0);
+
+ label = gtk_label_new (_("pixels"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ control_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (control_vbox), control_hbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_hbox);
+
+ label = gtk_label_new_with_mnemonic(_("Sys_tem monitor update interval: "));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
+ gtk_size_group_add_widget (label_size, label);
+ gtk_box_pack_start (GTK_BOX (control_hbox), label, FALSE, FALSE, 0);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (control_hbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ spin_button = gtk_spin_button_new_with_range(50, 10000, 50);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);
+ g_object_set_data(G_OBJECT(spin_button), "MultiloadApplet", ma);
+ g_object_set_data(G_OBJECT(spin_button), "prop_type",
+ GINT_TO_POINTER(PROP_SPEED));
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button),
+ (gdouble)g_settings_get_int (ma->settings, "speed"));
+ g_signal_connect(G_OBJECT(spin_button), "value_changed",
+ G_CALLBACK(spin_button_changed_cb), "speed");
+ gtk_size_group_add_widget (spin_size, spin_button);
+ gtk_box_pack_start (GTK_BOX (hbox), spin_button, FALSE, FALSE, 0);
+
+ if ( ! g_settings_is_writable (ma->settings, "speed")) {
+ hard_set_sensitive (label, FALSE);
+ hard_set_sensitive (hbox, FALSE);
+ }
+
+ label = gtk_label_new(_("milliseconds"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ g_free(label_text);
+
+
+ category_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (categories_vbox), category_vbox, TRUE, TRUE, 0);
+ gtk_widget_show (category_vbox);
+
+ title = g_strconcat ("<span weight=\"bold\">", _("Colors"), "</span>", NULL);
+ label = gtk_label_new (title);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_box_pack_start (GTK_BOX (category_vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+ g_free (title);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_pack_start (GTK_BOX (category_vbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ indent = gtk_label_new (HIG_IDENTATION);
+ gtk_label_set_justify (GTK_LABEL (indent), GTK_JUSTIFY_LEFT);
+ gtk_box_pack_start (GTK_BOX (hbox), indent, FALSE, FALSE, 0);
+ gtk_widget_show (indent);
+
+ control_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), control_vbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_vbox);
+
+ ma->notebook = gtk_notebook_new();
+ gtk_container_add (GTK_CONTAINER (control_vbox), ma->notebook);
+
+ page = add_page(ma->notebook, _("Processor"));
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+ add_color_selector(page, _("_User"), "cpuload-color0", ma);
+ add_color_selector(page, _("S_ystem"), "cpuload-color1", ma);
+ add_color_selector(page, _("N_ice"), "cpuload-color2", ma);
+ add_color_selector(page, _("I_OWait"), "cpuload-color3", ma);
+ add_color_selector(page, _("I_dle"), "cpuload-color4", ma);
+
+ page = add_page(ma->notebook, _("Memory"));
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+ add_color_selector(page, _("_User"), "memload-color0", ma);
+ add_color_selector(page, _("Sh_ared"), "memload-color1", ma);
+ add_color_selector(page, _("_Buffers"), "memload-color2", ma);
+ add_color_selector (page, _("Cach_ed"), "memload-color3", ma);
+ add_color_selector(page, _("F_ree"), "memload-color4", ma);
+
+ page = add_page(ma->notebook, _("Network"));
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+ add_color_selector (page, _("_In"), "netload2-color0", ma);
+ add_color_selector(page, _("_Out"), "netload2-color1", ma);
+ add_color_selector (page, _("_Local"), "netload2-color2", ma);
+ add_color_selector(page, _("_Background"), "netload2-color3", ma);
+ add_color_selector(page, _("_Gridline"), "netload2-color4", ma);
+ add_color_selector(page, _("_Indicator"), "netload2-color5", ma);
+
+ page = add_page(ma->notebook, _("Swap Space"));
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+ add_color_selector(page, _("_Used"), "swapload-color0", ma);
+ add_color_selector(page, _("_Free"), "swapload-color1", ma);
+
+ page = add_page(ma->notebook, _("Load"));
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+ add_color_selector(page, _("_Average"), "loadavg-color0", ma);
+ add_color_selector(page, _("_Background"), "loadavg-color1", ma);
+ add_color_selector(page, _("_Gridline"), "loadavg-color2", ma);
+
+ page = add_page (ma->notebook, _("Harddisk"));
+ gtk_container_set_border_width (GTK_CONTAINER (page), 12);
+ add_color_selector (page, _("_Read"), "diskload-color0", ma);
+ add_color_selector (page, _("_Write"), "diskload-color1", ma);
+ add_color_selector (page, _("_Background"), "diskload-color2", ma);
+ GtkWidget *nvme_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ GtkWidget *nvme_checkbox = gtk_check_button_new_with_mnemonic (_("Use diskstats for NVMe"));
+ ma->nvme_diskstats = g_settings_get_boolean (ma->settings, "diskload-nvme-diskstats");
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (nvme_checkbox),
+ ma->nvme_diskstats);
+ g_signal_connect (G_OBJECT (nvme_checkbox), "toggled",
+ G_CALLBACK (nvme_checkbox_toggled_cb), ma);
+ gtk_box_pack_start (GTK_BOX(nvme_box), nvme_checkbox, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX(page), nvme_box, FALSE, FALSE, 0);
+ gtk_widget_show (nvme_box);
+
+ title = g_strconcat ("<span weight=\"bold\">", _("Network speed thresholds"), "</span>", NULL);
+ label = gtk_label_new (title);
+ gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0);
+ gtk_box_pack_start (GTK_BOX (category_vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+ g_free (title);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_box_pack_start (GTK_BOX (category_vbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ indent = gtk_label_new (HIG_IDENTATION);
+ gtk_label_set_justify (GTK_LABEL (indent), GTK_JUSTIFY_LEFT);
+ gtk_box_pack_start (GTK_BOX (hbox), indent, FALSE, FALSE, 0);
+ gtk_widget_show (indent);
+
+ control_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (hbox), control_vbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_vbox);
+
+ control_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (control_vbox), control_hbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_hbox);
+
+ label_size = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ label_text = g_strdup(_("Threshold 1: "));
+ label = gtk_label_new_with_mnemonic(label_text);
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
+ gtk_size_group_add_widget (label_size, label);
+ gtk_box_pack_start (GTK_BOX (control_hbox), label, FALSE, FALSE, 0);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (control_hbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ spin_size = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ spin_button = gtk_spin_button_new_with_range (MIN_NET_THRESHOLD1, MAX_NET_THRESHOLD1, 5);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);
+ g_object_set_data(G_OBJECT(spin_button), "MultiloadApplet", ma);
+ g_object_set_data(G_OBJECT(spin_button), "prop_type",
+ GUINT_TO_POINTER(PROP_NET_THRESHOLD1));
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button),
+ (gdouble)g_settings_get_uint(ma->settings, "netthreshold1"));
+ g_signal_connect(G_OBJECT(spin_button), "value_changed",
+ G_CALLBACK(spin_button_changed_cb), "netthreshold1");
+
+ if ( ! g_settings_is_writable (ma->settings, "netthreshold1"))
+ {
+ hard_set_sensitive (label, FALSE);
+ hard_set_sensitive (hbox, FALSE);
+ }
+
+ gtk_size_group_add_widget (spin_size, spin_button);
+ gtk_box_pack_start (GTK_BOX (hbox), spin_button, FALSE, FALSE, 0);
+
+ label = gtk_label_new (_("bytes"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ control_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (control_vbox), control_hbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_hbox);
+
+ label = gtk_label_new_with_mnemonic(_("Threshold 2: "));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
+ gtk_size_group_add_widget (label_size, label);
+ gtk_box_pack_start (GTK_BOX (control_hbox), label, FALSE, FALSE, 0);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (control_hbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ spin_button = gtk_spin_button_new_with_range (MIN_NET_THRESHOLD2, MAX_NET_THRESHOLD2, 5);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);
+ g_object_set_data(G_OBJECT(spin_button), "MultiloadApplet", ma);
+ g_object_set_data(G_OBJECT(spin_button), "prop_type",
+ GINT_TO_POINTER(PROP_NET_THRESHOLD2));
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button),
+ (gdouble)g_settings_get_uint (ma->settings, "netthreshold2"));
+ g_signal_connect(G_OBJECT(spin_button), "value_changed",
+ G_CALLBACK(spin_button_changed_cb), "netthreshold2");
+ gtk_size_group_add_widget (spin_size, spin_button);
+ gtk_box_pack_start (GTK_BOX (hbox), spin_button, FALSE, FALSE, 0);
+
+ if ( ! g_settings_is_writable (ma->settings, "netthreshold2"))
+ {
+ hard_set_sensitive (label, FALSE);
+ hard_set_sensitive (hbox, FALSE);
+ }
+
+ label = gtk_label_new(_("bytes"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ control_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (control_vbox), control_hbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_hbox);
+
+ label = gtk_label_new_with_mnemonic(_("Threshold 3: "));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
+ gtk_size_group_add_widget (label_size, label);
+ gtk_box_pack_start (GTK_BOX (control_hbox), label, FALSE, FALSE, 0);
+
+ hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
+ gtk_box_pack_start (GTK_BOX (control_hbox), hbox, TRUE, TRUE, 0);
+ gtk_widget_show (hbox);
+
+ spin_button = gtk_spin_button_new_with_range (MIN_NET_THRESHOLD3, MAX_NET_THRESHOLD3, 5);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), spin_button);
+ g_object_set_data(G_OBJECT(spin_button), "MultiloadApplet", ma);
+ g_object_set_data(G_OBJECT(spin_button), "prop_type",
+ GINT_TO_POINTER(PROP_NET_THRESHOLD3));
+ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin_button),
+ (gdouble)g_settings_get_uint (ma->settings, "netthreshold3"));
+ g_signal_connect(G_OBJECT(spin_button), "value_changed",
+ G_CALLBACK(spin_button_changed_cb), "netthreshold3");
+ gtk_size_group_add_widget (spin_size, spin_button);
+ gtk_box_pack_start (GTK_BOX (hbox), spin_button, FALSE, FALSE, 0);
+
+ if ( ! g_settings_is_writable (ma->settings, "netthreshold3"))
+ {
+ hard_set_sensitive (label, FALSE);
+ hard_set_sensitive (hbox, FALSE);
+ }
+
+ label = gtk_label_new(_("bytes"));
+ gtk_label_set_xalign (GTK_LABEL (label), 0.0f);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ g_free(label_text);
+
+ category_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_box_pack_start (GTK_BOX (categories_vbox), category_vbox, TRUE, TRUE, 0);
+
+ control_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
+ gtk_box_pack_start (GTK_BOX (control_vbox), control_hbox, TRUE, TRUE, 0);
+ gtk_widget_show (control_hbox);
+
+ gtk_widget_show (category_vbox);
+
+ return;
+}
+
+/* show properties dialog */
+void
+multiload_properties_cb (GtkAction *action,
+ MultiloadApplet *ma)
+{
+ GtkWidget *dialog = NULL;
+
+ if (ma->prop_dialog) {
+ dialog = ma->prop_dialog;
+
+ gtk_window_set_screen (GTK_WINDOW (dialog),
+ gtk_widget_get_screen (GTK_WIDGET (ma->applet)));
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (ma->notebook),
+ ma->last_clicked);
+ gtk_window_present (GTK_WINDOW (dialog));
+ return;
+ }
+
+ dialog = gtk_dialog_new_with_buttons (_("System Monitor Preferences"),
+ NULL, 0,
+ "gtk-help", GTK_RESPONSE_HELP,
+ "gtk-close", GTK_RESPONSE_CLOSE,
+ NULL);
+ gtk_window_set_screen (GTK_WINDOW (dialog),
+ gtk_widget_get_screen (GTK_WIDGET (ma->applet)));
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2);
+
+ fill_properties(dialog, ma);
+
+ properties_set_insensitive(ma);
+
+ g_signal_connect(G_OBJECT(dialog), "response",
+ G_CALLBACK(properties_close_cb), ma);
+
+ ma->prop_dialog = dialog;
+
+ gtk_widget_show_all(dialog);
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (ma->notebook),
+ ma->last_clicked);
+}