summaryrefslogtreecommitdiff
path: root/hardinfo/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'hardinfo/util.c')
-rw-r--r--hardinfo/util.c1404
1 files changed, 1404 insertions, 0 deletions
diff --git a/hardinfo/util.c b/hardinfo/util.c
new file mode 100644
index 00000000..40566eac
--- /dev/null
+++ b/hardinfo/util.c
@@ -0,0 +1,1404 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/*
+ * Functions h_strdup_cprintf and h_strconcat are based on GLib version 2.4.6
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <config.h>
+
+#include <report.h>
+#include <string.h>
+#include <shell.h>
+#include <iconcache.h>
+#include <hardinfo.h>
+#include <gtk/gtk.h>
+
+#include <binreloc.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#define KiB 1024
+#define MiB 1048576
+#define GiB 1073741824
+#define TiB 1099511627776
+#define PiB 1125899906842624
+
+static GSList *modules_list = NULL;
+
+void sync_manager_clear_entries(void);
+
+gchar *find_program(gchar *program_name)
+{
+ int i;
+ char *temp;
+ static GHashTable *cache = NULL;
+ const char *path[] = { "/usr/local/bin", "/usr/local/sbin",
+ "/usr/bin", "/usr/sbin",
+ "/bin", "/sbin",
+ NULL };
+
+ /* we don't need to call stat() every time: cache the results */
+ if (!cache) {
+ cache = g_hash_table_new(g_str_hash, g_str_equal);
+ } else if ((temp = g_hash_table_lookup(cache, program_name))) {
+ return g_strdup(temp);
+ }
+
+ for (i = 0; path[i]; i++) {
+ temp = g_build_filename(path[i], program_name, NULL);
+
+ if (g_file_test(temp, G_FILE_TEST_IS_EXECUTABLE)) {
+ g_hash_table_insert(cache, program_name, g_strdup(temp));
+ return temp;
+ }
+
+ g_free(temp);
+ }
+
+ /* our search has failed; use GLib's search (which uses $PATH env var) */
+ if ((temp = g_find_program_in_path(program_name))) {
+ g_hash_table_insert(cache, program_name, g_strdup(temp));
+ return temp;
+ }
+
+ return NULL;
+}
+
+gchar *seconds_to_string(unsigned int seconds)
+{
+ unsigned int hours, minutes, days;
+
+ minutes = seconds / 60;
+ hours = minutes / 60;
+ minutes %= 60;
+ days = hours / 24;
+ hours %= 24;
+
+ gchar *wminutes;
+ gchar *whours;
+ gchar *wdays;
+
+ wdays = ngettext("%d day, ", "%d days, ", days);
+ whours = ngettext("%d hour, ", "%d hours, ", hours);
+ wminutes = ngettext("%d minute", "%d minutes", minutes);
+ if (days < 1) {
+ if (hours < 1)
+ return g_strdup_printf(ngettext("%d minute", "%d minutes", minutes), minutes);
+ return g_strdup_printf(whours, wminutes);
+ }
+ return g_strdup_printf(wdays, whours, wminutes);
+}
+
+inline gchar *size_human_readable(gfloat size)
+{
+ if (size < KiB)
+ return g_strdup_printf(_("%.1f B"), size);
+ if (size < MiB)
+ return g_strdup_printf(_("%.1f KiB"), size / KiB);
+ if (size < GiB)
+ return g_strdup_printf(_("%.1f MiB"), size / MiB);
+ if (size < TiB)
+ return g_strdup_printf(_("%.1f GiB"), size / GiB);
+ if (size < PiB)
+ return g_strdup_printf(_("%.1f TiB"), size / TiB);
+
+ return g_strdup_printf(_("%.1f PiB"), size / PiB);
+}
+
+inline char *strend(gchar * str, gchar chr)
+{
+ if (!str)
+ return NULL;
+
+ char *p;
+ if ((p = g_utf8_strchr(str, -1, chr)))
+ *p = 0;
+
+ return str;
+}
+
+inline void remove_quotes(gchar * str)
+{
+ if (!str)
+ return;
+
+ while (*str == '"')
+ *(str++) = ' ';
+
+ strend(str, '"');
+}
+
+inline void remove_linefeed(gchar * str)
+{
+ strend(str, '\n');
+}
+
+void widget_set_cursor(GtkWidget * widget, GdkCursorType cursor_type)
+{
+ GdkCursor *cursor;
+
+ if ((cursor = gdk_cursor_new(cursor_type))) {
+ gdk_window_set_cursor(GDK_WINDOW(widget->window), cursor);
+ gdk_display_flush(gtk_widget_get_display(widget));
+ gdk_cursor_unref(cursor);
+ }
+
+ while (gtk_events_pending())
+ gtk_main_iteration();
+}
+
+static gboolean __nonblock_cb(gpointer data)
+{
+ gtk_main_quit();
+ return FALSE;
+}
+
+void nonblock_sleep(guint msec)
+{
+ g_timeout_add(msec, (GSourceFunc) __nonblock_cb, NULL);
+ gtk_main();
+}
+
+static void __expand_cb(GtkWidget * widget, gpointer data)
+{
+ if (GTK_IS_EXPANDER(widget)) {
+ gtk_expander_set_expanded(GTK_EXPANDER(widget), TRUE);
+ } else if (GTK_IS_CONTAINER(widget)) {
+ gtk_container_foreach(GTK_CONTAINER(widget),
+ (GtkCallback) __expand_cb, NULL);
+ }
+}
+
+void file_chooser_open_expander(GtkWidget * chooser)
+{
+ gtk_container_foreach(GTK_CONTAINER(chooser),
+ (GtkCallback) __expand_cb, NULL);
+}
+
+void file_chooser_add_filters(GtkWidget * chooser, FileTypes * filters)
+{
+ GtkFileFilter *filter;
+ gint i;
+
+ for (i = 0; filters[i].name; i++) {
+ filter = gtk_file_filter_new();
+ gtk_file_filter_add_mime_type(filter, filters[i].mime_type);
+ gtk_file_filter_set_name(filter, filters[i].name);
+ gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(chooser), filter);
+ }
+}
+
+gchar *file_chooser_get_extension(GtkWidget * chooser, FileTypes * filters)
+{
+ GtkFileFilter *filter;
+ const gchar *filter_name;
+ gint i;
+
+ filter = gtk_file_chooser_get_filter(GTK_FILE_CHOOSER(chooser));
+ filter_name = gtk_file_filter_get_name(filter);
+ for (i = 0; filters[i].name; i++) {
+ if (g_str_equal(filter_name, filters[i].name)) {
+ return filters[i].extension;
+ }
+ }
+
+ return NULL;
+}
+
+gpointer file_types_get_data_by_name(FileTypes * filters, gchar * filename)
+{
+ gint i;
+
+ for (i = 0; filters[i].name; i++) {
+ if (g_str_has_suffix(filename, filters[i].extension)) {
+ return filters[i].data;
+ }
+ }
+
+ return NULL;
+}
+
+gchar *file_chooser_build_filename(GtkWidget * chooser, gchar * extension)
+{
+ gchar *filename =
+ gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(chooser));
+ gchar *retval;
+
+ if (g_str_has_suffix(filename, extension)) {
+ return filename;
+ }
+
+ retval = g_strconcat(filename, extension, NULL);
+ g_free(filename);
+
+ return retval;
+}
+
+gboolean binreloc_init(gboolean try_hardcoded)
+{
+ GError *error = NULL;
+ gchar *tmp;
+
+ DEBUG("initializing binreloc (hardcoded = %d)", try_hardcoded);
+
+ /* If the runtime data directories we previously found, don't even try
+ to find them again. */
+ if (params.path_data && params.path_lib) {
+ DEBUG("data and lib path already found.");
+ return TRUE;
+ }
+
+ if (try_hardcoded || !gbr_init(&error)) {
+ /* We were asked to try hardcoded paths or BinReloc failed to initialize. */
+ params.path_data = g_strdup(PREFIX);
+ params.path_lib = g_strdup(LIBPREFIX);
+
+ if (error) {
+ g_error_free(error);
+ }
+
+ DEBUG("%strying hardcoded paths.",
+ try_hardcoded ? "" : "binreloc init failed. ");
+ } else {
+ /* If we were able to initialize BinReloc, build the default data
+ and library paths. */
+ DEBUG("done, trying to use binreloc paths.");
+
+ tmp = gbr_find_data_dir(PREFIX);
+ params.path_data = g_build_filename(tmp, "hardinfo", NULL);
+ g_free(tmp);
+
+ tmp = gbr_find_lib_dir(PREFIX);
+ params.path_lib = g_build_filename(tmp, "hardinfo", NULL);
+ g_free(tmp);
+ }
+
+ DEBUG("searching for runtime data on these locations:");
+ DEBUG(" lib: %s", params.path_lib);
+ DEBUG(" data: %s", params.path_data);
+
+ /* Try to see if the uidefs.xml file isn't missing. This isn't the
+ definitive test, but it should do okay for most situations. */
+ tmp = g_build_filename(params.path_data, "benchmark.data", NULL);
+ if (!g_file_test(tmp, G_FILE_TEST_EXISTS)) {
+ DEBUG("runtime data not found");
+
+ g_free(params.path_data);
+ g_free(params.path_lib);
+ g_free(tmp);
+
+ params.path_data = params.path_lib = NULL;
+
+ if (try_hardcoded) {
+ /* We tried the hardcoded paths, but still was unable to find the
+ runtime data. Give up. */
+ DEBUG("giving up");
+ return FALSE;
+ } else {
+ /* Even though BinReloc worked OK, the runtime data was not found.
+ Try the hardcoded paths. */
+ DEBUG("trying to find elsewhere");
+ return binreloc_init(TRUE);
+ }
+ }
+ g_free(tmp);
+
+ DEBUG("runtime data found!");
+ /* We found the runtime data; hope everything is fine */
+ return TRUE;
+}
+
+static void
+log_handler(const gchar * log_domain,
+ GLogLevelFlags log_level,
+ const gchar * message, gpointer user_data)
+{
+ if (!params.gui_running) {
+ /* No GUI running: spit the message to the terminal */
+ g_print("\n\n*** %s: %s\n\n",
+ (log_level & G_LOG_FLAG_FATAL) ? _("Error") : _("Warning"),
+ message);
+ } else {
+ /* Hooray! We have a GUI running! */
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new_with_markup(NULL, GTK_DIALOG_MODAL,
+ (log_level &
+ G_LOG_FLAG_FATAL) ?
+ GTK_MESSAGE_ERROR :
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_CLOSE,
+ "<big><b>%s</b></big>\n\n%s",
+ (log_level &
+ G_LOG_FLAG_FATAL) ?
+ _("Fatal Error") :
+ _("Warning"), message);
+
+ gtk_dialog_run(GTK_DIALOG(dialog));
+ gtk_widget_destroy(dialog);
+ }
+}
+
+void parameters_init(int *argc, char ***argv, ProgramParameters * param)
+{
+ static gboolean create_report = FALSE;
+ static gboolean show_version = FALSE;
+ static gboolean list_modules = FALSE;
+ static gboolean autoload_deps = FALSE;
+ static gboolean run_xmlrpc_server = FALSE;
+ static gchar *report_format = NULL;
+ static gchar *run_benchmark = NULL;
+ static gchar **use_modules = NULL;
+
+ static GOptionEntry options[] = {
+ {
+ .long_name = "generate-report",
+ .short_name = 'r',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = &create_report,
+ .description = N_("creates a report and prints to standard output")},
+ {
+ .long_name = "report-format",
+ .short_name = 'f',
+ .arg = G_OPTION_ARG_STRING,
+ .arg_data = &report_format,
+ .description = N_("chooses a report format (text, html)")},
+ {
+ .long_name = "run-benchmark",
+ .short_name = 'b',
+ .arg = G_OPTION_ARG_STRING,
+ .arg_data = &run_benchmark,
+ .description = N_("run benchmark; requires benchmark.so to be loaded")},
+ {
+ .long_name = "list-modules",
+ .short_name = 'l',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = &list_modules,
+ .description = N_("lists modules")},
+ {
+ .long_name = "load-module",
+ .short_name = 'm',
+ .arg = G_OPTION_ARG_STRING_ARRAY,
+ .arg_data = &use_modules,
+ .description = N_("specify module to load")},
+ {
+ .long_name = "autoload-deps",
+ .short_name = 'a',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = &autoload_deps,
+ .description = N_("automatically load module dependencies")},
+#ifdef HAS_LIBSOUP
+ {
+ .long_name = "xmlrpc-server",
+ .short_name = 'x',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = &run_xmlrpc_server,
+ .description = N_("run in XML-RPC server mode")},
+#endif /* HAS_LIBSOUP */
+ {
+ .long_name = "version",
+ .short_name = 'v',
+ .arg = G_OPTION_ARG_NONE,
+ .arg_data = &show_version,
+ .description = N_("shows program version and quit")},
+ {NULL}
+ };
+ GOptionContext *ctx;
+
+ ctx = g_option_context_new(_("- System Profiler and Benchmark tool"));
+ g_option_context_set_ignore_unknown_options(ctx, FALSE);
+ g_option_context_set_help_enabled(ctx, TRUE);
+
+ g_option_context_add_main_entries(ctx, options, *(argv)[0]);
+ g_option_context_parse(ctx, argc, argv, NULL);
+
+ g_option_context_free(ctx);
+
+ if (*argc >= 2) {
+ g_print(_("Unrecognized arguments.\n"
+ "Try ``%s --help'' for more information.\n"), *(argv)[0]);
+ exit(1);
+ }
+
+ param->create_report = create_report;
+ param->report_format = REPORT_FORMAT_TEXT;
+ param->show_version = show_version;
+ param->list_modules = list_modules;
+ param->use_modules = use_modules;
+ param->run_benchmark = run_benchmark;
+ param->autoload_deps = autoload_deps;
+ param->run_xmlrpc_server = run_xmlrpc_server;
+ param->argv0 = *(argv)[0];
+
+ if (report_format && g_str_equal(report_format, "html"))
+ param->report_format = REPORT_FORMAT_HTML;
+
+ gchar *confdir = g_build_filename(g_get_home_dir(), ".hardinfo", NULL);
+ if (!g_file_test(confdir, G_FILE_TEST_EXISTS)) {
+ mkdir(confdir, 0744);
+ }
+ g_free(confdir);
+}
+
+gboolean ui_init(int *argc, char ***argv)
+{
+ DEBUG("initializing gtk+ UI");
+
+ g_set_application_name("HardInfo");
+ g_log_set_handler(NULL,
+ G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL |
+ G_LOG_LEVEL_ERROR, log_handler, NULL);
+
+ return gtk_init_check(argc, argv);
+}
+
+void open_url(gchar * url)
+{
+ const gchar *browsers[] = {
+ "xdg-open", "gnome-open", "kfmclient openURL",
+ "sensible-browser", "firefox", "epiphany",
+ "iceweasel", "seamonkey", "galeon", "mozilla",
+ "opera", "konqueror", "netscape", "links -g",
+ NULL
+ };
+ gint i = 0;
+ gchar *browser = (gchar *)g_getenv("BROWSER");
+
+ if (!browser || *browser == '\0') {
+ browser = (gchar *)browsers[i++];
+ }
+
+ do {
+ gchar *cmdline = g_strdup_printf("%s '%s'", browser, url);
+
+ if (g_spawn_command_line_async(cmdline, NULL)) {
+ g_free(cmdline);
+ return;
+ }
+
+ g_free(cmdline);
+
+ browser = (gchar *)browsers[i++];
+ } while (browser);
+
+ g_warning(_("Couldn't find a Web browser to open URL %s."), url);
+}
+
+/* Copyright: Jens Låås, SLU 2002 */
+gchar *strreplacechr(gchar * string, gchar * replace, gchar new_char)
+{
+ gchar *s;
+ for (s = string; *s; s++)
+ if (strchr(replace, *s))
+ *s = new_char;
+
+ return string;
+}
+
+gchar *strreplace(gchar *string, gchar *replace, gchar *replacement)
+{
+ gchar **tmp, *ret;
+
+ tmp = g_strsplit(string, replace, 0);
+ ret = g_strjoinv(replacement, tmp);
+ g_strfreev(tmp);
+
+ return ret;
+}
+
+static GHashTable *__module_methods = NULL;
+
+static void module_register_methods(ShellModule * module)
+{
+ ShellModuleMethod *(*get_methods) (void);
+ gchar *method_name;
+
+ if (__module_methods == NULL) {
+ __module_methods = g_hash_table_new(g_str_hash, g_str_equal);
+ }
+
+ if (g_module_symbol
+ (module->dll, "hi_exported_methods", (gpointer) & get_methods)) {
+ ShellModuleMethod *methods;
+
+ for (methods = get_methods(); methods->name; methods++) {
+ ShellModuleMethod method = *methods;
+ gchar *name = g_path_get_basename(g_module_name(module->dll));
+ gchar *simple_name = strreplace(name, "lib", "");
+
+ strend(simple_name, '.');
+
+ method_name = g_strdup_printf("%s::%s", simple_name, method.name);
+ g_hash_table_insert(__module_methods, method_name,
+ method.function);
+ g_free(name);
+ g_free(simple_name);
+ }
+ }
+
+}
+
+gchar *module_call_method(gchar * method)
+{
+ gchar *(*function) (void);
+
+ if (__module_methods == NULL) {
+ return NULL;
+ }
+
+ function = g_hash_table_lookup(__module_methods, method);
+ return function ? g_strdup(function()) : NULL;
+}
+
+/* FIXME: varargs? */
+gchar *module_call_method_param(gchar * method, gchar * parameter)
+{
+ gchar *(*function) (gchar *param);
+
+ if (__module_methods == NULL) {
+ return NULL;
+ }
+
+ function = g_hash_table_lookup(__module_methods, method);
+ return function ? g_strdup(function(parameter)) : NULL;
+}
+
+static gboolean remove_module_methods(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, data);
+}
+
+static void module_unload(ShellModule * module)
+{
+ GSList *entry;
+
+ if (module->dll) {
+ gchar *name;
+
+ if (module->deinit) {
+ DEBUG("cleaning up module \"%s\"", module->name);
+ module->deinit();
+ } else {
+ DEBUG("module \"%s\" does not need cleanup", module->name);
+ }
+
+ name = g_path_get_basename(g_module_name(module->dll));
+ g_hash_table_foreach_remove(__module_methods, remove_module_methods, name);
+
+ g_module_close(module->dll);
+ g_free(name);
+ }
+
+ g_free(module->name);
+ g_object_unref(module->icon);
+
+ for (entry = module->entries; entry; entry = entry->next) {
+ ShellModuleEntry *e = (ShellModuleEntry *)entry->data;
+
+ g_source_remove_by_user_data(e);
+ g_free(e);
+ }
+
+ g_slist_free(module->entries);
+ g_free(module);
+}
+
+
+void module_unload_all(void)
+{
+ Shell *shell;
+ GSList *module, *merge_id;
+
+ shell = shell_get_main_shell();
+
+ sync_manager_clear_entries();
+ shell_clear_timeouts(shell);
+ shell_clear_tree_models(shell);
+ shell_clear_field_updates();
+ shell_set_title(shell, NULL);
+
+ for (module = shell->tree->modules; module; module = module->next) {
+ module_unload((ShellModule *)module->data);
+ }
+
+ for (merge_id = shell->merge_ids; merge_id; merge_id = merge_id->next) {
+ gtk_ui_manager_remove_ui(shell->ui_manager,
+ GPOINTER_TO_INT(merge_id->data));
+ }
+ g_slist_free(shell->tree->modules);
+ g_slist_free(shell->merge_ids);
+
+ shell->merge_ids = NULL;
+ shell->tree->modules = NULL;
+ shell->selected = NULL;
+}
+
+static ShellModule *module_load(gchar * filename)
+{
+ ShellModule *module;
+ gchar *tmp;
+
+ module = g_new0(ShellModule, 1);
+
+ if (params.gui_running) {
+ gchar *tmpicon, *dot, *simple_name;
+
+ tmpicon = g_strdup(filename);
+ dot = g_strrstr(tmpicon, "." G_MODULE_SUFFIX);
+
+ *dot = '\0';
+
+ simple_name = strreplace(tmpicon, "lib", "");
+
+ tmp = g_strdup_printf("%s.png", simple_name);
+ module->icon = icon_cache_get_pixbuf(tmp);
+
+ g_free(tmp);
+ g_free(tmpicon);
+ g_free(simple_name);
+ }
+
+ tmp = g_build_filename(params.path_lib, "modules", filename, NULL);
+ module->dll = g_module_open(tmp, G_MODULE_BIND_LAZY);
+ DEBUG("gmodule resource for ``%s'' is %p", tmp, module->dll);
+ g_free(tmp);
+
+ if (module->dll) {
+ void (*init) (void);
+ ModuleEntry *(*get_module_entries) (void);
+ gint(*weight_func) (void);
+ gchar *(*name_func) (void);
+ ModuleEntry *entries;
+ gint i = 0;
+
+ if (!g_module_symbol(module->dll, "hi_module_get_entries", (gpointer) & get_module_entries) ||
+ !g_module_symbol(module->dll, "hi_module_get_name", (gpointer) & name_func)) {
+ DEBUG("cannot find needed symbols; is ``%s'' a real module?", filename);
+ goto failed;
+ }
+
+ if (g_module_symbol(module->dll, "hi_module_init", (gpointer) & init)) {
+ DEBUG("initializing module ``%s''", filename);
+ init();
+ }
+
+ g_module_symbol(module->dll, "hi_module_get_weight",
+ (gpointer) & weight_func);
+
+ module->weight = weight_func ? weight_func() : 0;
+ module->name = name_func();
+
+ g_module_symbol(module->dll, "hi_module_get_about",
+ (gpointer) & (module->aboutfunc));
+ g_module_symbol(module->dll, "hi_module_deinit",
+ (gpointer) & (module->deinit));
+ g_module_symbol(module->dll, "hi_module_get_summary",
+ (gpointer) & (module->summaryfunc));
+
+ entries = get_module_entries();
+ while (entries[i].name) {
+ ShellModuleEntry *entry = g_new0(ShellModuleEntry, 1);
+
+ if (params.gui_running) {
+ entry->icon = icon_cache_get_pixbuf(entries[i].icon);
+ }
+ entry->icon_file = entries[i].icon;
+
+ g_module_symbol(module->dll, "hi_more_info",
+ (gpointer) & (entry->morefunc));
+ g_module_symbol(module->dll, "hi_get_field",
+ (gpointer) & (entry->fieldfunc));
+ g_module_symbol(module->dll, "hi_note_func",
+ (gpointer) & (entry->notefunc));
+
+ entry->name = _(entries[i].name); //gettext unname N_() in computer.c line 67 etc...
+ entry->scan_func = entries[i].scan_callback;
+ entry->func = entries[i].callback;
+ entry->number = i;
+ entry->flags = entries[i].flags;
+
+ module->entries = g_slist_append(module->entries, entry);
+
+ i++;
+ }
+
+ DEBUG("registering methods for module ``%s''", filename);
+ module_register_methods(module);
+ } else {
+ DEBUG("cannot g_module_open(``%s''). permission problem?", filename);
+ failed:
+ DEBUG("loading module %s failed: %s", filename, g_module_error());
+
+ g_free(module->name);
+ g_free(module);
+ module = NULL;
+ }
+
+ return module;
+}
+
+static gboolean module_in_module_list(gchar * module, gchar ** module_list)
+{
+ int i = 0;
+
+ if (!module_list)
+ return TRUE;
+
+ for (; module_list[i]; i++) {
+ if (g_str_equal(module_list[i], module))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gint module_cmp(gconstpointer m1, gconstpointer m2)
+{
+ ShellModule *a = (ShellModule *) m1;
+ ShellModule *b = (ShellModule *) m2;
+
+ return a->weight - b->weight;
+}
+
+#if 0
+static void module_entry_free(gpointer data, gpointer user_data)
+{
+ ShellModuleEntry *entry = (ShellModuleEntry *) data;
+
+ if (entry) {
+ g_free(entry->name);
+ g_object_unref(entry->icon);
+
+ g_free(entry);
+ }
+}
+#endif
+
+ModuleAbout *module_get_about(ShellModule * module)
+{
+ if (module->aboutfunc) {
+ return module->aboutfunc();
+ }
+
+ return NULL;
+}
+
+static GSList *modules_check_deps(GSList * modules)
+{
+ GSList *mm;
+ ShellModule *module;
+
+ for (mm = modules; mm; mm = mm->next) {
+ gchar **(*get_deps) (void);
+ gchar **deps;
+ gint i;
+
+ module = (ShellModule *) mm->data;
+
+ if (g_module_symbol(module->dll, "hi_module_get_dependencies",
+ (gpointer) & get_deps)) {
+ for (i = 0, deps = get_deps(); deps[i]; i++) {
+ GSList *l;
+ ShellModule *m;
+ gboolean found = FALSE;
+
+ for (l = modules; l && !found; l = l->next) {
+ m = (ShellModule *) l->data;
+ gchar *name = g_path_get_basename(g_module_name(m->dll));
+
+ found = g_str_equal(name, deps[i]);
+ g_free(name);
+ }
+
+ if (!found) {
+ if (params.autoload_deps) {
+ ShellModule *mod = module_load(deps[i]);
+
+ if (mod)
+ modules = g_slist_append(modules, mod);
+ modules = modules_check_deps(modules); /* re-check dependencies */
+
+ break;
+ }
+
+ if (params.gui_running) {
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new(NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("Module \"%s\" depends on module \"%s\", load it?"),
+ module->name,
+ deps[i]);
+ gtk_dialog_add_buttons(GTK_DIALOG(dialog),
+ GTK_STOCK_NO,
+ GTK_RESPONSE_REJECT,
+ GTK_STOCK_OPEN,
+ GTK_RESPONSE_ACCEPT, NULL);
+
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) ==
+ GTK_RESPONSE_ACCEPT) {
+ ShellModule *mod = module_load(deps[i]);
+
+ if (mod)
+ modules = g_slist_prepend(modules, mod);
+ modules = modules_check_deps(modules); /* re-check dependencies */
+ } else {
+ g_error("HardInfo cannot run without loading the additional module.");
+ exit(1);
+ }
+
+ gtk_widget_destroy(dialog);
+ } else {
+ g_error(_("Module \"%s\" depends on module \"%s\"."),
+ module->name, deps[i]);
+ }
+ }
+ }
+ }
+ }
+
+ return modules;
+}
+
+
+GSList *modules_get_list()
+{
+ return modules_list;
+}
+
+static GSList *modules_load(gchar ** module_list)
+{
+ GDir *dir;
+ GSList *modules = NULL;
+ ShellModule *module;
+ gchar *filename;
+
+ filename = g_build_filename(params.path_lib, "modules", NULL);
+ dir = g_dir_open(filename, 0, NULL);
+ g_free(filename);
+
+ if (dir) {
+ while ((filename = (gchar *) g_dir_read_name(dir))) {
+ if (g_strrstr(filename, "." G_MODULE_SUFFIX) &&
+ module_in_module_list(filename, module_list) &&
+ ((module = module_load(filename)))) {
+ modules = g_slist_prepend(modules, module);
+ }
+ }
+
+ g_dir_close(dir);
+ }
+
+ modules = modules_check_deps(modules);
+
+ if (g_slist_length(modules) == 0) {
+ if (params.use_modules == NULL) {
+ g_error
+ (_("No module could be loaded. Check permissions on \"%s\" and try again."),
+ params.path_lib);
+ } else {
+ g_error
+ (_("No module could be loaded. Please use hardinfo -l to list all avai"
+ "lable modules and try again with a valid module list."));
+
+ }
+ }
+
+ modules_list = g_slist_sort(modules, module_cmp);
+ return modules_list;
+}
+
+GSList *modules_load_selected(void)
+{
+ return modules_load(params.use_modules);
+}
+
+GSList *modules_load_all(void)
+{
+ return modules_load(NULL);
+}
+
+gint tree_view_get_visible_height(GtkTreeView * tv)
+{
+ GtkTreePath *path;
+ GdkRectangle rect;
+ GtkTreeIter iter;
+ GtkTreeModel *model = gtk_tree_view_get_model(tv);
+ gint nrows = 1;
+
+ path = gtk_tree_path_new_first();
+ gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tv), path, NULL, &rect);
+
+ /* FIXME: isn't there any easier way to tell the number of rows? */
+ gtk_tree_model_get_iter_first(model, &iter);
+ do {
+ nrows++;
+ } while (gtk_tree_model_iter_next(model, &iter));
+
+ gtk_tree_path_free(path);
+
+ return nrows * rect.height;
+}
+
+void tree_view_save_image(gchar * filename)
+{
+ /* this is ridiculously complicated :/ why in the hell gtk+ makes this kind of
+ thing so difficult? */
+
+ /* FIXME: this does not work if the window (or part of it) isn't visible. does
+ anyone know how to fix this? :/ */
+ Shell *shell = shell_get_main_shell();
+ GtkWidget *widget = shell->info->view;
+
+ PangoLayout *layout;
+ PangoContext *context;
+ PangoRectangle rect;
+
+ GdkPixmap *pm;
+ GdkPixbuf *pb;
+ GdkGC *gc;
+ GdkColor black = { 0, 0, 0, 0 };
+ GdkColor white = { 0, 65535, 65535, 65535 };
+
+ gint w, h, visible_height;
+ gchar *tmp;
+
+ gboolean tv_enabled;
+
+ /* present the window */
+ gtk_window_present(GTK_WINDOW(shell->window));
+
+ /* if the treeview is disabled, we need to enable it so we get the
+ correct colors when saving. we make it insensitive later on if it
+ was this way before entering this function */
+ tv_enabled = GTK_WIDGET_IS_SENSITIVE(widget);
+ gtk_widget_set_sensitive(widget, TRUE);
+
+ gtk_widget_queue_draw(widget);
+
+ /* unselect things in the information treeview */
+ gtk_range_set_value(GTK_RANGE
+ (GTK_SCROLLED_WINDOW(shell->info->scroll)->
+ vscrollbar), 0.0);
+ gtk_tree_selection_unselect_all(gtk_tree_view_get_selection
+ (GTK_TREE_VIEW(widget)));
+ while (gtk_events_pending())
+ gtk_main_iteration();
+
+ /* initialize stuff */
+ gc = gdk_gc_new(widget->window);
+ gdk_gc_set_background(gc, &black);
+ gdk_gc_set_foreground(gc, &white);
+
+ context = gtk_widget_get_pango_context(widget);
+ layout = pango_layout_new(context);
+
+ visible_height = tree_view_get_visible_height(GTK_TREE_VIEW(widget));
+
+ /* draw the title */
+ tmp = g_strdup_printf("<b><big>%s</big></b>\n<small>%s</small>",
+ shell->selected->name,
+ shell->selected->notefunc(shell->selected->
+ number));
+ pango_layout_set_markup(layout, tmp, -1);
+ pango_layout_set_width(layout, widget->allocation.width * PANGO_SCALE);
+ pango_layout_set_alignment(layout, PANGO_ALIGN_CENTER);
+ pango_layout_get_pixel_extents(layout, NULL, &rect);
+
+ w = widget->allocation.width;
+ h = visible_height + rect.height;
+
+ pm = gdk_pixmap_new(widget->window, w, rect.height, -1);
+ gdk_draw_rectangle(GDK_DRAWABLE(pm), gc, TRUE, 0, 0, w, rect.height);
+ gdk_draw_layout_with_colors(GDK_DRAWABLE(pm), gc, 0, 0, layout,
+ &white, &black);
+
+ /* copy the pixmap from the treeview and from the title */
+ pb = gdk_pixbuf_get_from_drawable(NULL,
+ widget->window,
+ NULL, 0, 0, 0, 0, w, h);
+ pb = gdk_pixbuf_get_from_drawable(pb,
+ pm,
+ NULL,
+ 0, 0,
+ 0, visible_height, w, rect.height);
+
+ /* save the pixbuf to a png file */
+ gdk_pixbuf_save(pb, filename, "png", NULL,
+ "compression", "9",
+ "tEXt::hardinfo::version", VERSION,
+ "tEXt::hardinfo::arch", ARCH, NULL);
+
+ /* unref */
+ g_object_unref(pb);
+ g_object_unref(layout);
+ g_object_unref(pm);
+ g_object_unref(gc);
+ g_free(tmp);
+
+ gtk_widget_set_sensitive(widget, tv_enabled);
+}
+
+static gboolean __idle_free_do(gpointer ptr)
+{
+ g_free(ptr);
+
+ return FALSE;
+}
+
+#if RELEASE == 1
+gpointer idle_free(gpointer ptr)
+#else
+gpointer __idle_free(gpointer ptr, gchar * f, gint l)
+#endif
+{
+ DEBUG("file: %s, line: %d, ptr %p", f, l, ptr);
+
+ if (ptr) {
+ g_timeout_add(10000, __idle_free_do, ptr);
+ }
+
+ return ptr;
+}
+
+void module_entry_scan_all_except(ModuleEntry * entries, gint except_entry)
+{
+ ModuleEntry entry;
+ gint i = 0;
+ void (*scan_callback) (gboolean reload);
+ gchar *text;
+
+ shell_view_set_enabled(FALSE);
+
+ for (entry = entries[0]; entry.name; entry = entries[++i]) {
+ if (i == except_entry)
+ continue;
+
+ text = g_strdup_printf(_("Scanning: %s..."), _(entry.name));
+ shell_status_update(text);
+ g_free(text);
+
+ if ((scan_callback = entry.scan_callback)) {
+ scan_callback(FALSE);
+ }
+ }
+
+ shell_view_set_enabled(TRUE);
+ shell_status_update(_("Done."));
+}
+
+void module_entry_scan_all(ModuleEntry * entries)
+{
+ module_entry_scan_all_except(entries, -1);
+}
+
+void module_entry_reload(ShellModuleEntry * module_entry)
+{
+
+ if (module_entry->scan_func) {
+ module_entry->scan_func(TRUE);
+ }
+}
+
+void module_entry_scan(ShellModuleEntry * module_entry)
+{
+ if (module_entry->scan_func) {
+ module_entry->scan_func(FALSE);
+ }
+}
+
+gchar *module_entry_get_field(ShellModuleEntry * module_entry, gchar * field)
+{
+ if (module_entry->fieldfunc) {
+ return module_entry->fieldfunc(field);
+ }
+
+ return NULL;
+}
+
+gchar *module_entry_function(ShellModuleEntry * module_entry)
+{
+ if (module_entry->func) {
+ return module_entry->func();
+ }
+
+ return NULL;
+}
+
+gchar *module_entry_get_moreinfo(ShellModuleEntry * module_entry, gchar * field)
+{
+ if (module_entry->morefunc) {
+ return module_entry->morefunc(field);
+ }
+
+ return NULL;
+}
+
+const gchar *module_entry_get_note(ShellModuleEntry * module_entry)
+{
+ if (module_entry->notefunc) {
+ return module_entry->notefunc(module_entry->number);
+ }
+
+ return NULL;
+}
+
+gchar *h_strdup_cprintf(const gchar * format, gchar * source, ...)
+{
+ gchar *buffer, *retn;
+ va_list args;
+
+ va_start(args, source);
+ buffer = g_strdup_vprintf(format, args);
+ va_end(args);
+
+ if (source) {
+ retn = g_strconcat(source, buffer, NULL);
+ g_free(buffer);
+ g_free(source);
+ } else {
+ retn = buffer;
+ }
+
+ return retn;
+}
+
+gchar *h_strconcat(gchar * string1, ...)
+{
+ gsize l;
+ va_list args;
+ gchar *s;
+ gchar *concat;
+ gchar *ptr;
+
+ if (!string1)
+ return NULL;
+
+ l = 1 + strlen(string1);
+ va_start(args, string1);
+ s = va_arg(args, gchar *);
+ while (s) {
+ l += strlen(s);
+ s = va_arg(args, gchar *);
+ }
+ va_end(args);
+
+ concat = g_new(gchar, l);
+ ptr = concat;
+
+ ptr = g_stpcpy(ptr, string1);
+ va_start(args, string1);
+ s = va_arg(args, gchar *);
+ while (s) {
+ ptr = g_stpcpy(ptr, s);
+ s = va_arg(args, gchar *);
+ }
+ va_end(args);
+
+ g_free(string1);
+
+ return concat;
+}
+
+static gboolean h_hash_table_remove_all_true(gpointer key, gpointer data, gpointer user_data)
+{
+ return TRUE;
+}
+
+void
+h_hash_table_remove_all(GHashTable *hash_table)
+{
+ g_hash_table_foreach_remove(hash_table,
+ h_hash_table_remove_all_true,
+ NULL);
+}
+
+gfloat
+h_sysfs_read_float(gchar *endpoint, gchar *entry)
+{
+ gchar *tmp, *buffer;
+ gfloat return_value = 0.0f;
+
+ tmp = g_build_filename(endpoint, entry, NULL);
+ if (g_file_get_contents(tmp, &buffer, NULL, NULL))
+ return_value = atof(buffer);
+
+ g_free(tmp);
+ g_free(buffer);
+
+ return return_value;
+}
+
+gint
+h_sysfs_read_int(gchar *endpoint, gchar *entry)
+{
+ gchar *tmp, *buffer;
+ gint return_value = 0;
+
+ tmp = g_build_filename(endpoint, entry, NULL);
+ if (g_file_get_contents(tmp, &buffer, NULL, NULL))
+ return_value = atoi(buffer);
+
+ g_free(tmp);
+ g_free(buffer);
+
+ return return_value;
+}
+
+gchar *
+h_sysfs_read_string(gchar *endpoint, gchar *entry)
+{
+ gchar *tmp, *return_value;
+
+ tmp = g_build_filename(endpoint, entry, NULL);
+ if (!g_file_get_contents(tmp, &return_value, NULL, NULL)) {
+ g_free(return_value);
+
+ return_value = NULL;
+ } else {
+ return_value = g_strstrip(return_value);
+ }
+
+ g_free(tmp);
+
+ return return_value;
+}
+
+static GHashTable *_moreinfo = NULL;
+
+void
+moreinfo_init(void)
+{
+ if (G_UNLIKELY(_moreinfo)) {
+ DEBUG("moreinfo already initialized");
+ return;
+ }
+ DEBUG("initializing moreinfo");
+ _moreinfo = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+}
+
+void
+moreinfo_shutdown(void)
+{
+ if (G_UNLIKELY(!_moreinfo)) {
+ DEBUG("moreinfo not initialized");
+ return;
+ }
+ DEBUG("shutting down moreinfo");
+ g_hash_table_destroy(_moreinfo);
+ _moreinfo = NULL;
+}
+
+void
+moreinfo_add_with_prefix(gchar *prefix, gchar *key, gchar *value)
+{
+ if (G_UNLIKELY(!_moreinfo)) {
+ DEBUG("moreinfo not initialized");
+ return;
+ }
+
+ if (prefix) {
+ gchar *hashkey = g_strconcat(prefix, ":", key, NULL);
+ g_hash_table_insert(_moreinfo, hashkey, value);
+ return;
+ }
+
+ g_hash_table_insert(_moreinfo, g_strdup(key), value);
+}
+
+void
+moreinfo_add(gchar *key, gchar *value)
+{
+ moreinfo_add_with_prefix(NULL, key, value);
+}
+
+static gboolean
+_moreinfo_del_cb(gpointer key, gpointer value, gpointer data)
+{
+ return g_str_has_prefix(key, data);
+}
+
+void
+moreinfo_del_with_prefix(gchar *prefix)
+{
+ if (G_UNLIKELY(!_moreinfo)) {
+ DEBUG("moreinfo not initialized");
+ return;
+ }
+
+ g_hash_table_foreach_remove(_moreinfo, _moreinfo_del_cb, prefix);
+}
+
+void
+moreinfo_clear(void)
+{
+ if (G_UNLIKELY(!_moreinfo)) {
+ DEBUG("moreinfo not initialized");
+ return;
+ }
+ h_hash_table_remove_all(_moreinfo);
+}
+
+gchar *
+moreinfo_lookup_with_prefix(gchar *prefix, gchar *key)
+{
+ if (G_UNLIKELY(!_moreinfo)) {
+ DEBUG("moreinfo not initialized");
+ return 0;
+ }
+
+ if (prefix) {
+ gchar *lookup_key = g_strconcat(prefix, ":", key, NULL);
+ gchar *result = g_hash_table_lookup(_moreinfo, lookup_key);
+ g_free(lookup_key);
+ return result;
+ }
+
+ return g_hash_table_lookup(_moreinfo, key);
+}
+
+gchar *
+moreinfo_lookup(gchar *key)
+{
+ return moreinfo_lookup_with_prefix(NULL, key);
+}
+
+#if !GLIB_CHECK_VERSION(2,44,0)
+gboolean g_strv_contains(const gchar * const * strv, const gchar *str) {
+ /* g_strv_contains() requires glib>2.44
+ * fallback for older versions */
+ gint i = 0;
+ while(strv[i] != NULL) {
+ if (g_strcmp0(strv[i], str) == 0)
+ return 1;
+ i++;
+ }
+ return 0;
+}
+#endif