zram-aware memory, configurable uptime format (1:1.3.2-2ubuntu3+zram2)
- zram.cc/.h: read zram usage; memory bar can subtract RAM held by zram
- memswap: zram and disk swap shown separately in the tooltip
- uptime: format string with %d %h %m %s, %H %M %S, %t, \n and {...}
- settings dialog fields for both, Russian translation
- tests/test_format_uptime.cc with tests/run.sh
This is what the installed 1:1.3.2-2ubuntu3+zram2 package was built from.
This commit is contained in:
parent
56dd2917ba
commit
0a59ec699f
14 changed files with 892 additions and 26 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -13,6 +13,7 @@ stamp-h1
|
|||
autom4te.cache/
|
||||
*.gmo
|
||||
po/.intltool-merge-cache
|
||||
po/.intltool-merge-cache.lock
|
||||
po/POTFILES
|
||||
po/stamp-it
|
||||
po/*.pot
|
||||
|
|
|
|||
32
debian/changelog
vendored
32
debian/changelog
vendored
|
|
@ -1,3 +1,35 @@
|
|||
xfce4-systemload-plugin (1:1.3.2-2ubuntu3+zram2) noble; urgency=medium
|
||||
|
||||
* Configurable uptime format (uptime/format in xfconf, "Format" field in
|
||||
the properties dialog). Placeholders %d %h %m %s, two-digit %H %M %S,
|
||||
total hours %t; \n splits the label into several centred lines; a {...}
|
||||
block disappears when all its numbers are zero. Empty keeps the old
|
||||
built-in text.
|
||||
* Fix g_snprintf size argument in the uptime label: it passed the size of
|
||||
the whole [2][32] array (64) for a 32-byte buffer.
|
||||
* Not for upload. Keep on hold.
|
||||
|
||||
-- chaiman <chaiman@lpc25> Tue, 03 Nov 2026 12:00:00 +0300
|
||||
|
||||
xfce4-systemload-plugin (1:1.3.2-2ubuntu3+zram1) noble; urgency=medium
|
||||
|
||||
* Local build: zram-aware memory accounting.
|
||||
- New zram monitor: physical RAM occupied by the compressed swap,
|
||||
with stored size and compression ratio in the tooltip.
|
||||
- New "Do not count the RAM held by zram" option in the memory monitor,
|
||||
off by default. Off, the memory bar keeps the literal meaning of
|
||||
"used" - RAM that is occupied and unavailable - and the zram bar is a
|
||||
breakdown of a part of it, so the two overlap. On, the two bars add up
|
||||
to the occupied total without counting the same pages twice.
|
||||
Either way the tooltip spells out the zram share, so the number on
|
||||
screen is never ambiguous.
|
||||
- Swap monitor now reads /proc/swaps and counts disk-backed areas
|
||||
only. SwapTotal/SwapFree lump zram in and report its uncompressed
|
||||
size, which corresponds to nothing physical.
|
||||
- Not for upload. Keep on hold, rebuild after any upstream change.
|
||||
|
||||
-- chaiman <chaiman@lpc25> Thu, 27 Aug 2026 20:54:13 +0300
|
||||
|
||||
xfce4-systemload-plugin (1:1.3.2-2ubuntu3) noble; urgency=medium
|
||||
|
||||
* No-change rebuild for CVE-2024-3094
|
||||
|
|
|
|||
|
|
@ -39,7 +39,9 @@ libsystemload_la_SOURCES = \
|
|||
settings.h \
|
||||
systemload.cc \
|
||||
uptime.cc \
|
||||
uptime.h
|
||||
uptime.h \
|
||||
zram.cc \
|
||||
zram.h
|
||||
|
||||
libsystemload_la_LDFLAGS = \
|
||||
-avoid-version \
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@
|
|||
#include <glib.h>
|
||||
|
||||
#include "memswap.h"
|
||||
#include "zram.h"
|
||||
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD_kernel__)
|
||||
|
|
@ -120,7 +121,35 @@ gint read_memswap(gulong *mem, gulong *swap, gulong *MT, gulong *MU, gulong *ST,
|
|||
|
||||
MFree += MCached + MBuffers;
|
||||
MUsed = MTotal - MFree;
|
||||
|
||||
/*
|
||||
* MUsed deliberately still includes the RAM held by zram: that memory is
|
||||
* in fact occupied and unavailable to anyone. Whether to subtract it is a
|
||||
* presentation choice, made by the caller through the "exclude zram from
|
||||
* memory usage" setting - see update_monitors() in systemload.cc.
|
||||
*/
|
||||
|
||||
/*
|
||||
* SwapTotal/SwapFree lump zram together with disk swap, and for zram they
|
||||
* report the UNCOMPRESSED size - a figure that corresponds to nothing
|
||||
* physical. Ask /proc/swaps instead and count only the disk-backed areas:
|
||||
* anything landing there is a genuine spill out of RAM.
|
||||
*
|
||||
* If /proc/swaps is unreadable, fall back to the meminfo numbers.
|
||||
*/
|
||||
{
|
||||
gulong DTotal = 0, DUsed = 0;
|
||||
if (read_disk_swap(&DTotal, &DUsed) == 0)
|
||||
{
|
||||
STotal = DTotal;
|
||||
SUsed = DUsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
SUsed = STotal - SFree;
|
||||
}
|
||||
}
|
||||
|
||||
*mem = MUsed * 100 / MTotal;
|
||||
|
||||
if(STotal)
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ static const gchar *const DEFAULT_LABEL[] = {
|
|||
"mem",
|
||||
"net",
|
||||
"swap",
|
||||
"zram",
|
||||
};
|
||||
|
||||
static const gchar *const DEFAULT_COLOR[] = {
|
||||
|
|
@ -62,6 +63,7 @@ static const gchar *const DEFAULT_COLOR[] = {
|
|||
"#2ec27e", /* MEM */
|
||||
"#e66100", /* NET */
|
||||
"#f5c211", /* SWAP */
|
||||
"#c061cb", /* ZRAM */
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -92,13 +94,15 @@ struct _SystemloadConfig {
|
|||
guint timeout_seconds;
|
||||
gchar *system_monitor_command;
|
||||
bool uptime;
|
||||
gchar *uptime_format;
|
||||
bool memory_exclude_zram;
|
||||
|
||||
struct {
|
||||
bool enabled;
|
||||
bool use_label;
|
||||
gchar *label;
|
||||
GdkRGBA color;
|
||||
} monitor[4];
|
||||
} monitor[N_MONITORS];
|
||||
};
|
||||
|
||||
enum SystemloadProperty {
|
||||
|
|
@ -123,6 +127,12 @@ enum SystemloadProperty {
|
|||
PROP_SWAP_USE_LABEL,
|
||||
PROP_SWAP_LABEL,
|
||||
PROP_SWAP_COLOR,
|
||||
PROP_ZRAM_ENABLED,
|
||||
PROP_ZRAM_USE_LABEL,
|
||||
PROP_ZRAM_LABEL,
|
||||
PROP_ZRAM_COLOR,
|
||||
PROP_MEMORY_EXCLUDE_ZRAM,
|
||||
PROP_UPTIME_FORMAT,
|
||||
N_PROPERTIES,
|
||||
};
|
||||
|
||||
|
|
@ -158,6 +168,11 @@ prop2monitor (SystemloadProperty p)
|
|||
case PROP_SWAP_LABEL:
|
||||
case PROP_SWAP_COLOR:
|
||||
return SWAP_MONITOR;
|
||||
case PROP_ZRAM_ENABLED:
|
||||
case PROP_ZRAM_USE_LABEL:
|
||||
case PROP_ZRAM_LABEL:
|
||||
case PROP_ZRAM_COLOR:
|
||||
return ZRAM_MONITOR;
|
||||
default:
|
||||
/* Ideally, this codepath is never reached */
|
||||
return CPU_MONITOR;
|
||||
|
|
@ -339,6 +354,46 @@ systemload_config_class_init (SystemloadConfigClass *klass)
|
|||
GDK_TYPE_RGBA,
|
||||
GParamFlags (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_ZRAM_ENABLED,
|
||||
g_param_spec_boolean ("zram-enabled", NULL, NULL,
|
||||
TRUE,
|
||||
GParamFlags (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_ZRAM_USE_LABEL,
|
||||
g_param_spec_boolean ("zram-use-label", NULL, NULL,
|
||||
TRUE,
|
||||
GParamFlags (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_ZRAM_LABEL,
|
||||
g_param_spec_string ("zram-label", NULL, NULL,
|
||||
DEFAULT_LABEL[ZRAM_MONITOR],
|
||||
GParamFlags (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_ZRAM_COLOR,
|
||||
g_param_spec_boxed ("zram-color",
|
||||
NULL, NULL,
|
||||
GDK_TYPE_RGBA,
|
||||
GParamFlags (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
/* Default FALSE: "used memory" keeps its literal meaning - RAM that is
|
||||
* occupied and unavailable, zram's own footprint included. */
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_MEMORY_EXCLUDE_ZRAM,
|
||||
g_param_spec_boolean ("memory-exclude-zram", NULL, NULL,
|
||||
FALSE,
|
||||
GParamFlags (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
/* Empty = the built-in localized "1d 2h 3m" text; see format_uptime() */
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_UPTIME_FORMAT,
|
||||
g_param_spec_string ("uptime-format", NULL, NULL,
|
||||
"",
|
||||
GParamFlags (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
systemload_config_signals[CONFIGURATION_CHANGED] =
|
||||
g_signal_new (g_intern_static_string ("configuration-changed"),
|
||||
G_TYPE_FROM_CLASS (gobject_class),
|
||||
|
|
@ -357,6 +412,7 @@ systemload_config_init (SystemloadConfig *config)
|
|||
config->timeout_seconds = DEFAULT_TIMEOUT_SECONDS;
|
||||
config->system_monitor_command = g_strdup (DEFAULT_SYSTEM_MONITOR_COMMAND);
|
||||
config->uptime = true;
|
||||
config->uptime_format = g_strdup ("");
|
||||
for (gsize i = 0; i < G_N_ELEMENTS (config->monitor); i++)
|
||||
{
|
||||
config->monitor[i].enabled = true;
|
||||
|
|
@ -376,6 +432,7 @@ systemload_config_finalize (GObject *object)
|
|||
xfconf_shutdown();
|
||||
g_free (config->property_base);
|
||||
g_free (config->system_monitor_command);
|
||||
g_free (config->uptime_format);
|
||||
for (gsize i = 0; i < G_N_ELEMENTS (config->monitor); i++)
|
||||
g_free (config->monitor[i].label);
|
||||
|
||||
|
|
@ -411,10 +468,19 @@ systemload_config_get_property (GObject *object,
|
|||
g_value_set_boolean (value, config->uptime);
|
||||
break;
|
||||
|
||||
case PROP_UPTIME_FORMAT:
|
||||
g_value_set_string (value, config->uptime_format);
|
||||
break;
|
||||
|
||||
case PROP_MEMORY_EXCLUDE_ZRAM:
|
||||
g_value_set_boolean (value, config->memory_exclude_zram);
|
||||
break;
|
||||
|
||||
case PROP_CPU_ENABLED:
|
||||
case PROP_MEMORY_ENABLED:
|
||||
case PROP_NETWORK_ENABLED:
|
||||
case PROP_SWAP_ENABLED:
|
||||
case PROP_ZRAM_ENABLED:
|
||||
g_value_set_boolean (value, config->monitor[prop2monitor(prop_id)].enabled);
|
||||
break;
|
||||
|
||||
|
|
@ -422,6 +488,7 @@ systemload_config_get_property (GObject *object,
|
|||
case PROP_MEMORY_USE_LABEL:
|
||||
case PROP_NETWORK_USE_LABEL:
|
||||
case PROP_SWAP_USE_LABEL:
|
||||
case PROP_ZRAM_USE_LABEL:
|
||||
g_value_set_boolean (value, config->monitor[prop2monitor(prop_id)].use_label);
|
||||
break;
|
||||
|
||||
|
|
@ -429,6 +496,7 @@ systemload_config_get_property (GObject *object,
|
|||
case PROP_MEMORY_LABEL:
|
||||
case PROP_NETWORK_LABEL:
|
||||
case PROP_SWAP_LABEL:
|
||||
case PROP_ZRAM_LABEL:
|
||||
g_value_set_string (value, config->monitor[prop2monitor(prop_id)].label);
|
||||
break;
|
||||
|
||||
|
|
@ -436,6 +504,7 @@ systemload_config_get_property (GObject *object,
|
|||
case PROP_MEMORY_COLOR:
|
||||
case PROP_NETWORK_COLOR:
|
||||
case PROP_SWAP_COLOR:
|
||||
case PROP_ZRAM_COLOR:
|
||||
g_value_set_boxed (value, &config->monitor[prop2monitor(prop_id)].color);
|
||||
break;
|
||||
|
||||
|
|
@ -502,6 +571,28 @@ systemload_config_set_property (GObject *object,
|
|||
}
|
||||
break;
|
||||
|
||||
case PROP_UPTIME_FORMAT:
|
||||
val_string = g_value_get_string (value);
|
||||
if (g_strcmp0 (config->uptime_format, val_string) != 0)
|
||||
{
|
||||
g_free (config->uptime_format);
|
||||
/* xfconf may hand over NULL for an unset key; keep "" for "default" */
|
||||
config->uptime_format = g_strdup (val_string ? val_string : "");
|
||||
g_object_notify (G_OBJECT (config), "uptime-format");
|
||||
g_signal_emit (G_OBJECT (config), systemload_config_signals [CONFIGURATION_CHANGED], 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_MEMORY_EXCLUDE_ZRAM:
|
||||
val_bool = g_value_get_boolean (value);
|
||||
if (config->memory_exclude_zram != val_bool)
|
||||
{
|
||||
config->memory_exclude_zram = val_bool;
|
||||
g_object_notify (G_OBJECT (config), "memory-exclude-zram");
|
||||
g_signal_emit (G_OBJECT (config), systemload_config_signals [CONFIGURATION_CHANGED], 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_CPU_ENABLED:
|
||||
val_bool = g_value_get_boolean (value);
|
||||
if (config->monitor[CPU_MONITOR].enabled != val_bool)
|
||||
|
|
@ -694,6 +785,54 @@ systemload_config_set_property (GObject *object,
|
|||
g_boxed_free (GDK_TYPE_RGBA, val_rgba);
|
||||
break;
|
||||
|
||||
case PROP_ZRAM_ENABLED:
|
||||
val_bool = g_value_get_boolean (value);
|
||||
if (config->monitor[ZRAM_MONITOR].enabled != val_bool)
|
||||
{
|
||||
config->monitor[ZRAM_MONITOR].enabled = val_bool;
|
||||
g_object_notify (G_OBJECT (config), "zram-enabled");
|
||||
g_signal_emit (G_OBJECT (config), systemload_config_signals [CONFIGURATION_CHANGED], 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_ZRAM_USE_LABEL:
|
||||
val_bool = g_value_get_boolean (value);
|
||||
if (config->monitor[ZRAM_MONITOR].use_label != val_bool)
|
||||
{
|
||||
config->monitor[ZRAM_MONITOR].use_label = val_bool;
|
||||
g_object_notify (G_OBJECT (config), "zram-use-label");
|
||||
g_signal_emit (G_OBJECT (config), systemload_config_signals [CONFIGURATION_CHANGED], 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_ZRAM_LABEL:
|
||||
val_string = g_value_get_string (value);
|
||||
if (g_strcmp0 (config->monitor[ZRAM_MONITOR].label, val_string) != 0)
|
||||
{
|
||||
g_free (config->monitor[ZRAM_MONITOR].label);
|
||||
config->monitor[ZRAM_MONITOR].label = g_value_dup_string (value);
|
||||
g_object_notify (G_OBJECT (config), "zram-label");
|
||||
g_signal_emit (G_OBJECT (config), systemload_config_signals [CONFIGURATION_CHANGED], 0);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_ZRAM_COLOR:
|
||||
val_rgba = (GdkRGBA*) g_value_dup_boxed (value);
|
||||
if (!rgba_equal (config->monitor[ZRAM_MONITOR].color, *val_rgba))
|
||||
{
|
||||
config->monitor[ZRAM_MONITOR].color = *val_rgba;
|
||||
g_object_notify (G_OBJECT (config), "zram-color");
|
||||
g_signal_emit (G_OBJECT (config), systemload_config_signals [CONFIGURATION_CHANGED], 0);
|
||||
}
|
||||
if (is_default_color (ZRAM_MONITOR, val_rgba))
|
||||
{
|
||||
char *property = g_strconcat (config->property_base, "/zram/color", NULL);
|
||||
xfconf_channel_reset_property (config->channel, property, TRUE);
|
||||
g_free (property);
|
||||
}
|
||||
g_boxed_free (GDK_TYPE_RGBA, val_rgba);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
@ -734,6 +873,22 @@ systemload_config_get_uptime_enabled (const SystemloadConfig *config)
|
|||
return config->uptime;
|
||||
}
|
||||
|
||||
const gchar*
|
||||
systemload_config_get_uptime_format (const SystemloadConfig *config)
|
||||
{
|
||||
g_return_val_if_fail (IS_SYSTEMLOAD_CONFIG (config), "");
|
||||
|
||||
return config->uptime_format;
|
||||
}
|
||||
|
||||
bool
|
||||
systemload_config_get_memory_exclude_zram (const SystemloadConfig *config)
|
||||
{
|
||||
g_return_val_if_fail (IS_SYSTEMLOAD_CONFIG (config), false);
|
||||
|
||||
return config->memory_exclude_zram;
|
||||
}
|
||||
|
||||
bool
|
||||
systemload_config_get_enabled (const SystemloadConfig *config, SystemloadMonitor monitor)
|
||||
{
|
||||
|
|
@ -809,6 +964,10 @@ systemload_config_new (const gchar *property_base)
|
|||
xfconf_g_property_bind (channel, property, G_TYPE_BOOLEAN, config, "uptime-enabled");
|
||||
g_free (property);
|
||||
|
||||
property = g_strconcat (property_base, "/uptime/format", NULL);
|
||||
xfconf_g_property_bind (channel, property, G_TYPE_STRING, config, "uptime-format");
|
||||
g_free (property);
|
||||
|
||||
property = g_strconcat (property_base, "/cpu/enabled", NULL);
|
||||
xfconf_g_property_bind (channel, property, G_TYPE_BOOLEAN, config, "cpu-enabled");
|
||||
g_free (property);
|
||||
|
|
@ -872,6 +1031,26 @@ systemload_config_new (const gchar *property_base)
|
|||
property = g_strconcat (property_base, "/swap/color", NULL);
|
||||
xfconf_g_property_bind_gdkrgba (channel, property, config, "swap-color");
|
||||
g_free (property);
|
||||
|
||||
property = g_strconcat (property_base, "/zram/enabled", NULL);
|
||||
xfconf_g_property_bind (channel, property, G_TYPE_BOOLEAN, config, "zram-enabled");
|
||||
g_free (property);
|
||||
|
||||
property = g_strconcat (property_base, "/zram/use-label", NULL);
|
||||
xfconf_g_property_bind (channel, property, G_TYPE_BOOLEAN, config, "zram-use-label");
|
||||
g_free (property);
|
||||
|
||||
property = g_strconcat (property_base, "/zram/label", NULL);
|
||||
xfconf_g_property_bind (channel, property, G_TYPE_STRING, config, "zram-label");
|
||||
g_free (property);
|
||||
|
||||
property = g_strconcat (property_base, "/zram/color", NULL);
|
||||
xfconf_g_property_bind_gdkrgba (channel, property, config, "zram-color");
|
||||
g_free (property);
|
||||
|
||||
property = g_strconcat (property_base, "/memory/exclude-zram", NULL);
|
||||
xfconf_g_property_bind (channel, property, G_TYPE_BOOLEAN, config, "memory-exclude-zram");
|
||||
g_free (property);
|
||||
}
|
||||
|
||||
return config;
|
||||
|
|
|
|||
|
|
@ -26,11 +26,19 @@
|
|||
#define MIN_TIMEOUT 500
|
||||
#define MAX_TIMEOUT 10000
|
||||
|
||||
/*
|
||||
* ZRAM_MONITOR is appended at the end on purpose: the numeric values of the
|
||||
* existing entries index both the config array and the settings already
|
||||
* stored in xfconf. Inserting in the middle would silently reassign the
|
||||
* user's colours and labels to the wrong monitors.
|
||||
*/
|
||||
enum SystemloadMonitor {
|
||||
CPU_MONITOR,
|
||||
MEM_MONITOR,
|
||||
NET_MONITOR,
|
||||
SWAP_MONITOR,
|
||||
ZRAM_MONITOR,
|
||||
N_MONITORS,
|
||||
};
|
||||
|
||||
typedef struct _SystemloadConfigClass SystemloadConfigClass;
|
||||
|
|
@ -55,6 +63,20 @@ guint systemload_config_get_timeout (const Syste
|
|||
guint systemload_config_get_timeout_seconds (const SystemloadConfig *config);
|
||||
const gchar *systemload_config_get_system_monitor_command (const SystemloadConfig *config);
|
||||
bool systemload_config_get_uptime_enabled (const SystemloadConfig *config);
|
||||
/* "" means the built-in format; syntax is documented at format_uptime() */
|
||||
const gchar *systemload_config_get_uptime_format (const SystemloadConfig *config);
|
||||
|
||||
/*
|
||||
* When true, the RAM occupied by zram is subtracted from the memory monitor.
|
||||
*
|
||||
* Both readings are truthful, they answer different questions. Included (the
|
||||
* default) means "how much RAM is unavailable" - the literal sense of "used",
|
||||
* and what every other monitor reports; the zram bar is then a breakdown of a
|
||||
* part of it, so the two bars overlap. Excluded means "how much RAM the system
|
||||
* spends on its actual work" - the memory and zram bars then add up to the
|
||||
* occupied total without counting anything twice.
|
||||
*/
|
||||
bool systemload_config_get_memory_exclude_zram (const SystemloadConfig *config);
|
||||
|
||||
bool systemload_config_get_enabled (const SystemloadConfig *config, SystemloadMonitor monitor);
|
||||
bool systemload_config_get_use_label (const SystemloadConfig *config, SystemloadMonitor monitor);
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@
|
|||
#include "plugin.h"
|
||||
#include "settings.h"
|
||||
#include "uptime.h"
|
||||
#include "zram.h"
|
||||
|
||||
|
||||
|
||||
|
|
@ -88,7 +89,7 @@ struct t_global_monitor {
|
|||
bool use_timeout_seconds;
|
||||
guint timeout_id;
|
||||
t_command command;
|
||||
t_monitor *monitor[4];
|
||||
t_monitor *monitor[N_MONITORS];
|
||||
t_uptime_monitor uptime;
|
||||
#ifdef HAVE_UPOWER_GLIB
|
||||
UpClient *upower;
|
||||
|
|
@ -97,9 +98,12 @@ struct t_global_monitor {
|
|||
|
||||
|
||||
|
||||
/* zram sits between memory and swap: that is where it sits physically too -
|
||||
* data already pushed out of RAM, but not yet spilled onto the disk. */
|
||||
static const SystemloadMonitor VISUAL_ORDER[] = {
|
||||
CPU_MONITOR,
|
||||
MEM_MONITOR,
|
||||
ZRAM_MONITOR,
|
||||
SWAP_MONITOR,
|
||||
NET_MONITOR,
|
||||
};
|
||||
|
|
@ -168,7 +172,10 @@ static void
|
|||
update_monitors(t_global_monitor *global)
|
||||
{
|
||||
const SystemloadConfig *config = global->config;
|
||||
gulong MTotal = 0, MUsed = 0, NTotal = 0, STotal = 0, SUsed = 0;
|
||||
gulong MTotal = 0, MUsed = 0, NTotal = 0, STotal = 0, SUsed = 0, MZram = 0;
|
||||
gulong ZPhys = 0, ZStored = 0;
|
||||
gdouble ZRatio = 0.0;
|
||||
bool ZValid = false;
|
||||
|
||||
for(gsize i = 0; i < G_N_ELEMENTS (global->monitor); i++)
|
||||
global->monitor[i]->value_read = 0;
|
||||
|
|
@ -181,10 +188,32 @@ update_monitors(t_global_monitor *global)
|
|||
gulong mem, swap;
|
||||
if (read_memswap(&mem, &swap, &MTotal, &MUsed, &STotal, &SUsed) == 0)
|
||||
{
|
||||
/*
|
||||
* MUsed as returned includes the RAM held by zram - that memory is
|
||||
* genuinely occupied. Whether the memory bar should show it is a
|
||||
* question of what the bar is meant to answer, so it is left to
|
||||
* the user; see systemload_config_get_memory_exclude_zram().
|
||||
*/
|
||||
MZram = read_zram_phys();
|
||||
if (systemload_config_get_memory_exclude_zram (config))
|
||||
{
|
||||
MUsed = (MUsed > MZram) ? (MUsed - MZram) : 0;
|
||||
mem = (MTotal > 0) ? (MUsed * 100 / MTotal) : 0;
|
||||
}
|
||||
|
||||
global->monitor[MEM_MONITOR]->value_read = mem;
|
||||
global->monitor[SWAP_MONITOR]->value_read = swap;
|
||||
}
|
||||
}
|
||||
if (systemload_config_get_enabled (config, ZRAM_MONITOR))
|
||||
{
|
||||
gulong zram;
|
||||
if (read_zram (&zram, &ZPhys, &ZStored, &ZRatio) == 0)
|
||||
{
|
||||
global->monitor[ZRAM_MONITOR]->value_read = zram;
|
||||
ZValid = true;
|
||||
}
|
||||
}
|
||||
if (systemload_config_get_enabled (config, NET_MONITOR))
|
||||
{
|
||||
gulong net;
|
||||
|
|
@ -215,8 +244,26 @@ update_monitors(t_global_monitor *global)
|
|||
|
||||
if (systemload_config_get_enabled (config, MEM_MONITOR))
|
||||
{
|
||||
gchar tooltip[128];
|
||||
gchar tooltip[192];
|
||||
|
||||
/* Always spell out the zram share, whichever way the bar is counted:
|
||||
* that way the number on screen is never ambiguous. */
|
||||
if (MZram > 0)
|
||||
{
|
||||
if (systemload_config_get_memory_exclude_zram (config))
|
||||
g_snprintf(tooltip, sizeof(tooltip),
|
||||
_("Memory: %ldMB of %ldMB used, excluding %ldMB held by zram"),
|
||||
MUsed >> 10, MTotal >> 10, MZram >> 10);
|
||||
else
|
||||
g_snprintf(tooltip, sizeof(tooltip),
|
||||
_("Memory: %ldMB of %ldMB used, including %ldMB held by zram"),
|
||||
MUsed >> 10, MTotal >> 10, MZram >> 10);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_snprintf(tooltip, sizeof(tooltip), _("Memory: %ldMB of %ldMB used"), MUsed >> 10 , MTotal >> 10);
|
||||
}
|
||||
|
||||
set_tooltip(global->monitor[MEM_MONITOR]->ebox, tooltip);
|
||||
}
|
||||
|
||||
|
|
@ -227,14 +274,31 @@ update_monitors(t_global_monitor *global)
|
|||
set_tooltip(global->monitor[NET_MONITOR]->ebox, tooltip);
|
||||
}
|
||||
|
||||
if (systemload_config_get_enabled (config, ZRAM_MONITOR))
|
||||
{
|
||||
gchar tooltip[192];
|
||||
|
||||
if (ZValid && ZStored > 0)
|
||||
g_snprintf(tooltip, sizeof(tooltip),
|
||||
_("ZRAM: %ldMB of RAM holds %ldMB of data (%.2f:1)"),
|
||||
ZPhys >> 10, ZStored >> 10, ZRatio);
|
||||
else if (ZValid)
|
||||
g_snprintf(tooltip, sizeof(tooltip), _("ZRAM: empty"));
|
||||
else
|
||||
g_snprintf(tooltip, sizeof(tooltip), _("No zram device"));
|
||||
|
||||
set_tooltip(global->monitor[ZRAM_MONITOR]->ebox, tooltip);
|
||||
}
|
||||
|
||||
if (systemload_config_get_enabled (config, SWAP_MONITOR))
|
||||
{
|
||||
gchar tooltip[128];
|
||||
|
||||
/* Disk-backed swap only; zram is reported by its own monitor */
|
||||
if (STotal)
|
||||
g_snprintf(tooltip, sizeof(tooltip), _("Swap: %ldMB of %ldMB used"), SUsed >> 10, STotal >> 10);
|
||||
g_snprintf(tooltip, sizeof(tooltip), _("Disk swap: %ldMB of %ldMB used"), SUsed >> 10, STotal >> 10);
|
||||
else
|
||||
g_snprintf(tooltip, sizeof(tooltip), _("No swap"));
|
||||
g_snprintf(tooltip, sizeof(tooltip), _("No disk swap"));
|
||||
|
||||
set_tooltip(global->monitor[SWAP_MONITOR]->ebox, tooltip);
|
||||
}
|
||||
|
|
@ -248,22 +312,33 @@ update_monitors(t_global_monitor *global)
|
|||
gint hours = (global->uptime.value_read / 3600) % 24;
|
||||
gint mins = (global->uptime.value_read / 60) % 60;
|
||||
|
||||
g_snprintf(days_str[0], sizeof(days_str), _("%dd"), days);
|
||||
g_snprintf(hours_str[0], sizeof(hours_str), _("%dh"), hours);
|
||||
g_snprintf(mins_str[0], sizeof(mins_str), _("%dm"), mins);
|
||||
/* sizeof of one element: the whole [2][32] array is 64 bytes and
|
||||
* would let g_snprintf write past the 32-byte buffer */
|
||||
g_snprintf(days_str[0], sizeof(days_str[0]), _("%dd"), days);
|
||||
g_snprintf(hours_str[0], sizeof(hours_str[0]), _("%dh"), hours);
|
||||
g_snprintf(mins_str[0], sizeof(mins_str[0]), _("%dm"), mins);
|
||||
|
||||
g_snprintf(days_str[1], sizeof(days_str), ngettext("%d day", "%d days", days), days);
|
||||
g_snprintf(hours_str[1], sizeof(hours_str), ngettext("%d hour", "%d hours", hours), hours);
|
||||
g_snprintf(mins_str[1], sizeof(mins_str), ngettext("%d minute", "%d minutes", mins), mins);
|
||||
g_snprintf(days_str[1], sizeof(days_str[1]), ngettext("%d day", "%d days", days), days);
|
||||
g_snprintf(hours_str[1], sizeof(hours_str[1]), ngettext("%d hour", "%d hours", hours), hours);
|
||||
g_snprintf(mins_str[1], sizeof(mins_str[1]), ngettext("%d minute", "%d minutes", mins), mins);
|
||||
|
||||
g_snprintf(tooltip, sizeof(tooltip), _("Uptime: %s, %s, %s"), days_str[1], hours_str[1], mins_str[1]);
|
||||
|
||||
const gchar *format = systemload_config_get_uptime_format (config);
|
||||
if (format != NULL && format[0] != '\0')
|
||||
{
|
||||
gchar *custom = format_uptime (format, global->uptime.value_read);
|
||||
set_label_text(GTK_LABEL(global->uptime.label), custom);
|
||||
g_free (custom);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (days > 0)
|
||||
g_snprintf(text, sizeof(text), "%s %s %s", days_str[0], hours_str[0], mins_str[0]);
|
||||
else
|
||||
g_snprintf(text, sizeof(text), "%s %s", hours_str[0], mins_str[0]);
|
||||
|
||||
g_snprintf(tooltip, sizeof(tooltip), _("Uptime: %s, %s, %s"), days_str[1], hours_str[1], mins_str[1]);
|
||||
|
||||
set_label_text(GTK_LABEL(global->uptime.label), text);
|
||||
}
|
||||
set_tooltip(global->uptime.ebox, tooltip);
|
||||
}
|
||||
}
|
||||
|
|
@ -344,6 +419,8 @@ create_monitor (t_global_monitor *global)
|
|||
gtk_event_box_set_visible_window(GTK_EVENT_BOX(global->uptime.ebox), FALSE);
|
||||
|
||||
global->uptime.label = gtk_label_new("");
|
||||
/* A format with \n gives several lines; keep them centred as a block */
|
||||
gtk_label_set_justify(GTK_LABEL(global->uptime.label), GTK_JUSTIFY_CENTER);
|
||||
|
||||
gtk_widget_show(global->uptime.label);
|
||||
gtk_container_add(GTK_CONTAINER(global->uptime.ebox),
|
||||
|
|
@ -669,12 +746,18 @@ static GtkWidget *new_label (GtkGrid *grid, guint row, const gchar *labeltext, G
|
|||
return label;
|
||||
}
|
||||
|
||||
/* Create a new monitor setting with gtkswitch, and eventually a color button and a checkbox + entry */
|
||||
/* Create a new monitor setting with gtkswitch, and eventually a color button and a checkbox + entry
|
||||
*
|
||||
* extra_toggle_setting: optional boolean property of the config object to
|
||||
* expose as a checkbox under the label row; NULL for none. Used by the memory
|
||||
* monitor for "exclude zram". */
|
||||
static void
|
||||
new_monitor_setting (t_global_monitor *global,
|
||||
GtkGrid *grid, int position,
|
||||
const gchar *title, bool color,
|
||||
const gchar *setting)
|
||||
const gchar *setting,
|
||||
const gchar *extra_toggle_setting = NULL,
|
||||
const gchar *extra_toggle_text = NULL)
|
||||
{
|
||||
GtkWidget *sw, *label;
|
||||
gchar *markup, *setting_name;
|
||||
|
|
@ -747,6 +830,50 @@ new_monitor_setting (t_global_monitor *global,
|
|||
g_free (setting_name);
|
||||
gtk_grid_attach(GTK_GRID(subgrid), button, 2, 0, 1, 1);
|
||||
}
|
||||
|
||||
if (extra_toggle_setting != NULL)
|
||||
{
|
||||
GtkWidget *check = gtk_check_button_new_with_mnemonic (extra_toggle_text);
|
||||
gtk_widget_set_margin_start (check, 12);
|
||||
g_object_bind_property (G_OBJECT (global->config), extra_toggle_setting,
|
||||
G_OBJECT (check), "active",
|
||||
GBindingFlags (G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
|
||||
gtk_grid_attach (GTK_GRID(subgrid), check, 0, 1, 3, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkWidget *revealer = gtk_revealer_new ();
|
||||
GtkWidget *subgrid = gtk_grid_new ();
|
||||
gtk_container_add (GTK_CONTAINER (revealer), subgrid);
|
||||
gtk_revealer_set_reveal_child (GTK_REVEALER (revealer), TRUE);
|
||||
g_object_set_data (G_OBJECT(sw), "sensitive_widget", revealer);
|
||||
gtk_grid_attach(GTK_GRID(grid), revealer, 0, position + 1, 2, 1);
|
||||
gtk_grid_set_column_spacing (GTK_GRID(subgrid), 12);
|
||||
gtk_grid_set_row_spacing (GTK_GRID(subgrid), 6);
|
||||
|
||||
label = gtk_label_new_with_mnemonic (_("_Format:"));
|
||||
gtk_widget_set_halign (label, GTK_ALIGN_START);
|
||||
gtk_widget_set_valign (label, GTK_ALIGN_CENTER);
|
||||
gtk_widget_set_margin_start (label, 12);
|
||||
gtk_grid_attach (GTK_GRID(subgrid), label, 0, 0, 1, 1);
|
||||
|
||||
GtkWidget *entry = gtk_entry_new ();
|
||||
gtk_widget_set_hexpand (entry, TRUE);
|
||||
gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
|
||||
gtk_entry_set_placeholder_text (GTK_ENTRY (entry), _("built-in format"));
|
||||
gtk_widget_set_tooltip_text (entry,
|
||||
_("%d days, %h hours, %m minutes, %s seconds\n"
|
||||
"%H %M %S - the same with two digits (07)\n"
|
||||
"%t - total hours, %% - percent sign\n"
|
||||
"\\n - new line\n"
|
||||
"{...} - hidden when every number inside is 0\n"
|
||||
"Example: {%dd }%H:%M\n"
|
||||
"Leave empty for the built-in format"));
|
||||
g_object_bind_property (G_OBJECT (global->config), "uptime-format",
|
||||
G_OBJECT (entry), "text",
|
||||
GBindingFlags (G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL));
|
||||
gtk_grid_attach(GTK_GRID(subgrid), entry, 1, 0, 1, 1);
|
||||
}
|
||||
|
||||
switch_cb (GTK_SWITCH (sw), enabled, global);
|
||||
|
|
@ -758,18 +885,22 @@ monitor_create_options(XfcePanelPlugin *plugin, t_global_monitor *global)
|
|||
SystemloadConfig *config = global->config;
|
||||
GtkWidget *label, *entry, *button, *box;
|
||||
|
||||
/* Indices must match enum SystemloadMonitor; uptime has no enum entry and
|
||||
* therefore sits at N_MONITORS, right after the last real monitor. */
|
||||
static const gchar *FRAME_TEXT[] = {
|
||||
N_ ("CPU monitor"),
|
||||
N_ ("Memory monitor"),
|
||||
N_ ("Network monitor"),
|
||||
N_ ("Swap monitor"),
|
||||
N_ ("ZRAM monitor"),
|
||||
N_ ("Uptime monitor")
|
||||
};
|
||||
static const gchar *SETTING_TEXT[] = {
|
||||
"cpu",
|
||||
"memory",
|
||||
"network",
|
||||
"swap"
|
||||
"swap",
|
||||
"zram"
|
||||
};
|
||||
|
||||
xfce_panel_plugin_block_menu (plugin);
|
||||
|
|
@ -856,12 +987,16 @@ monitor_create_options(XfcePanelPlugin *plugin, t_global_monitor *global)
|
|||
new_monitor_setting (global, GTK_GRID(grid), 4 + 2 * i,
|
||||
_(FRAME_TEXT[monitor]),
|
||||
true,
|
||||
SETTING_TEXT[monitor]);
|
||||
SETTING_TEXT[monitor],
|
||||
(monitor == MEM_MONITOR) ? "memory-exclude-zram" : NULL,
|
||||
(monitor == MEM_MONITOR)
|
||||
? _("Do not count the RAM held by _zram")
|
||||
: NULL);
|
||||
}
|
||||
|
||||
/* Uptime monitor options */
|
||||
new_monitor_setting (global, GTK_GRID(grid), 4 + 2*G_N_ELEMENTS (global->monitor),
|
||||
_(FRAME_TEXT[4]), FALSE, "uptime");
|
||||
_(FRAME_TEXT[N_MONITORS]), FALSE, "uptime");
|
||||
|
||||
gtk_widget_show_all (dlg);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -138,3 +138,86 @@ gulong read_uptime()
|
|||
#else
|
||||
#error "Your platform is not yet supported"
|
||||
#endif
|
||||
|
||||
/* Platform independent, hence outside the #if chain above. The scan is
|
||||
* byte-wise: every special character is ASCII and UTF-8 continuation bytes
|
||||
* never collide with ASCII, so Cyrillic text passes through untouched. */
|
||||
gchar *format_uptime(const gchar *format, gulong uptime)
|
||||
{
|
||||
const gulong days = uptime / 86400;
|
||||
const gulong hours = (uptime / 3600) % 24;
|
||||
const gulong mins = (uptime / 60) % 60;
|
||||
const gulong secs = uptime % 60;
|
||||
const gulong total_hours = uptime / 3600;
|
||||
|
||||
GString *out = g_string_new(NULL);
|
||||
GString *group = NULL; /* non-NULL while inside {...} */
|
||||
gboolean group_nonzero = FALSE;
|
||||
|
||||
for (const gchar *p = format ? format : ""; *p; p++)
|
||||
{
|
||||
GString *dst = group ? group : out;
|
||||
|
||||
if (*p == '\\' && p[1] != '\0')
|
||||
{
|
||||
p++;
|
||||
g_string_append_c(dst, (*p == 'n') ? '\n' : *p);
|
||||
}
|
||||
else if (*p == '{' && group == NULL)
|
||||
{
|
||||
group = g_string_new(NULL);
|
||||
group_nonzero = FALSE;
|
||||
}
|
||||
else if (*p == '}' && group != NULL)
|
||||
{
|
||||
if (group_nonzero)
|
||||
g_string_append_len(out, group->str, group->len);
|
||||
g_string_free(group, TRUE);
|
||||
group = NULL;
|
||||
}
|
||||
else if (*p == '%' && p[1] != '\0')
|
||||
{
|
||||
p++;
|
||||
gulong value;
|
||||
gboolean padded = FALSE;
|
||||
switch (*p)
|
||||
{
|
||||
case 'd': value = days; break;
|
||||
case 'h': value = hours; break;
|
||||
case 'm': value = mins; break;
|
||||
case 's': value = secs; break;
|
||||
case 'H': value = hours; padded = TRUE; break;
|
||||
case 'M': value = mins; padded = TRUE; break;
|
||||
case 'S': value = secs; padded = TRUE; break;
|
||||
case 't': value = total_hours; break;
|
||||
case '%':
|
||||
g_string_append_c(dst, '%');
|
||||
continue;
|
||||
default:
|
||||
g_string_append_c(dst, '%');
|
||||
g_string_append_c(dst, *p);
|
||||
continue;
|
||||
}
|
||||
if (padded)
|
||||
g_string_append_printf(dst, "%02lu", value);
|
||||
else
|
||||
g_string_append_printf(dst, "%lu", value);
|
||||
if (value != 0)
|
||||
group_nonzero = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_string_append_c(dst, *p);
|
||||
}
|
||||
}
|
||||
|
||||
if (group != NULL)
|
||||
{
|
||||
/* Unclosed block: show it as typed rather than hiding the rest */
|
||||
g_string_append_c(out, '{');
|
||||
g_string_append_len(out, group->str, group->len);
|
||||
g_string_free(group, TRUE);
|
||||
}
|
||||
|
||||
return g_string_free(out, FALSE);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,4 +33,19 @@
|
|||
|
||||
gulong read_uptime();
|
||||
|
||||
/*
|
||||
* Render an uptime (in seconds) through a user format string.
|
||||
*
|
||||
* %d days %h hours (0-23) %m minutes (0-59) %s seconds (0-59)
|
||||
* %H %M %S the same, always two digits ("07")
|
||||
* %t total hours %% a literal percent sign
|
||||
* \n line break \\ \{ \} \% the character itself
|
||||
* {...} the block is dropped when every number inside it is 0
|
||||
*
|
||||
* Unknown %x sequences and an unclosed '{' are kept as literal text, so a
|
||||
* typo is visible on the panel instead of silently disappearing.
|
||||
* Returns a newly allocated string; free with g_free().
|
||||
*/
|
||||
gchar *format_uptime(const gchar *format, gulong uptime);
|
||||
|
||||
#endif /* _XFCE_SYSTEMLOAD_UPTIME_H_ */
|
||||
|
|
|
|||
226
panel-plugin/zram.cc
Normal file
226
panel-plugin/zram.cc
Normal file
|
|
@ -0,0 +1,226 @@
|
|||
/*
|
||||
* This file is part of Xfce (https://gitlab.xfce.org).
|
||||
*
|
||||
* zram monitor: local addition, not part of upstream.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES
|
||||
* ARE DISCLAIMED.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "zram.h"
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* /sys/block/zramN/mm_stat is a single line of whitespace-separated numbers:
|
||||
*
|
||||
* orig_data_size compr_data_size mem_used_total mem_limit mem_used_max
|
||||
* same_pages pages_compacted huge_pages [huge_pages_since]
|
||||
*
|
||||
* All sizes are in bytes. Only the first three are needed here.
|
||||
*
|
||||
* The file exists only while the device is initialised; an allocated but
|
||||
* unused zramN has no mm_stat, so a failed read is normal, not an error.
|
||||
*/
|
||||
static gboolean
|
||||
read_one_device (const gchar *devname, guint64 *orig, guint64 *compr, guint64 *used)
|
||||
{
|
||||
gchar *path = g_strdup_printf ("/sys/block/%s/mm_stat", devname);
|
||||
gchar *contents = NULL;
|
||||
gboolean ok = FALSE;
|
||||
|
||||
if (g_file_get_contents (path, &contents, NULL, NULL))
|
||||
{
|
||||
guint64 o = 0, c = 0, u = 0;
|
||||
if (sscanf (contents, "%" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT " %" G_GUINT64_FORMAT,
|
||||
&o, &c, &u) == 3)
|
||||
{
|
||||
*orig = o;
|
||||
*compr = c;
|
||||
*used = u;
|
||||
ok = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_free (contents);
|
||||
g_free (path);
|
||||
return ok;
|
||||
}
|
||||
|
||||
/* Walks /sys/block and sums mm_stat over every zram device. */
|
||||
static gboolean
|
||||
sum_devices (guint64 *orig, guint64 *compr, guint64 *used)
|
||||
{
|
||||
GDir *dir = g_dir_open ("/sys/block", 0, NULL);
|
||||
if (dir == NULL)
|
||||
return FALSE;
|
||||
|
||||
guint64 t_orig = 0, t_compr = 0, t_used = 0;
|
||||
gboolean found = FALSE;
|
||||
const gchar *name;
|
||||
|
||||
while ((name = g_dir_read_name (dir)) != NULL)
|
||||
{
|
||||
if (!g_str_has_prefix (name, "zram"))
|
||||
continue;
|
||||
|
||||
guint64 o = 0, c = 0, u = 0;
|
||||
if (read_one_device (name, &o, &c, &u))
|
||||
{
|
||||
t_orig += o;
|
||||
t_compr += c;
|
||||
t_used += u;
|
||||
found = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
g_dir_close (dir);
|
||||
|
||||
if (!found)
|
||||
return FALSE;
|
||||
|
||||
*orig = t_orig;
|
||||
*compr = t_compr;
|
||||
*used = t_used;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gulong
|
||||
mem_total_kb (void)
|
||||
{
|
||||
gchar *contents = NULL;
|
||||
gulong total = 0;
|
||||
|
||||
if (g_file_get_contents ("/proc/meminfo", &contents, NULL, NULL))
|
||||
{
|
||||
const gchar *p = strstr (contents, "MemTotal");
|
||||
if (p != NULL)
|
||||
sscanf (p + strlen ("MemTotal"), ": %lu", &total);
|
||||
}
|
||||
|
||||
g_free (contents);
|
||||
return total;
|
||||
}
|
||||
|
||||
gulong
|
||||
read_zram_phys (void)
|
||||
{
|
||||
guint64 orig = 0, compr = 0, used = 0;
|
||||
|
||||
if (!sum_devices (&orig, &compr, &used))
|
||||
return 0;
|
||||
|
||||
return (gulong) (used / 1024);
|
||||
}
|
||||
|
||||
gint
|
||||
read_zram (gulong *zram, gulong *phys_kb, gulong *stored_kb, gdouble *ratio)
|
||||
{
|
||||
guint64 orig = 0, compr = 0, used = 0;
|
||||
|
||||
if (!sum_devices (&orig, &compr, &used))
|
||||
return -1;
|
||||
|
||||
*phys_kb = (gulong) (used / 1024);
|
||||
*stored_kb = (gulong) (orig / 1024);
|
||||
*ratio = (compr > 0) ? ((gdouble) orig / (gdouble) compr) : 0.0;
|
||||
|
||||
gulong total = mem_total_kb ();
|
||||
*zram = (total > 0) ? (*phys_kb * 100 / total) : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint
|
||||
read_disk_swap (gulong *total_kb, gulong *used_kb)
|
||||
{
|
||||
gchar *contents = NULL;
|
||||
|
||||
if (!g_file_get_contents ("/proc/swaps", &contents, NULL, NULL))
|
||||
return -1;
|
||||
|
||||
gulong total = 0, used = 0;
|
||||
gchar **lines = g_strsplit (contents, "\n", -1);
|
||||
|
||||
/* Line 0 is the header: Filename Type Size Used Priority */
|
||||
for (guint i = 1; lines[i] != NULL; i++)
|
||||
{
|
||||
if (lines[i][0] == '\0')
|
||||
continue;
|
||||
|
||||
gchar **f = g_strsplit_set (lines[i], " \t", -1);
|
||||
gchar **compact = g_new0 (gchar *, g_strv_length (f) + 1);
|
||||
guint n = 0;
|
||||
|
||||
/* /proc/swaps is tab-padded, so collapse the empty fields */
|
||||
for (guint j = 0; f[j] != NULL; j++)
|
||||
if (f[j][0] != '\0')
|
||||
compact[n++] = f[j];
|
||||
|
||||
/* Skip zram: its size is the uncompressed one and it costs no disk */
|
||||
if (n >= 4 && !g_str_has_prefix (compact[0], "/dev/zram"))
|
||||
{
|
||||
total += strtoul (compact[2], NULL, 10);
|
||||
used += strtoul (compact[3], NULL, 10);
|
||||
}
|
||||
|
||||
g_free (compact);
|
||||
g_strfreev (f);
|
||||
}
|
||||
|
||||
g_strfreev (lines);
|
||||
g_free (contents);
|
||||
|
||||
*total_kb = total;
|
||||
*used_kb = used;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !__linux__ */
|
||||
|
||||
gulong
|
||||
read_zram_phys (void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
gint
|
||||
read_zram (gulong *zram, gulong *phys_kb, gulong *stored_kb, gdouble *ratio)
|
||||
{
|
||||
*zram = 0;
|
||||
*phys_kb = 0;
|
||||
*stored_kb = 0;
|
||||
*ratio = 0.0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
gint
|
||||
read_disk_swap (gulong *total_kb, gulong *used_kb)
|
||||
{
|
||||
*total_kb = 0;
|
||||
*used_kb = 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* __linux__ */
|
||||
59
panel-plugin/zram.h
Normal file
59
panel-plugin/zram.h
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* This file is part of Xfce (https://gitlab.xfce.org).
|
||||
*
|
||||
* zram monitor: local addition, not part of upstream.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES
|
||||
* ARE DISCLAIMED.
|
||||
*/
|
||||
|
||||
#ifndef _XFCE_SYSTEMLOAD_ZRAM_H_
|
||||
#define _XFCE_SYSTEMLOAD_ZRAM_H_
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
/*
|
||||
* Physical RAM occupied by all zram devices, in kB.
|
||||
* Returns 0 when there is no zram device or the data cannot be read.
|
||||
*
|
||||
* This is the number that has to be subtracted from "used memory": pages held
|
||||
* by zram are counted as used RAM, yet they are not memory of any process -
|
||||
* they are the compressed backing store of the swap.
|
||||
*/
|
||||
gulong read_zram_phys (void);
|
||||
|
||||
/*
|
||||
* zram summary across all devices.
|
||||
*
|
||||
* zram - physical footprint as a percentage of MemTotal (for the bar)
|
||||
* phys_kb - physical RAM used, kB (mem_used_total from mm_stat)
|
||||
* stored_kb - uncompressed size of the stored pages, kB (orig_data_size)
|
||||
* ratio - stored/compressed, 0.0 when nothing is stored
|
||||
*
|
||||
* Returns 0 on success, -1 when there is no zram device.
|
||||
*/
|
||||
gint read_zram (gulong *zram, gulong *phys_kb, gulong *stored_kb, gdouble *ratio);
|
||||
|
||||
/*
|
||||
* Swap totals EXCLUDING zram devices, in kB, read from /proc/swaps.
|
||||
*
|
||||
* SwapTotal/SwapFree in /proc/meminfo lump zram together with disk swap, and
|
||||
* for zram they report the uncompressed size - a number that corresponds to
|
||||
* nothing physical. The real question the swap bar should answer is "how much
|
||||
* has spilled onto the disk", and that is what this returns.
|
||||
*
|
||||
* Returns 0 on success, -1 when /proc/swaps cannot be read.
|
||||
*/
|
||||
gint read_disk_swap (gulong *total_kb, gulong *used_kb);
|
||||
|
||||
#endif /* _XFCE_SYSTEMLOAD_ZRAM_H_ */
|
||||
27
po/ru.po
27
po/ru.po
|
|
@ -176,3 +176,30 @@ msgstr "Copyright © 2003-2022\n"
|
|||
#: ../panel-plugin/uptime.c:52
|
||||
msgid "File /proc/uptime not found!"
|
||||
msgstr "Файл /proc/uptime не найден!"
|
||||
|
||||
#: ../panel-plugin/systemload.cc
|
||||
msgid "_Format:"
|
||||
msgstr "_Формат:"
|
||||
|
||||
#: ../panel-plugin/systemload.cc
|
||||
msgid "built-in format"
|
||||
msgstr "встроенный формат"
|
||||
|
||||
#: ../panel-plugin/systemload.cc
|
||||
#, no-c-format
|
||||
msgid ""
|
||||
"%d days, %h hours, %m minutes, %s seconds\n"
|
||||
"%H %M %S - the same with two digits (07)\n"
|
||||
"%t - total hours, %% - percent sign\n"
|
||||
"\\n - new line\n"
|
||||
"{...} - hidden when every number inside is 0\n"
|
||||
"Example: {%dd }%H:%M\n"
|
||||
"Leave empty for the built-in format"
|
||||
msgstr ""
|
||||
"%d дни, %h часы, %m минуты, %s секунды\n"
|
||||
"%H %M %S - то же, всегда две цифры (07)\n"
|
||||
"%t - часы всего, %% - знак процента\n"
|
||||
"\\n - новая строка\n"
|
||||
"{...} - скрывается, если все числа внутри равны 0\n"
|
||||
"Пример: {%dд }%H:%M\n"
|
||||
"Пустое поле - встроенный формат"
|
||||
|
|
|
|||
8
tests/run.sh
Normal file
8
tests/run.sh
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
# Build and run the standalone format_uptime() test.
|
||||
set -e
|
||||
dir="$(cd "$(dirname "$0")" && pwd)"
|
||||
out="$dir/build"
|
||||
mkdir -p "$out"
|
||||
g++ -Wall -Wextra -o "$out/test_format_uptime" "$dir/test_format_uptime.cc" "$dir/../panel-plugin/uptime.cc" $(pkg-config --cflags --libs glib-2.0)
|
||||
"$out/test_format_uptime"
|
||||
48
tests/test_format_uptime.cc
Normal file
48
tests/test_format_uptime.cc
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/* Standalone check of format_uptime(); not part of the package build.
|
||||
* Build and run: tests/run.sh */
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../panel-plugin/uptime.h"
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
static void check(const char *format, gulong uptime, const char *expected)
|
||||
{
|
||||
gchar *got = format_uptime(format, uptime);
|
||||
if (strcmp(got, expected) != 0)
|
||||
{
|
||||
printf("FAIL format=\"%s\" uptime=%lu\n expected=\"%s\"\n got =\"%s\"\n",
|
||||
format, uptime, expected, got);
|
||||
failures++;
|
||||
}
|
||||
g_free(got);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
const gulong T = 2 * 86400 + 5 * 3600 + 7 * 60 + 9; /* 2d 5h 7m 9s */
|
||||
|
||||
check("%d %h %m %s", T, "2 5 7 9");
|
||||
check("%H:%M:%S", T, "05:07:09");
|
||||
check("%t", T, "53");
|
||||
check("100%%", T, "100%");
|
||||
check("%x%", T, "%x%"); /* unknown and trailing % kept */
|
||||
check("line1\\nline2", T, "line1\nline2");
|
||||
check("a\\\\b \\{x\\}", T, "a\\b {x}");
|
||||
check("ends with \\", T, "ends with \\");
|
||||
|
||||
/* Cyrillic passes through byte-wise */
|
||||
check("{%dд }%hч %Mм", T, "2д 5ч 07м");
|
||||
check("{%dд }%hч %Mм", 5 * 3600 + 7 * 60, "5ч 07м"); /* zero days hidden */
|
||||
check("{%dд\\n}%H:%M", 3600, "01:00");
|
||||
check("{%dд\\n}%H:%M", T, "2д\n05:07");
|
||||
check("{const}", 0, ""); /* no numbers = all zero */
|
||||
check("{open %d", 0, "{open 0"); /* unclosed block literal */
|
||||
check("stray}", 0, "stray}");
|
||||
check("", T, "");
|
||||
check(NULL, T, "");
|
||||
|
||||
if (failures == 0)
|
||||
printf("OK all checks passed\n");
|
||||
return failures ? 1 : 0;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue