diff options
Diffstat (limited to 'hardinfo2/util/util.c')
-rw-r--r-- | hardinfo2/util/util.c | 1292 |
1 files changed, 1292 insertions, 0 deletions
diff --git a/hardinfo2/util/util.c b/hardinfo2/util/util.c new file mode 100644 index 00000000..fb995406 --- /dev/null +++ b/hardinfo2/util/util.c @@ -0,0 +1,1292 @@ +/* + * 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 + +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[] = { "/bin", "/sbin", + "/usr/bin", "/usr/sbin", + "/usr/local/bin", "/usr/local/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; + +#define plural(x) ((x > 1) ? "s" : "") + + if (days < 1) { + if (hours < 1) { + return g_strdup_printf("%d minute%s", minutes, + plural(minutes)); + } else { + return g_strdup_printf("%d hour%s, %d minute%s", + hours, + plural(hours), minutes, + plural(minutes)); + } + } + + return g_strdup_printf("%d day%s, %d hour%s and %d minute%s", + days, plural(days), hours, + plural(hours), minutes, plural(minutes)); +} + +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); + + return g_strdup_printf("%.1f GiB", size / GiB); +} + +inline char *strend(gchar * str, gchar chr) +{ + if (!str) + return NULL; + + char *p; + if ((p = strchr(str, 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 = "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 = "chooses a report format (text, html)"}, + { + .long_name = "run-benchmark", + .short_name = 'b', + .arg = G_OPTION_ARG_STRING, + .arg_data = &run_benchmark, + .description = "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 = "lists modules"}, + { + .long_name = "load-module", + .short_name = 'm', + .arg = G_OPTION_ARG_STRING_ARRAY, + .arg_data = &use_modules, + .description = "specify module to load"}, + { + .long_name = "autoload-deps", + .short_name = 'a', + .arg = G_OPTION_ARG_NONE, + .arg_data = &autoload_deps, + .description = "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 = "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 = "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); + gdk_pixbuf_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; + 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) +{ + if (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; +} + |