diff options
Diffstat (limited to 'src/util.cpp')
-rw-r--r-- | src/util.cpp | 637 |
1 files changed, 637 insertions, 0 deletions
diff --git a/src/util.cpp b/src/util.cpp new file mode 100644 index 0000000..044fc92 --- /dev/null +++ b/src/util.cpp @@ -0,0 +1,637 @@ +/* -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +#include <config.h> + +#include <glib/gi18n.h> +#include <glib.h> +#include <gtk/gtk.h> + +#include <glibtop/proctime.h> +#include <glibtop/procstate.h> + +#include "util.h" +#include "application.h" + +extern "C" { +#include "legacy/e_date.h" +} + + +const char* +format_process_state(guint state) +{ + const char *status; + + switch (state) + { + case GLIBTOP_PROCESS_RUNNING: + status = _("Running"); + break; + + case GLIBTOP_PROCESS_STOPPED: + status = _("Stopped"); + break; + + case GLIBTOP_PROCESS_ZOMBIE: + status = _("Zombie"); + break; + + case GLIBTOP_PROCESS_UNINTERRUPTIBLE: + status = _("Uninterruptible"); + break; + + default: + status = _("Sleeping"); + break; + } + + return status; +} + + + +static char * +mnemonic_safe_process_name(const char *process_name) +{ + const char *p; + GString *name; + + name = g_string_new (""); + + for(p = process_name; *p; ++p) + { + g_string_append_c (name, *p); + + if(*p == '_') + g_string_append_c (name, '_'); + } + + return g_string_free (name, FALSE); +} + + + +static inline unsigned divide(unsigned *q, unsigned *r, unsigned d) +{ + *q = *r / d; + *r = *r % d; + return *q != 0; +} + + +/* + * @param d: duration in centiseconds + * @type d: unsigned + */ +char * +procman::format_duration_for_display(unsigned centiseconds) +{ + unsigned weeks = 0, days = 0, hours = 0, minutes = 0, seconds = 0; + + (void)(divide(&seconds, ¢iseconds, 100) + && divide(&minutes, &seconds, 60) + && divide(&hours, &minutes, 60) + && divide(&days, &hours, 24) + && divide(&weeks, &days, 7)); + + if (weeks) + /* xgettext: weeks, days */ + return g_strdup_printf(_("%uw%ud"), weeks, days); + + if (days) + /* xgettext: days, hours (0 -> 23) */ + return g_strdup_printf(_("%ud%02uh"), days, hours); + + if (hours) + /* xgettext: hours (0 -> 23), minutes, seconds */ + return g_strdup_printf(_("%u:%02u:%02u"), hours, minutes, seconds); + + /* xgettext: minutes, seconds, centiseconds */ + return g_strdup_printf(_("%u:%02u.%02u"), minutes, seconds, centiseconds); +} + + + +GtkLabel* +procman_make_label_for_mmaps_or_ofiles(const char *format, + const char *process_name, + unsigned pid) +{ + GtkLabel* label; + char *name, *title; + + name = mnemonic_safe_process_name (process_name); + title = g_strdup_printf(format, name, pid); + label = GTK_LABEL (gtk_label_new_with_mnemonic (title)); + gtk_widget_set_valign (GTK_WIDGET (label), GTK_ALIGN_CENTER); + gtk_widget_set_halign (GTK_WIDGET (label), GTK_ALIGN_START); + + g_free (title); + g_free (name); + + return label; +} + + + +/** + * procman::format_size: + * @size: + * + * Formats the file size passed in @bytes in a way that is easy for + * the user to read. Gives the size in bytes, kibibytes, mebibytes or + * gibibytes, choosing whatever is appropriate. + * + * Returns: a newly allocated string with the size ready to be shown. + **/ + +gchar* +procman::format_size(guint64 size, bool want_bits) +{ + if (want_bits) + size *= 8; + + const GFormatSizeFlags flags = (want_bits ? G_FORMAT_SIZE_BITS : G_FORMAT_SIZE_IEC_UNITS); + return g_format_size_full(size, flags); +} + +gchar * +procman::get_nice_level (gint nice) +{ + if (nice < -7) + return _("Very High"); + else if (nice < -2) + return _("High"); + else if (nice < 3) + return _("Normal"); + else if (nice < 7) + return _("Low"); + else + return _("Very Low"); +} + +gchar * +procman::get_nice_level_with_priority (gint nice) +{ + if (nice < -7) + return _("Very High Priority"); + else if (nice < -2) + return _("High Priority"); + else if (nice < 3) + return _("Normal Priority"); + else if (nice < 7) + return _("Low Priority"); + else + return _("Very Low Priority"); +} + +gboolean +load_symbols(const char *module, ...) +{ + GModule *mod; + gboolean found_all = TRUE; + va_list args; + + mod = g_module_open(module, static_cast<GModuleFlags>(G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL)); + + if (!mod) + return FALSE; + + procman_debug("Found %s", module); + + va_start(args, module); + + while (1) { + const char *name; + void **symbol; + + name = va_arg(args, char*); + + if (!name) + break; + + symbol = va_arg(args, void**); + + if (g_module_symbol(mod, name, symbol)) { + procman_debug("Loaded %s from %s", name, module); + } + else { + procman_debug("Could not load %s from %s", name, module); + found_all = FALSE; + break; + } + } + + va_end(args); + + + if (found_all) + g_module_make_resident(mod); + else + g_module_close(mod); + + return found_all; +} + + +static gboolean +is_debug_enabled(void) +{ + static gboolean init; + static gboolean enabled; + + if (!init) { + enabled = g_getenv("GNOME_SYSTEM_MONITOR_DEBUG") != NULL; + init = TRUE; + } + + return enabled; +} + + +static double +get_relative_time(void) +{ + static unsigned long start_time; + + if (G_UNLIKELY(!start_time)) { + glibtop_proc_time buf; + glibtop_get_proc_time(&buf, getpid()); + start_time = buf.start_time; + } + + return 1e-6 * g_get_monotonic_time () - start_time; +} + +static guint64 +get_size_from_column(GtkTreeModel* model, GtkTreeIter* first, + const guint index) +{ + GValue value = { 0 }; + gtk_tree_model_get_value(model, first, index, &value); + + guint64 size; + switch (G_VALUE_TYPE(&value)) { + case G_TYPE_UINT: + size = g_value_get_uint(&value); + break; + case G_TYPE_ULONG: + size = g_value_get_ulong(&value); + break; + case G_TYPE_UINT64: + size = g_value_get_uint64(&value); + break; + default: + g_assert_not_reached(); + } + + g_value_unset(&value); + return size; +} + +void +procman_debug_real(const char *file, int line, const char *func, + const char *format, ...) +{ + va_list args; + char *msg; + + if (G_LIKELY(!is_debug_enabled())) + return; + + va_start(args, format); + msg = g_strdup_vprintf(format, args); + va_end(args); + + g_print ("[%.3f %s:%d %s] %s\n", get_relative_time(), file, line, func, msg); + + g_free(msg); +} + + + +namespace procman +{ + void size_cell_data_func(GtkTreeViewColumn *, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, + gpointer user_data) + { + const guint index = GPOINTER_TO_UINT(user_data); + + guint64 size; + GValue value = { 0 }; + + gtk_tree_model_get_value(model, iter, index, &value); + + switch (G_VALUE_TYPE(&value)) { + case G_TYPE_ULONG: + size = g_value_get_ulong(&value); + break; + + case G_TYPE_UINT64: + size = g_value_get_uint64(&value); + break; + + default: + g_assert_not_reached(); + } + + g_value_unset(&value); + + char *str = g_format_size_full(size, G_FORMAT_SIZE_IEC_UNITS); + g_object_set(renderer, "text", str, NULL); + g_free(str); + } + + + /* + Same as above but handles size == 0 as not available + */ + void size_na_cell_data_func(GtkTreeViewColumn *, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, + gpointer user_data) + { + const guint index = GPOINTER_TO_UINT(user_data); + + guint64 size; + GValue value = { 0 }; + + gtk_tree_model_get_value(model, iter, index, &value); + + switch (G_VALUE_TYPE(&value)) { + case G_TYPE_ULONG: + size = g_value_get_ulong(&value); + break; + + case G_TYPE_UINT64: + size = g_value_get_uint64(&value); + break; + + default: + g_assert_not_reached(); + } + + g_value_unset(&value); + + if (size == 0) { + char *str = g_strdup_printf ("<i>%s</i>", _("N/A")); + g_object_set(renderer, "markup", str, NULL); + g_free(str); + } + else { + char *str = g_format_size_full(size, G_FORMAT_SIZE_IEC_UNITS); + g_object_set(renderer, "text", str, NULL); + g_free(str); + } + + } + + void io_rate_cell_data_func(GtkTreeViewColumn *, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, + gpointer user_data) + { + const guint index = GPOINTER_TO_UINT(user_data); + + guint64 size; + GValue value = { 0 }; + + gtk_tree_model_get_value(model, iter, index, &value); + + switch (G_VALUE_TYPE(&value)) { + case G_TYPE_ULONG: + size = g_value_get_ulong(&value); + break; + + case G_TYPE_UINT64: + size = g_value_get_uint64(&value); + break; + + default: + g_assert_not_reached(); + } + + g_value_unset(&value); + + if (size == 0) { + char *str = g_strdup_printf ("<i>%s</i>", _("N/A")); + g_object_set(renderer, "markup", str, NULL); + g_free(str); + } + else { + g_object_set(renderer, "text", procman::format_rate(size, FALSE).c_str(), NULL); + } + + } + + /* + Cell data function to format a size value with SI units (to be used only for disk size, see bugzilla 693630) + */ + void size_si_cell_data_func(GtkTreeViewColumn *, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, + gpointer user_data) + { + const guint index = GPOINTER_TO_UINT(user_data); + + guint64 size; + GValue value = { 0 }; + + gtk_tree_model_get_value(model, iter, index, &value); + + switch (G_VALUE_TYPE(&value)) { + case G_TYPE_ULONG: + size = g_value_get_ulong(&value); + break; + + case G_TYPE_UINT64: + size = g_value_get_uint64(&value); + break; + + default: + g_assert_not_reached(); + } + + g_value_unset(&value); + + char *str = g_format_size(size); + g_object_set(renderer, "text", str, NULL); + g_free(str); + } + + void duration_cell_data_func(GtkTreeViewColumn *, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, + gpointer user_data) + { + const guint index = GPOINTER_TO_UINT(user_data); + + unsigned time; + GValue value = { 0 }; + + gtk_tree_model_get_value(model, iter, index, &value); + + switch (G_VALUE_TYPE(&value)) { + case G_TYPE_ULONG: + time = g_value_get_ulong(&value); + break; + + case G_TYPE_UINT64: + time = g_value_get_uint64(&value); + break; + + default: + g_assert_not_reached(); + } + + g_value_unset(&value); + + time = 100 * time / GsmApplication::get()->frequency; + char *str = format_duration_for_display(time); + g_object_set(renderer, "text", str, NULL); + g_free(str); + } + + + void time_cell_data_func(GtkTreeViewColumn *, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, + gpointer user_data) + { + const guint index = GPOINTER_TO_UINT(user_data); + + time_t time; + GValue value = { 0 }; + + gtk_tree_model_get_value(model, iter, index, &value); + + switch (G_VALUE_TYPE(&value)) { + case G_TYPE_ULONG: + time = g_value_get_ulong(&value); + break; + + default: + g_assert_not_reached(); + } + + g_value_unset(&value); + + char *str = procman_format_date_for_display(time); + g_object_set(renderer, "text", str, NULL); + g_free(str); + } + + void status_cell_data_func(GtkTreeViewColumn *, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, + gpointer user_data) + { + const guint index = GPOINTER_TO_UINT(user_data); + + guint state; + GValue value = { 0 }; + + gtk_tree_model_get_value(model, iter, index, &value); + + switch (G_VALUE_TYPE(&value)) { + case G_TYPE_UINT: + state = g_value_get_uint(&value); + break; + + default: + g_assert_not_reached(); + } + + g_value_unset(&value); + + const char *str = format_process_state(state); + g_object_set(renderer, "text", str, NULL); + } + + void priority_cell_data_func(GtkTreeViewColumn *, GtkCellRenderer *renderer, + GtkTreeModel *model, GtkTreeIter *iter, + gpointer user_data) + { + const guint index = GPOINTER_TO_UINT(user_data); + + GValue value = { 0 }; + + gtk_tree_model_get_value(model, iter, index, &value); + + gint priority = g_value_get_int(&value); + + g_value_unset(&value); + + g_object_set(renderer, "text", procman::get_nice_level(priority), NULL); + + } + + gint priority_compare_func(GtkTreeModel* model, GtkTreeIter* first, + GtkTreeIter* second, gpointer user_data) + { + const guint index = GPOINTER_TO_UINT(user_data); + GValue value1 = { 0 }; + GValue value2 = { 0 }; + gtk_tree_model_get_value(model, first, index, &value1); + gtk_tree_model_get_value(model, second, index, &value2); + gint result = g_value_get_int(&value1) - g_value_get_int(&value2); + g_value_unset(&value1); + g_value_unset(&value2); + return result; + } + + gint number_compare_func(GtkTreeModel* model, GtkTreeIter* first, + GtkTreeIter* second, gpointer user_data) + { + const guint index = GPOINTER_TO_UINT(user_data); + + guint64 size1, size2; + size1 = get_size_from_column(model, first, index); + size2 = get_size_from_column(model, second, index); + + if ( size2 > size1 ) + return 1; + else if ( size2 < size1 ) + return -1; + return 0; + } + + template<> + void tree_store_update<const char>(GtkTreeModel* model, GtkTreeIter* iter, int column, const char* new_value) + { + char* current_value; + + gtk_tree_model_get(model, iter, column, ¤t_value, -1); + + if (g_strcmp0(current_value, new_value) != 0) + gtk_tree_store_set(GTK_TREE_STORE(model), iter, column, new_value, -1); + + g_free(current_value); + } + + + std::string format_rate(guint64 rate, bool want_bits) + { + char* bytes = procman::format_size(rate, want_bits); + // xgettext: rate, 10MiB/s or 10Mbit/s + std::string formatted_rate(make_string(g_strdup_printf(_("%s/s"), bytes))); + g_free(bytes); + return formatted_rate; + } + + + std::string format_network(guint64 rate) + { + char* bytes = procman::format_size(rate, GsmApplication::get()->config.network_in_bits); + std::string formatted(bytes); + g_free(bytes); + return formatted; + } + + + std::string format_network_rate(guint64 rate) + { + return procman::format_rate(rate, GsmApplication::get()->config.network_in_bits); + } + +} + +Glib::ustring +get_monospace_system_font_name () +{ + return Gio::Settings::create ("org.gnome.desktop.interface")->get_string ("monospace-font-name"); +} |