diff options
author | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2024-04-22 00:35:53 -0300 |
---|---|---|
committer | Lucas de Castro Borges <lucas@gnuabordo.com.br> | 2024-04-22 00:35:53 -0300 |
commit | 5f01c706267c595de92406a32e7f31ef5056c2d0 (patch) | |
tree | d1e74ef54efc41ada622900fe3e2a50dee44a237 /shell | |
parent | 09fcc751ef158898c315ebc9299a0fa3a722d914 (diff) |
New upstream version 2.0.3preupstream/2.0.3pre
Diffstat (limited to 'shell')
-rw-r--r-- | shell/callbacks.c | 150 | ||||
-rw-r--r-- | shell/iconcache.c | 4 | ||||
-rw-r--r-- | shell/loadgraph-uber.c | 8 | ||||
-rw-r--r-- | shell/loadgraph.c | 33 | ||||
-rw-r--r-- | shell/menu.c | 38 | ||||
-rw-r--r-- | shell/report.c | 527 | ||||
-rw-r--r-- | shell/shell.c | 1547 | ||||
-rw-r--r-- | shell/stock.c | 22 | ||||
-rw-r--r-- | shell/syncmanager.c | 737 |
9 files changed, 1895 insertions, 1171 deletions
diff --git a/shell/callbacks.c b/shell/callbacks.c index 9bb5c990..b9c6252b 100644 --- a/shell/callbacks.c +++ b/shell/callbacks.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2009 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -26,7 +26,7 @@ #include "shell.h" #include "report.h" #include "syncmanager.h" -#include "xmlrpc-server.h" +#include "uri_handler.h" #include "config.h" @@ -36,15 +36,62 @@ void cb_sync_manager() sync_manager_show(shell->window); } +#if GLIB_CHECK_VERSION(2,40,0) +#else +//For compatibility with older glib +gboolean g2_key_file_save_to_file (GKeyFile *key_file, + const gchar *filename, GError **error) +{ + gchar *contents; + gboolean success; + gsize length; + + g_return_val_if_fail (key_file != NULL, FALSE); + g_return_val_if_fail (filename != NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + contents = g_key_file_to_data (key_file, &length, NULL); + g_assert (contents != NULL); + + success = g_file_set_contents (filename, contents, length, error); + g_free (contents); + + return success; +} +#endif + +void cb_sync_on_startup() +{ + gboolean setting = shell_action_get_active("SyncOnStartupAction"); + GKeyFile *key_file = g_key_file_new(); + + g_mkdir(g_get_user_config_dir(),0755); + g_mkdir(g_build_filename(g_get_user_config_dir(), "hardinfo", NULL),0755); + + gchar *conf_path = g_build_filename(g_get_user_config_dir(), "hardinfo2", + "settings.ini", NULL); + + g_key_file_load_from_file( + key_file, conf_path, + G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, NULL); + g_key_file_set_boolean(key_file, "Sync", "OnStartup", setting); +#if GLIB_CHECK_VERSION(2,40,0) + g_key_file_save_to_file(key_file, conf_path, NULL); +#else + g2_key_file_save_to_file(key_file, conf_path, NULL); +#endif + g_free(conf_path); + g_key_file_free(key_file); +} void cb_open_web_page() { - open_url("http://www.hardinfo.org"); + uri_open("https://www.hardinfo2.org"); } void cb_report_bug() { - open_url("https://github.com/lpereira/hardinfo"); + uri_open("https://github.com/hardinfo2/hardinfo2/issues"); } void cb_refresh() @@ -95,7 +142,7 @@ void cb_about_module(GtkAction * action) { Shell *shell = shell_get_main_shell(); GSList *modules = shell->tree->modules; - ModuleAbout *ma; + const ModuleAbout *ma; gchar *name; g_object_get(G_OBJECT(action), "tooltip", &name, NULL); @@ -155,31 +202,63 @@ void cb_about() GtkWidget *about; gchar *copyright = NULL; const gchar *authors[] = { - _("Author:"), - "Leandro A. F. Pereira", - "", - _("Contributors:"), + "L. A. F. Pereira (2003-2023)", + "hwspeedy(2024-)", "Agney Lopes Roth Ferraz", "Andrey Esin", "Burt P.", + "Ondrej Čerman", + "Stewart Adam", + "Pascal F. Martin", + "TotalCaesar659", + "Julian Ospald", + "Julien Lavergne", + "Fernando López", + "PICCORO Lenz McKAY", + "Alexander Münch", + "Simon Quigley", + "AsciiWolf", + "George Schneeloch", + "Mattia Rizzolo", + "Yo", + "jamesbond", + "Ondrej Čerman", + "Mike Hewitt", + "Boris Afonot", + "", + "Based on work by:", + "uber-graph by Christian Hergert and others.", + "BinReloc by Hongli Lai", + "decode-dimms by Philip Edelbrock", + "decode-dimms by Christian Zuckschwerdt", + "decode-dimms by Burkart Lingner", + "x86cpucaps by Osamu Kayasono", + "MD5 implementation by Colin Plumb", + "SHA1 implementation by Steve Reid", + "Blowfish implementation by Paul Kocher", + "Raytracing benchmark by John Walker", + "FFT benchmark by Scott Robert Ladd", + "Vendor list based on GtkSysInfo by Pissens Sebastien", + "DMI support based on code by Stewart Adam", + "SCSI support based on code by Pascal F. Martin", + "", + "Translated by:", + "Alexander Münch", + "micrococo", + "yolanteng0", + "Yunji Lee", + "Hugo Carvalho", + "Paulo Giovanni pereira", + "Sergey Rodin", + "Sabri Ünal", + "yetist", "", - _("Based on work by:"), - _("MD5 implementation by Colin Plumb (see md5.c for details)"), - _("SHA1 implementation by Steve Reid (see sha1.c for details)"), - _("Blowfish implementation by Paul Kocher (see blowfich.c for details)"), - _("Raytracing benchmark by John Walker (see fbench.c for details)"), - _("FFT benchmark by Scott Robert Ladd (see fftbench.c for details)"), - _("Some code partly based on x86cpucaps by Osamu Kayasono"), - _("Vendor list based on GtkSysInfo by Pissens Sebastien"), - _("DMI support based on code by Stewart Adam"), - _("SCSI support based on code by Pascal F. Martin"), - NULL - }; - const gchar *artists[] = { + "Artwork by:", "Jakub Szypulka", - _("Tango Project"), - _("The GNOME Project"), - _("VMWare, Inc. (USB icon from VMWare Workstation 6)"), + "Tango Project", + "The GNOME Project", + "epicbard", + "Roundicons", NULL }; @@ -187,24 +266,24 @@ void cb_about() gtk_window_set_transient_for(GTK_WINDOW(about), GTK_WINDOW(shell->window)); #if GTK_CHECK_VERSION(2, 12, 0) - gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about), "HardInfo"); + gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(about), "Hardinfo2"); #else - gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "HardInfo"); + gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about), "Hardinfo2"); #endif - copyright = g_strdup_printf("Copyright \302\251 2003-%d Leandro A. F. Pereira", HARDINFO_COPYRIGHT_LATEST_YEAR); + copyright = g_strdup_printf("Copyright \302\251 2003-2023 L. A. F. Pereira\nCopyright \302\251 2024-%d Hardinfo2 Project\n\n\n\n", HARDINFO2_COPYRIGHT_LATEST_YEAR); gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about), VERSION); gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about), copyright); gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(about), - _("System information and benchmark tool")); + _("System Information and Benchmark")); gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(about), - icon_cache_get_pixbuf("logo.png")); + icon_cache_get_pixbuf("hardinfo2.png")); gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(about), - _("HardInfo is free software; you can redistribute it and/or modify " + _("HardInfo2 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.\n\n" + "the Free Software Foundation, version 2 or later.\n\n" "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 " @@ -215,9 +294,8 @@ void cb_about() gtk_about_dialog_set_wrap_license(GTK_ABOUT_DIALOG(about), TRUE); gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(about), authors); - gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about), artists); - gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), - _("translator-credits")); + //gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(about), artists); + //gtk_about_dialog_set_translator_credits(GTK_ABOUT_DIALOG(about), _("translator-credits")); gtk_dialog_run(GTK_DIALOG(about)); gtk_widget_destroy(about); diff --git a/shell/iconcache.c b/shell/iconcache.c index 74b19b0c..8a3e6e13 100644 --- a/shell/iconcache.c +++ b/shell/iconcache.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of diff --git a/shell/loadgraph-uber.c b/shell/loadgraph-uber.c index 61964b37..08f1e2b5 100644 --- a/shell/loadgraph-uber.c +++ b/shell/loadgraph-uber.c @@ -1,7 +1,7 @@ /* * Christian Hergert's uber-graph (GPL3) * wrapped in an interface compatible with - * Leandro A. F. Pereira's loadgraph (GPL2.1). + * L. A. F. Pereira's loadgraph (GPL2.1). */ #include <string.h> @@ -75,6 +75,10 @@ GtkWidget *load_graph_get_framed(LoadGraph * lg) return NULL; } +void load_graph_set_title(LoadGraph * lg, const gchar *title) +{ +} + void load_graph_clear(LoadGraph * lg) { int i; @@ -82,7 +86,7 @@ void load_graph_clear(LoadGraph * lg) for (i = 0; i < LG_MAX_LINES; i++) { lg->cur_value[i] = UBER_LINE_GRAPH_NO_VALUE; } - uber_graph_scale_changed(lg->uber_widget); + uber_graph_scale_changed(UBER_GRAPH(lg->uber_widget)); } } diff --git a/shell/loadgraph.c b/shell/loadgraph.c index ceb91720..0290d1f1 100644 --- a/shell/loadgraph.c +++ b/shell/loadgraph.c @@ -6,7 +6,7 @@ * - fixes autoscaling * - add color * - * Copyright (C) 2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2006 L. A. F. Pereira <l@tia.mat.br> * * The Simple Load Graph is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -43,6 +43,7 @@ struct _LoadGraph { PangoLayout *layout; gchar *suffix; + gchar *title; }; static void _draw(LoadGraph * lg); @@ -56,6 +57,7 @@ LoadGraph *load_graph_new(gint size) size++; lg->suffix = g_strdup(""); + lg->title = g_strdup(""); lg->area = gtk_drawing_area_new(); lg->size = (size * 3) / 2; lg->data = g_new0(gint, lg->size); @@ -87,6 +89,18 @@ gchar *load_graph_get_data_suffix(LoadGraph * lg) return lg->suffix; } +void load_graph_set_title(LoadGraph * lg, const gchar * title) +{ + g_free(lg->title); + lg->title = g_strdup(title); +} + +const gchar *load_graph_get_title(LoadGraph *lg) +{ + if (lg != NULL) return lg->title; + return NULL; +} + GtkWidget *load_graph_get_framed(LoadGraph * lg) { GtkWidget *align, *frame; @@ -115,6 +129,8 @@ void load_graph_clear(LoadGraph * lg) lg->max_value = 1; lg->remax_count = 0; + load_graph_set_title(lg, ""); + _draw(lg); } @@ -179,6 +195,18 @@ void load_graph_configure_expose(LoadGraph * lg) (GCallback) _expose, lg); } +static void _draw_title(LoadGraph * lg, const char* title) { + gchar *tmp = g_strdup_printf("<span size=\"x-small\">%s</span>", title); + pango_layout_set_markup(lg->layout, tmp, -1); + int width = 0; + int height = 0; + pango_layout_get_pixel_size(lg->layout, &width, &height); + gint position = (lg->width / 2) - (width / 2); + gdk_draw_layout(GDK_DRAWABLE(lg->buf), lg->trace, position, 2, + lg->layout); + g_free(tmp); +} + static void _draw_label_and_line(LoadGraph * lg, gint position, gint value) { gchar *tmp; @@ -242,6 +270,9 @@ static void _draw(LoadGraph * lg) _draw_label_and_line(lg, lg->height / 2, lg->max_value / 2); _draw_label_and_line(lg, 3 * (lg->height / 4), lg->max_value / 4); + /* graph title */ + _draw_title(lg, lg->title); + gtk_widget_queue_draw(lg->area); } diff --git a/shell/menu.c b/shell/menu.c index b0f01e58..83bd8144 100644 --- a/shell/menu.c +++ b/shell/menu.c @@ -1,13 +1,13 @@ /* * HardInfo - * Copyright(C) 2003-2007 Leandro A. F. Pereira. + * Copyright(C) 2003-2007 L. A. F. Pereira. * * menu.c is based on UI Manager tutorial by Ryan McDougall * Copyright(C) 2005 Ryan McDougall. * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -31,22 +31,30 @@ #include "uidefs.h" +#ifndef GTK_STOCK_COPY +#define GTK_STOCK_COPY "_Copy" +#endif + +#ifndef GTK_STOCK_REFRESH +#define GTK_STOCK_REFRESH "_Refresh" +#endif + static GtkActionEntry entries[] = { {"InformationMenuAction", NULL, N_("_Information")}, /* name, stock id, label */ - {"RemoteMenuAction", NULL, N_("_Remote")}, + // {"RemoteMenuAction", NULL, N_("_Remote")}, {"ViewMenuAction", NULL, N_("_View")}, {"HelpMenuAction", NULL, N_("_Help")}, - {"HelpMenuModulesAction", HI_STOCK_ABOUT_MODULES, N_("About _Modules")}, + // {"HelpMenuModulesAction", HI_STOCK_ABOUT_MODULES, N_("About _Modules")}, {"MainMenuBarAction", NULL, ""}, {"ReportAction", HI_STOCK_REPORT, /* name, stock id */ N_("Generate _Report"), "<control>R", /* label, accelerator */ - NULL, /* tooltip */ + N_("Generates a report with detailed system information"), /* tooltip */ G_CALLBACK(cb_generate_report)}, {"SyncManagerAction", HI_STOCK_SYNC_MENU, - N_("_Network Updater..."), NULL, - NULL, + N_("Synchronize"), NULL, + N_("Send benchmark results and receive updated data from the network"), G_CALLBACK(cb_sync_manager)}, {"OpenAction", "_Open", @@ -54,18 +62,18 @@ static GtkActionEntry entries[] = { NULL, G_CALLBACK(cb_sync_manager)}, - {"CopyAction", "_Copy", + {"CopyAction", HI_STOCK_CLIPBOARD, N_("_Copy to Clipboard"), "<control>C", N_("Copy to clipboard"), G_CALLBACK(cb_copy_to_clipboard)}, - {"RefreshAction", "_Refresh", + {"RefreshAction", HI_STOCK_REFRESH, N_("_Refresh"), "F5", NULL, G_CALLBACK(cb_refresh)}, {"HomePageAction", HI_STOCK_INTERNET, - N_("_Open HardInfo Web Site"), NULL, + N_("_Open HardInfo2 Web Site"), NULL, NULL, G_CALLBACK(cb_open_web_page)}, @@ -75,7 +83,7 @@ static GtkActionEntry entries[] = { G_CALLBACK(cb_report_bug)}, {"AboutAction", "_About", - N_("_About HardInfo"), NULL, + N_("_About HardInfo2"), NULL, N_("Displays program version information"), G_CALLBACK(cb_about)}, @@ -94,6 +102,10 @@ static GtkToggleActionEntry toggle_entries[] = { N_("_Toolbar"), NULL, NULL, G_CALLBACK(cb_toolbar)}, + {"SyncOnStartupAction", NULL, + N_("Synchronize on startup"), NULL, + NULL, + G_CALLBACK(cb_sync_on_startup)}, }; /* Implement a handler for GtkUIManager's "add_widget" signal. The UI manager @@ -116,7 +128,7 @@ void menu_init(Shell * shell) /* Create our objects */ menu_box = shell->vbox; - action_group = gtk_action_group_new("HardInfo"); + action_group = gtk_action_group_new("HardInfo2"); menu_manager = gtk_ui_manager_new(); shell->action_group = action_group; @@ -126,7 +138,7 @@ void menu_init(Shell * shell) * menu_box -> window * actions -> action_group * action_group -> menu_manager */ - gtk_action_group_set_translation_domain( action_group, "hardinfo" );//gettext + gtk_action_group_set_translation_domain( action_group, "hardinfo2" );//gettext gtk_action_group_add_actions(action_group, entries, G_N_ELEMENTS(entries), NULL); gtk_action_group_add_toggle_actions(action_group, toggle_entries, diff --git a/shell/report.c b/shell/report.c index 6abb03a0..25b73beb 100644 --- a/shell/report.c +++ b/shell/report.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2008 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -23,6 +23,7 @@ #include <iconcache.h> #include <hardinfo.h> #include <config.h> +#include "uri_handler.h" static ReportDialog *report_dialog_new(GtkTreeModel * model, GtkWidget * parent); @@ -31,38 +32,41 @@ static void set_all_active(ReportDialog * rd, gboolean setting); static FileTypes file_types[] = { {"HTML (*.html)", "text/html", ".html", report_context_html_new}, {"Plain Text (*.txt)", "text/plain", ".txt", report_context_text_new}, + {"Shell Dump (*.txt)", "text/plain", ".txt", report_context_shell_new}, {NULL, NULL, NULL, NULL} }; +/* virtual functions */ void report_header(ReportContext * ctx) -{ - ctx->header(ctx); -} +{ ctx->header(ctx); } void report_footer(ReportContext * ctx) -{ - ctx->footer(ctx); -} +{ ctx->footer(ctx); } void report_title(ReportContext * ctx, gchar * text) -{ - ctx->title(ctx, text); -} +{ ctx->title(ctx, text); } void report_subtitle(ReportContext * ctx, gchar * text) -{ - ctx->subtitle(ctx, text); -} +{ ctx->subtitle(ctx, text); } void report_subsubtitle(ReportContext * ctx, gchar * text) -{ - ctx->subsubtitle(ctx, text); -} +{ ctx->subsubtitle(ctx, text); } -void report_key_value(ReportContext * ctx, gchar * key, gchar * value) -{ - ctx->keyvalue(ctx, key, value); -} +void report_key_value(ReportContext * ctx, gchar *key, gchar *value, gsize longest_key) +{ ctx->keyvalue(ctx, key, value, longest_key); } + +void report_details_start(ReportContext *ctx, gchar *key, gchar *value, gsize longest_key) +{ ctx->details_start(ctx, key, value, longest_key); } + +void report_details_section(ReportContext *ctx, gchar *label) +{ ctx->details_section(ctx, label); } + +void report_details_keyvalue(ReportContext *ctx, gchar *key, gchar *value, gsize longest_key) +{ ctx->details_keyvalue(ctx, key, value, longest_key); } + +void report_details_end(ReportContext *ctx) +{ ctx->details_end(ctx); } +/* end virtual functions */ gint report_get_visible_columns(ReportContext *ctx) { @@ -84,22 +88,60 @@ gint report_get_visible_columns(ReportContext *ctx) return columns; } +gchar *icon_name_css_id(const gchar *file) { + gchar *safe = g_strdup_printf("icon-%s", file); + gchar *p = safe; + while(*p) { + if (!isalnum(*p)) + *p = '-'; + p++; + } + return safe; +} + +gchar *make_icon_css(const gchar *file) { + if (!file || *file == 0) + return g_strdup(""); + gchar *ret = NULL; + gchar *path = g_build_filename(params.path_data, "pixmaps", file, NULL); + gchar *contents = NULL; + gsize length = 0; + if ( g_file_get_contents(path, &contents, &length, NULL) ) { + gchar *css_class = icon_name_css_id(file); + const char *ctype = "image/png"; + if (g_str_has_suffix(file, ".svg") ) + ctype = "image/svg+xml"; + gchar *b64data = g_base64_encode(contents, length); + ret = g_strdup_printf( + ".%s\n" + "{ background: url(data:%s;base64,%s) no-repeat;\n" + " background-size: cover; }\n", + css_class ? css_class : "", + ctype, b64data ); + g_free(b64data); + g_free(css_class); + } + g_free(contents); + g_free(path); + return ret ? ret : g_strdup(""); +} + +void cache_icon(ReportContext *ctx, const gchar *file) { + if (!ctx->icon_data) return; + if (!g_hash_table_lookup(ctx->icon_data, file) ) + g_hash_table_insert(ctx->icon_data, g_strdup(file), make_icon_css(file)); +} + void report_context_configure(ReportContext * ctx, GKeyFile * keyfile) { gchar **keys; const gchar *group = "$ShellParam$"; - /* FIXME: sometime in the future we'll save images in the report. this - flag will be set if we should support that. - - so i don't forget how to encode the images inside the html files: - https://en.wikipedia.org/wiki/Data:_URI_scheme */ - - ctx->is_image_enabled = (g_key_file_get_boolean(keyfile, - group, - "ViewType", - NULL) == SHELL_VIEW_PROGRESS); - + if (ctx->icon_refs) { + g_hash_table_remove_all(ctx->icon_refs); + ctx->icon_refs = NULL; + } + ctx->icon_refs = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); keys = g_key_file_get_keys(keyfile, group, NULL, NULL); if (keys) { @@ -143,6 +185,12 @@ void report_context_configure(ReportContext * ctx, GKeyFile * keyfile) ctx->columns &= ~REPORT_COL_VALUE; ctx->columns |= REPORT_COL_PROGRESS; } + } else if (g_str_has_prefix(key, "Icon$")) { + gchar *ikey = g_utf8_strchr(key, -1, '$'); + gchar *tag = key_mi_tag(ikey); + gchar *icon = g_key_file_get_value(keyfile, group, key, NULL); + cache_icon(ctx, icon); + g_hash_table_insert(ctx->icon_refs, tag, icon); } } @@ -151,12 +199,144 @@ void report_context_configure(ReportContext * ctx, GKeyFile * keyfile) } -void report_table(ReportContext * ctx, gchar * text) +static void report_html_details_start(ReportContext *ctx, gchar *key, gchar *value, gsize longest_key) { + guint cols = report_get_visible_columns(ctx); + report_key_value(ctx, key, value, longest_key); + ctx->parent_columns = ctx->columns; + ctx->columns = REPORT_COL_VALUE; + ctx->output = h_strdup_cprintf("<tr><td colspan=\"%d\"><table class=\"details\">\n", ctx->output, cols); +} + +static void report_html_details_end(ReportContext *ctx) { + ctx->output = h_strdup_cprintf("</table></td></tr>\n", ctx->output); + ctx->columns = ctx->parent_columns; + ctx->parent_columns = 0; +} + +void report_details(ReportContext *ctx, gchar *key, gchar *value, gchar *details, gsize longest_key) { GKeyFile *key_file = g_key_file_new(); gchar **groups; gint i; + report_details_start(ctx, key, value, longest_key); + ctx->in_details = TRUE; + + g_key_file_load_from_data(key_file, details, strlen(details), 0, NULL); + groups = g_key_file_get_groups(key_file, NULL); + + for (i = 0; groups[i]; i++) { + gchar *group, *tmpgroup; + gchar **keys; + gint j; + + if (groups[i][0] == '$') { + continue; + } + + group = groups[i]; + + tmpgroup = g_strdup(group); + strend(group, '#'); + + report_subsubtitle(ctx, group); + + keys = g_key_file_get_keys(key_file, tmpgroup, NULL, NULL); + + gsize longest_key = 0; + for (j = 0; keys[j]; j++) { + gchar *lbl; + key_get_components(keys[j], NULL, NULL, NULL, &lbl, NULL, TRUE); + longest_key = MAX(longest_key, strlen(lbl)); + g_free(lbl); + } + + for (j = 0; keys[j]; j++) { + gchar *key = keys[j]; + gchar *raw_value, *value; + + raw_value = g_key_file_get_value(key_file, tmpgroup, key, NULL); + value = g_strcompress(raw_value); /* un-escape \n, \t, etc */ + + if (g_utf8_validate(key, -1, NULL) && g_utf8_validate(value, -1, NULL)) { + strend(key, '#'); + + if (g_str_equal(value, "...")) { + g_free(value); + if (!(value = ctx->entry->fieldfunc(key))) { + value = g_strdup("..."); + } + } + + report_key_value(ctx, key, value, longest_key); + + } + + g_free(value); + g_free(raw_value); + } + + g_strfreev(keys); + g_free(tmpgroup); + } + + g_strfreev(groups); + g_key_file_free(key_file); + + ctx->in_details = FALSE; + report_details_end(ctx); +} + +static void report_table_shell_dump(ReportContext *ctx, gchar *key_file_str, int level) +{ + gchar *text, *p, *next_nl, *eq, *indent; + gchar *key, *value; + + indent = g_strnfill(level * 4, ' '); + + if (key_file_str) { + p = text = g_strdup(key_file_str); + while(next_nl = strchr(p, '\n')) { + *next_nl = 0; + eq = strchr(p, '='); + if (*p != '[' && eq) { + *eq = 0; + key = p; value = eq + 1; + + ctx->output = h_strdup_cprintf("%s%s=%s\n", ctx->output, indent, key, value); + if (key_wants_details(key) || params.force_all_details) { + gchar *mi_tag = key_mi_tag(key); + gchar *mi_data = ctx->entry->morefunc(mi_tag); /*const*/ + + if (mi_data) + report_table_shell_dump(ctx, mi_data, level + 1); + + g_free(mi_tag); + } + + } else + ctx->output = h_strdup_cprintf("%s%s\n", ctx->output, indent, p); + p = next_nl + 1; + } + } + g_free(text); + g_free(indent); + return; +} + +void report_table(ReportContext * ctx, gchar * text) +{ + GKeyFile *key_file = NULL; + gchar **groups; + gint i; + + if (ctx->format == REPORT_FORMAT_SHELL) { + report_table_shell_dump(ctx, text, 0); + return; + } + + key_file = g_key_file_new(); + /* make only "Value" column visible ("Key" column is always visible) */ ctx->columns = REPORT_COL_VALUE; ctx->show_column_headers = FALSE; @@ -166,67 +346,81 @@ void report_table(ReportContext * ctx, gchar * text) groups = g_key_file_get_groups(key_file, NULL); for (i = 0; groups[i]; i++) { - if (groups[i][0] == '$') { - report_context_configure(ctx, key_file); - break; - } + if (groups[i][0] == '$') { + report_context_configure(ctx, key_file); + break; + } } for (i = 0; groups[i]; i++) { - gchar *group, *tmpgroup; - gchar **keys; - gint j; + gchar *group, *tmpgroup; + gchar **keys; + gint j; - if (groups[i][0] == '$') { - continue; - } + if (groups[i][0] == '$') { + continue; + } - group = groups[i]; + group = groups[i]; - tmpgroup = g_strdup(group); - strend(group, '#'); + tmpgroup = g_strdup(group); + strend(group, '#'); - report_subsubtitle(ctx, group); + report_subsubtitle(ctx, group); -#if 0 - if (ctx->is_image_enabled) { - report_embed_image(ctx, key_file, group); - } else { -#endif - keys = g_key_file_get_keys(key_file, tmpgroup, NULL, NULL); - for (j = 0; keys[j]; j++) { - gchar *key = keys[j]; - gchar *value; + keys = g_key_file_get_keys(key_file, tmpgroup, NULL, NULL); - value = g_key_file_get_value(key_file, tmpgroup, key, NULL); + gsize longest_key = 0; + for (j = 0; keys[j]; j++) { + gchar *lbl; + key_get_components(keys[j], NULL, NULL, NULL, &lbl, NULL, TRUE); + longest_key = MAX(longest_key, strlen(lbl)); + g_free(lbl); + } - if (g_utf8_validate(key, -1, NULL) && g_utf8_validate(value, -1, NULL)) { - strend(key, '#'); + for (j = 0; keys[j]; j++) { + gchar *key = keys[j]; + gchar *raw_value, *value; - if (g_str_equal(value, "...")) { - g_free(value); - if (!(value = ctx->entry->fieldfunc(key))) { - value = g_strdup("..."); - } - } + raw_value = g_key_file_get_value(key_file, tmpgroup, key, NULL); + value = g_strcompress(raw_value); /* un-escape \n, \t, etc */ - if (*key == '$') { - report_key_value(ctx, strchr(key + 1, '$') + 1, - value); - } else { - report_key_value(ctx, key, value); - } + if (g_utf8_validate(key, -1, NULL) && g_utf8_validate(value, -1, NULL)) { + strend(key, '#'); - } + if (g_str_equal(value, "...")) { + g_free(value); + if (!(value = ctx->entry->fieldfunc(key))) { + value = g_strdup("..."); + } + } - g_free(value); - } + if ( key_is_flagged(key) ) { + gchar *mi_tag = key_mi_tag(key); + gchar *mi_data = NULL; /*const*/ - g_strfreev(keys); -#if 0 - } -#endif - g_free(tmpgroup); + if (key_wants_details(key) || params.force_all_details) + mi_data = ctx->entry->morefunc(mi_tag); + + if (mi_data) + report_details(ctx, key, value, mi_data, longest_key); + else + report_key_value(ctx, key, value, longest_key); + + g_free(mi_tag); + } else { + report_key_value(ctx, key, value, longest_key); + } + + } + + g_free(value); + g_free(raw_value); + } + + g_strfreev(keys); + + g_free(tmpgroup); } g_strfreev(groups); @@ -244,18 +438,35 @@ static void report_html_header(ReportContext * ctx) "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n" "<style>\n" " body { background: #fff }\n" " .title { font: bold 130%% serif; color: #0066FF; padding: 30px 0 10px 0 }\n" - " .stitle { font: bold 100%% sans-serif; color: #0044DD; padding: 30px 0 10px 0 }\n" + " .stitle { font: bold 100%% sans-serif; color: #0044DD; padding: 0 0 0 0; }\n" " .sstitle{ font: bold 80%% serif; color: #000000; background: #efefef }\n" - " .field { font: 80%% sans-serif; color: #000000; padding: 2px; padding-left: 50px }\n" + " .field { font: 80%% sans-serif; color: #000000; padding: 2px; }\n" " .value { font: 80%% sans-serif; color: #505050 }\n" + " .hilight { font: bold 110%% sans-serif; color: #000000; background: #ffff66 }\n" + " table.details { margin-left: 50px; }\n" + " td.icon { width: 1.2em; padding-left: 1.2em; }\n" + " td.icon img { width: 1.2em; }\n" + " td.icon div { display: block; box-sizing: border-box; -moz-box-sizing: border-box;\n" + " width: 1.2em; height: 1.2em; background-position: right; }\n" + " td.icon_subtitle div { display: block; box-sizing: border-box; -moz-box-sizing: border-box;\n" + " width: 1.8em; height: 1.8em; background-position: right; }\n" "</style>\n" "</head><body>\n", VERSION); } static void report_html_footer(ReportContext * ctx) { - ctx->output = h_strconcat(ctx->output, - "</table></html>", NULL); + ctx->output = h_strconcat(ctx->output, "</table>", NULL); + ctx->output = h_strconcat(ctx->output, "<style>\n", NULL); + GList *l = NULL, *keys = g_hash_table_get_keys(ctx->icon_data); + for(l = keys; l; l = l->next) { + gchar *data = g_hash_table_lookup(ctx->icon_data, (gchar*)l->data); + if (data) + ctx->output = h_strconcat(ctx->output, data, NULL); + } + g_list_free(keys); + ctx->output = h_strconcat(ctx->output, "</style>\n", NULL); + ctx->output = h_strconcat(ctx->output, "</html>", NULL); } static void report_html_title(ReportContext * ctx, gchar * text) @@ -277,11 +488,22 @@ static void report_html_subtitle(ReportContext * ctx, gchar * text) ctx->first_table = FALSE; } - ctx->output = h_strdup_cprintf("<table><tr><td colspan=\"%d\" class=\"stit" + gchar *icon = NULL; + if (ctx->entry->icon_file) { + gchar *icon_class = icon_name_css_id(ctx->entry->icon_file); + icon = g_strdup_printf("<div class=\"%s\"></div>", icon_class); + g_free(icon_class); + } else { + icon = g_strdup(""); + } + + ctx->output = h_strdup_cprintf("<table><tr><td class=\"icon_subtitle\">%s</td><td colspan=\"%d\" class=\"stit" "le\">%s</td></tr>\n", ctx->output, + icon, columns, text); + g_free(icon); } static void report_html_subsubtitle(ReportContext * ctx, gchar * text) @@ -291,27 +513,42 @@ static void report_html_subsubtitle(ReportContext * ctx, gchar * text) ctx->output = h_strdup_cprintf("<tr><td colspan=\"%d\" class=\"ssti" "tle\">%s</td></tr>\n", ctx->output, - columns, + columns+1, text); } static void -report_html_key_value(ReportContext * ctx, gchar * key, gchar * value) +report_html_key_value(ReportContext * ctx, gchar *key, gchar *value, gsize longest_key) { gint columns = report_get_visible_columns(ctx); gchar **values; gint i, mc; + gboolean highlight = key_is_highlighted(key); + gchar *tag = key_mi_tag(key); + gchar *icon = tag ? (gchar*)g_hash_table_lookup(ctx->icon_refs, tag) : NULL; + g_free(tag); + /* icon from the table is const, so can be re-used without free */ + if (icon) { + gchar *icon_class = icon_name_css_id(icon); + icon = g_strdup_printf("<div class=\"%s\"></div>", icon_class); + g_free(icon_class); + } else + icon = g_strdup(""); + + gchar *name = (gchar*)key_get_name(key); + if (columns == 2) { - ctx->output = h_strdup_cprintf("<tr><td class=\"field\">%s</td>" + ctx->output = h_strdup_cprintf("<tr%s><td class=\"icon\">%s</td><td class=\"field\">%s</td>" "<td class=\"value\">%s</td></tr>\n", ctx->output, - key, value); + highlight ? " class=\"hilight\"" : "", + icon, name, value); } else { values = g_strsplit(value, "|", columns); mc = g_strv_length(values) - 1; - ctx->output = h_strdup_cprintf("\n<tr>\n<td class=\"field\">%s</td>", ctx->output, key); + ctx->output = h_strdup_cprintf("\n<tr%s>\n<td class=\"icon\">%s</td><td class=\"field\">%s</td>", ctx->output, highlight ? " class=\"hilight\"" : "", icon, name); for (i = mc; i >= 0; i--) { ctx->output = h_strdup_cprintf("<td class=\"value\">%s</td>", @@ -323,6 +560,7 @@ report_html_key_value(ReportContext * ctx, gchar * key, gchar * value) g_strfreev(values); } + g_free(icon); } static void report_text_header(ReportContext * ctx) @@ -364,29 +602,60 @@ static void report_text_subtitle(ReportContext * ctx, gchar * text) static void report_text_subsubtitle(ReportContext * ctx, gchar * text) { - ctx->output = h_strdup_cprintf("-%s-\n", ctx->output, text); + gchar indent[10] = " "; + if (!ctx->in_details) + indent[0] = 0; + ctx->output = h_strdup_cprintf("%s-%s-\n", ctx->output, indent, text); } static void -report_text_key_value(ReportContext * ctx, gchar * key, gchar * value) +report_text_key_value(ReportContext * ctx, gchar *key, gchar *value, gsize longest_key) { gint columns = report_get_visible_columns(ctx); gchar **values; - gint i, mc; - - if (columns == 2) { - if (strlen(value)) - ctx->output = h_strdup_cprintf("%s\t\t: %s\n", ctx->output, key, value); - else - ctx->output = h_strdup_cprintf("%s\n", ctx->output, key); + gint i, mc, field_width = MAX(10, longest_key); + gchar indent[10] = " "; + if (!ctx->in_details) + indent[0] = 0; + gchar field_spacer[51]; + for(i = 0; i < 49; i++) + field_spacer[i] = ' '; + field_width = MIN(50, field_width); + field_spacer[field_width] = 0; + + gboolean highlight = key_is_highlighted(key); + gboolean multiline = (value && strlen(value) && strchr(value, '\n')); + gchar *name = (gchar*)key_get_name(key); + gchar *pf = g_strdup_printf("%s%s", indent, highlight ? "* " : " "); + gchar *rjname = g_strdup(field_spacer); + if (strlen(name) > strlen(rjname)) + name[strlen(rjname)] = 0; + strcpy(rjname + strlen(rjname) - strlen(name), name); + + if (columns == 2 || ctx->in_details) { + if (strlen(value)) { + if (multiline) { + gchar **lines = g_strsplit(value, "\n", 0); + for(i=0; lines[i]; i++) { + if (i == 0) + ctx->output = h_strdup_cprintf("%s%s : %s\n", ctx->output, pf, rjname, lines[i]); + else + ctx->output = h_strdup_cprintf("%s%s %s\n", ctx->output, pf, field_spacer, lines[i]); + } + g_strfreev(lines); + } else { + ctx->output = h_strdup_cprintf("%s%s : %s\n", ctx->output, pf, rjname, value); + } + } else + ctx->output = h_strdup_cprintf("%s%s\n", ctx->output, pf, rjname); } else { values = g_strsplit(value, "|", columns); mc = g_strv_length(values) - 1; - ctx->output = h_strdup_cprintf("%s\t", ctx->output, key); + ctx->output = h_strdup_cprintf("%s%s", ctx->output, pf, rjname); for (i = mc; i >= 0; i--) { - ctx->output = h_strdup_cprintf("%s\t", + ctx->output = h_strdup_cprintf("\t%s", ctx->output, values[i]); } @@ -395,6 +664,7 @@ report_text_key_value(ReportContext * ctx, gchar * key, gchar * value) g_strfreev(values); } + g_free(pf); } static GSList *report_create_module_list_from_dialog(ReportDialog * rd) @@ -454,18 +724,22 @@ report_create_inner_from_module_list(ReportContext * ctx, GSList * modules) ShellModule *module = (ShellModule *) modules->data; GSList *entries; - if (!params.gui_running) + if (!params.gui_running && !params.quiet) fprintf(stderr, "\033[40;32m%s\033[0m\n", module->name); report_title(ctx, module->name); for (entries = module->entries; entries; entries = entries->next) { ShellModuleEntry *entry = (ShellModuleEntry *) entries->data; + if (entry->flags & MODULE_FLAG_HIDE) continue; - if (!params.gui_running) + if (!params.gui_running && !params.quiet) fprintf(stderr, "\033[2K\033[40;32;1m %s\033[0m\n", entry->name); + if (entry->icon_file) + cache_icon(ctx, entry->icon_file); + ctx->entry = entry; report_subtitle(ctx, entry->name); module_entry_scan(entry); @@ -536,6 +810,11 @@ ReportContext *report_context_html_new() ctx->subsubtitle = report_html_subsubtitle; ctx->keyvalue = report_html_key_value; + ctx->details_start = report_html_details_start; + ctx->details_section = report_html_subsubtitle; + ctx->details_keyvalue = report_html_key_value; + ctx->details_end = report_html_details_end; + ctx->output = g_strdup(""); ctx->format = REPORT_FORMAT_HTML; @@ -543,6 +822,8 @@ ReportContext *report_context_html_new() g_free, g_free); ctx->first_table = TRUE; + ctx->icon_data = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + return ctx; } @@ -558,6 +839,11 @@ ReportContext *report_context_text_new() ctx->subsubtitle = report_text_subsubtitle; ctx->keyvalue = report_text_key_value; + ctx->details_start = report_text_key_value; + ctx->details_section = report_text_subsubtitle; + ctx->details_keyvalue = report_text_key_value; + ctx->details_end = report_text_footer; /* nothing */ + ctx->output = g_strdup(""); ctx->format = REPORT_FORMAT_TEXT; @@ -568,15 +854,45 @@ ReportContext *report_context_text_new() return ctx; } +ReportContext *report_context_shell_new() +{ + ReportContext *ctx; + + ctx = g_new0(ReportContext, 1); + ctx->header = report_text_header; + ctx->footer = report_text_footer; + + ctx->title = report_text_title; + ctx->subtitle = report_text_subtitle; + /* special format handled in report_table(), + * doesn't need the others. */ + + ctx->output = g_strdup(""); + ctx->format = REPORT_FORMAT_SHELL; + + ctx->column_titles = g_hash_table_new_full(g_str_hash, g_str_equal, + g_free, g_free); + ctx->first_table = TRUE; + + return ctx; +} + void report_context_free(ReportContext * ctx) { g_hash_table_destroy(ctx->column_titles); + if(ctx->icon_refs) + g_hash_table_destroy(ctx->icon_refs); + if(ctx->icon_data) + g_hash_table_destroy(ctx->icon_data); g_free(ctx->output); g_free(ctx); } void report_create_from_module_list(ReportContext * ctx, GSList * modules) { + if (ctx->format == REPORT_FORMAT_HTML) + params.fmt_opts = FMT_OPT_HTML; + report_header(ctx); report_create_inner_from_module_list(ctx, modules); @@ -617,6 +933,9 @@ static gboolean report_generate(ReportDialog * rd) gchar *file; FILE *stream; + int old_fmt_opts = params.fmt_opts; + params.fmt_opts = FMT_OPT_NONE; + if (!(file = report_get_filename())) return FALSE; @@ -631,6 +950,7 @@ static gboolean report_generate(ReportDialog * rd) g_warning(_("Cannot create ReportContext. Programming bug?")); g_free(file); fclose(stream); + params.fmt_opts = old_fmt_opts; return FALSE; } @@ -661,7 +981,7 @@ static gboolean report_generate(ReportDialog * rd) gchar *temp; temp = g_strdup_printf("file://%s", file); - open_url(temp); + uri_open(temp); g_free(temp); } @@ -672,6 +992,7 @@ static gboolean report_generate(ReportDialog * rd) report_context_free(ctx); g_free(file); + params.fmt_opts = old_fmt_opts; return TRUE; } diff --git a/shell/shell.c b/shell/shell.c index 8688f9ac..a2773523 100644 --- a/shell/shell.c +++ b/shell/shell.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -15,6 +15,8 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ +#define _GNU_SOURCE + #include <stdlib.h> #include <string.h> @@ -30,22 +32,31 @@ #include "iconcache.h" #include "menu.h" #include "stock.h" +#include "uri_handler.h" #include "callbacks.h" +struct UpdateTableItem { + union { + GtkWidget *widget; + GtkTreeIter *iter; + }; + gboolean is_iter; +}; + /* * Internal Prototypes ******************************************************** */ -static void create_window(); +static void create_window(void); static ShellTree *tree_new(void); -static ShellInfoTree *info_tree_new(gboolean extra); +static ShellInfoTree *info_tree_new(void); static void module_selected(gpointer data); static void module_selected_show_info(ShellModuleEntry * entry, gboolean reload); static void info_selected(GtkTreeSelection * ts, gpointer data); -static void info_selected_show_extra(gchar * data); +static void info_selected_show_extra(const gchar *tag); static gboolean reload_section(gpointer data); static gboolean rescan_section(gpointer data); static gboolean update_field(gpointer data); @@ -58,6 +69,8 @@ static Shell *shell = NULL; static GHashTable *update_tbl = NULL; static GSList *update_sfusrc = NULL; +gchar *lginterval = NULL; + /* * Code :) ******************************************************************** */ @@ -87,9 +100,8 @@ void shell_ui_manager_set_visible(const gchar * path, gboolean setting) void shell_clear_tree_models(Shell *shell) { gtk_tree_store_clear(GTK_TREE_STORE(shell->tree->model)); - gtk_tree_store_clear(GTK_TREE_STORE(shell->info->model)); - gtk_tree_store_clear(GTK_TREE_STORE(shell->moreinfo->model)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(shell->info->view), FALSE); + gtk_tree_store_clear(GTK_TREE_STORE(shell->info_tree->model)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(shell->info_tree->view), FALSE); } void shell_clear_timeouts(Shell *shell) @@ -236,7 +248,7 @@ void shell_status_pulse(void) gtk_progress_bar_pulse(GTK_PROGRESS_BAR(shell->progress)); while (gtk_events_pending()) gtk_main_iteration(); - } else { + } else if (!params.quiet) { static gint counter = 0; fprintf(stderr, "\033[2K\033[40;37;1m %c\033[0m\r", @@ -251,7 +263,7 @@ void shell_status_set_percentage(gint percentage) (float) percentage / 100.0); while (gtk_events_pending()) gtk_main_iteration(); - } else { + } else if (!params.quiet) { if (percentage < 1 || percentage >= 100) { fprintf(stderr, "\033[2K"); } else { @@ -277,14 +289,13 @@ void shell_view_set_enabled(gboolean setting) widget_set_cursor(shell->window, GDK_WATCH); } - gtk_widget_set_sensitive(shell->hpaned, setting); + gtk_widget_set_sensitive(shell->hbox, setting); shell_action_set_enabled("ViewMenuAction", setting); shell_action_set_enabled("ConnectToAction", setting); shell_action_set_enabled("RefreshAction", setting); shell_action_set_enabled("CopyAction", setting); shell_action_set_enabled("ReportAction", setting); shell_action_set_enabled("SyncManagerAction", setting && sync_manager_count_entries() > 0); - } void shell_status_set_enabled(gboolean setting) @@ -328,7 +339,7 @@ void shell_status_update(const gchar * message) gtk_progress_bar_pulse(GTK_PROGRESS_BAR(shell->progress)); while (gtk_events_pending()) gtk_main_iteration(); - } else { + } else if (!params.quiet) { fprintf(stderr, "\033[2K\033[40;37;1m %s\033[0m\r", message); } } @@ -362,12 +373,8 @@ static ShellNote *note_new(void) gtk_container_add(GTK_CONTAINER(note->event_box), border_box); gtk_widget_show(border_box); -#if GTK_CHECK_VERSION(3, 0, 0) - /* TODO:GTK3 css-based style */ -#else gtk_widget_modify_bg(border_box, GTK_STATE_NORMAL, &info_default_fill_color); gtk_widget_modify_bg(note->event_box, GTK_STATE_NORMAL, &info_default_border_color); -#endif icon = icon_cache_get_image("close.png"); gtk_widget_show(icon); @@ -399,12 +406,12 @@ void shell_set_title(Shell *shell, gchar *subtitle) if (subtitle) { gchar *tmp; - tmp = g_strdup_printf(_("%s - System Information"), subtitle); + tmp = g_strdup_printf(_("%s - System Information and Benchmark"), subtitle); gtk_window_set_title(GTK_WINDOW(shell->window), tmp); g_free(tmp); } else { - gtk_window_set_title(GTK_WINDOW(shell->window), _("System Information")); + gtk_window_set_title(GTK_WINDOW(shell->window), _("System Information and Benchmark")); } } @@ -416,9 +423,9 @@ static void create_window(void) shell->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_icon(GTK_WINDOW(shell->window), - icon_cache_get_pixbuf("logo.png")); + icon_cache_get_pixbuf("hardinfo2.png")); shell_set_title(shell, NULL); - gtk_window_set_default_size(GTK_WINDOW(shell->window), 800, 600); + gtk_window_set_default_size(GTK_WINDOW(shell->window), 1024, 800); g_signal_connect(G_OBJECT(shell->window), "destroy", destroy_me, NULL); #if GTK_CHECK_VERSION(3, 0, 0) @@ -455,13 +462,12 @@ static void create_window(void) gtk_box_pack_start(GTK_BOX(hbox), shell->status, FALSE, FALSE, 5); #if GTK_CHECK_VERSION(3, 0, 0) - shell->hpaned = gtk_paned_new(GTK_ORIENTATION_HORIZONTAL); + shell->hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); #else - shell->hpaned = gtk_hpaned_new(); + shell->hbox = gtk_hbox_new(FALSE, 5); #endif - gtk_widget_show(shell->hpaned); - gtk_box_pack_end(GTK_BOX(vbox), shell->hpaned, TRUE, TRUE, 0); - gtk_paned_set_position(GTK_PANED(shell->hpaned), 210); + gtk_widget_show(shell->hbox); + gtk_box_pack_end(GTK_BOX(vbox), shell->hbox, TRUE, TRUE, 0); #if GTK_CHECK_VERSION(3, 0, 0) vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); @@ -469,7 +475,7 @@ static void create_window(void) vbox = gtk_vbox_new(FALSE, 5); #endif gtk_widget_show(vbox); - gtk_paned_add2(GTK_PANED(shell->hpaned), vbox); + gtk_box_pack_end(GTK_BOX(shell->hbox), vbox, TRUE, TRUE, 0); shell->note = note_new(); gtk_box_pack_end(GTK_BOX(vbox), shell->note->event_box, FALSE, FALSE, 0); @@ -512,10 +518,8 @@ static void menu_item_set_icon_always_visible(Shell *shell, path = g_strdup_printf("%s/%s", parent_path, item_id); menuitem = gtk_ui_manager_get_widget(shell->ui_manager, path); -#if GTK_CHECK_VERSION(3, 0, 0) -#else - gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(menuitem), TRUE); -#endif + + //gtk_image_menu_item_set_always_show_image(GTK_IMAGE_MENU_ITEM(menuitem), TRUE); g_free(path); } @@ -568,7 +572,8 @@ static void add_module_to_menu(gchar * name, GdkPixbuf * pixbuf) merge_id = gtk_ui_manager_new_merge_id(shell->ui_manager); gtk_ui_manager_add_ui(shell->ui_manager, merge_id, - "/menubar/HelpMenu/HelpMenuModules/LastSep", + // "/menubar/HelpMenu/HelpMenuModules/LastSep", + "/menubar/HelpMenu/LastSep", about_module, about_module, GTK_UI_MANAGER_AUTO, TRUE); shell->merge_ids = g_slist_prepend(shell->merge_ids, GINT_TO_POINTER(merge_id)); @@ -638,7 +643,7 @@ void shell_add_modules_to_gui(gpointer _shell_module, gpointer _shell_tree) -1); } - add_module_to_menu(module->name, module->icon); + //add_module_to_menu(module->name, module->icon); if (module->entries) { ShellModuleEntry *entry; @@ -647,6 +652,7 @@ void shell_add_modules_to_gui(gpointer _shell_module, gpointer _shell_tree) for (p = module->entries; p; p = g_slist_next(p)) { GtkTreeIter child; entry = (ShellModuleEntry *) p->data; + if (entry->flags & MODULE_FLAG_HIDE) continue; gtk_tree_store_append(store, &child, &parent); gtk_tree_store_set(store, &child, TREE_COL_NAME, entry->name, @@ -668,38 +674,44 @@ void shell_add_modules_to_gui(gpointer _shell_module, gpointer _shell_tree) } } -static void __tree_iter_destroy(gpointer data) +static void destroy_update_tbl_value(gpointer data) { - gtk_tree_iter_free((GtkTreeIter *) data); + struct UpdateTableItem *item = data; + + if (item->is_iter) { + gtk_tree_iter_free(item->iter); + } else { + g_object_unref(item->widget); + } + + g_free(item); } -ShellSummary *summary_new(void) +DetailView *detail_view_new(void) { - ShellSummary *summary; + DetailView *detail_view; - summary = g_new0(ShellSummary, 1); - summary->scroll = gtk_scrolled_window_new(NULL, NULL); + detail_view = g_new0(DetailView, 1); + detail_view->scroll = gtk_scrolled_window_new(NULL, NULL); #if GTK_CHECK_VERSION(3, 0, 0) - summary->view = gtk_box_new(GTK_ORIENTATION_VERTICAL, 5); + detail_view->view = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); #else - summary->view = gtk_vbox_new(FALSE, 5); + detail_view->view = gtk_vbox_new(FALSE, 0); #endif - summary->items = NULL; - gtk_container_set_border_width(GTK_CONTAINER(summary->view), 6); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(summary->scroll), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(detail_view->scroll), + GTK_SHADOW_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(detail_view->scroll), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); #if GTK_CHECK_VERSION(3, 0, 0) - gtk_container_add(GTK_CONTAINER(summary->scroll), - summary->view); + gtk_container_add(GTK_CONTAINER(detail_view->scroll), detail_view->view); #else - gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(summary->scroll), - summary->view); + gtk_scrolled_window_add_with_viewport( + GTK_SCROLLED_WINDOW(detail_view->scroll), detail_view->view); #endif - gtk_widget_show_all(summary->scroll); + gtk_widget_show_all(detail_view->scroll); - return summary; + return detail_view; } static gboolean @@ -713,6 +725,50 @@ select_first_tree_item(gpointer data) return FALSE; } +static void +check_for_updates(void) +{ + GKeyFile *key_file = g_key_file_new(); + + gchar *conf_path = g_build_filename(g_get_user_config_dir(), "hardinfo2", + "settings.ini", NULL); + + g_key_file_load_from_file( + key_file, conf_path, + G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, NULL); + + gboolean setting = g_key_file_get_boolean(key_file, "Sync", "OnStartup", NULL); + shell_action_set_active("SyncOnStartupAction", setting); + + g_free(conf_path); + g_key_file_free(key_file); + + if (setting) { + sync_manager_update_on_startup(); + } +} + +gboolean hardinfo_link(const gchar *uri) { + /* Clicked link events pass through here on their + * way to the default handler (xdg-open). + * + * TODO: In the future, links could be used to + * jump to different pages in hardinfo. + * + * if (g_str_has_prefix(uri, "hardinfo:")) { + * hardinfo_navigate(g_utf8_strchr(uri, strlen("hardinfo2"), ':') + 1); + * return TRUE; + * } + */ + + return FALSE; /* didn't handle it */ +} + +void shell_set_transient_dialog(GtkWindow *dialog) +{ + shell->transient_dialog = dialog ? dialog : GTK_WINDOW(shell->window); +} + void shell_init(GSList * modules) { if (shell) { @@ -722,6 +778,9 @@ void shell_init(GSList * modules) DEBUG("initializing shell"); + uri_set_function(hardinfo_link); + params.fmt_opts = FMT_OPT_PANGO; + create_window(); shell_action_set_property("ConnectToAction", "is-important", TRUE); @@ -729,28 +788,27 @@ void shell_init(GSList * modules) shell_action_set_property("RefreshAction", "is-important", TRUE); shell_action_set_property("ReportAction", "is-important", TRUE); shell_action_set_property("ReportBugAction", "is-important", TRUE); + shell_action_set_property("SyncManagerAction", "is-important", TRUE); shell->tree = tree_new(); - shell->info = info_tree_new(FALSE); - shell->moreinfo = info_tree_new(TRUE); + shell->info_tree = info_tree_new(); shell->loadgraph = load_graph_new(75); - shell->summary = summary_new(); + shell->detail_view = detail_view_new(); + shell->transient_dialog = GTK_WINDOW(shell->window); update_tbl = g_hash_table_new_full(g_str_hash, g_str_equal, - g_free, __tree_iter_destroy); + g_free, destroy_update_tbl_value); - gtk_paned_pack1(GTK_PANED(shell->hpaned), shell->tree->scroll, - SHELL_PACK_RESIZE, SHELL_PACK_SHRINK); - gtk_paned_pack1(GTK_PANED(shell->vpaned), shell->info->scroll, + gtk_box_pack_start(GTK_BOX(shell->hbox), shell->tree->scroll, + FALSE, FALSE, 0); + gtk_paned_pack1(GTK_PANED(shell->vpaned), shell->info_tree->scroll, SHELL_PACK_RESIZE, SHELL_PACK_SHRINK); gtk_notebook_append_page(GTK_NOTEBOOK(shell->notebook), - shell->moreinfo->scroll, NULL); - gtk_notebook_append_page(GTK_NOTEBOOK(shell->notebook), load_graph_get_framed(shell->loadgraph), NULL); gtk_notebook_append_page(GTK_NOTEBOOK(shell->notebook), - shell->summary->scroll, NULL); + shell->detail_view->scroll, NULL); gtk_notebook_set_show_tabs(GTK_NOTEBOOK(shell->notebook), FALSE); gtk_notebook_set_show_border(GTK_NOTEBOOK(shell->notebook), FALSE); @@ -760,10 +818,12 @@ void shell_init(GSList * modules) shell->tree->modules = modules ? modules : modules_load_all(); + check_for_updates(); + g_slist_foreach(shell->tree->modules, shell_add_modules_to_gui, shell->tree); gtk_tree_view_expand_all(GTK_TREE_VIEW(shell->tree->view)); - gtk_widget_show_all(shell->hpaned); + gtk_widget_show_all(shell->hbox); load_graph_configure_expose(shell->loadgraph); gtk_widget_hide(shell->notebook); @@ -777,11 +837,7 @@ void shell_init(GSList * modules) shell_action_set_active("SidePaneAction", TRUE); shell_action_set_active("ToolbarAction", TRUE); -#ifndef HAS_LIBSOUP - shell_action_set_enabled("SyncManagerAction", FALSE); -#else shell_action_set_enabled("SyncManagerAction", sync_manager_count_entries() > 0); -#endif /* Should select Computer Summary (note: not Computer/Summary) */ g_idle_add(select_first_tree_item, NULL); @@ -790,48 +846,56 @@ void shell_init(GSList * modules) static gboolean update_field(gpointer data) { ShellFieldUpdate *fu; - GtkTreeIter *iter; + struct UpdateTableItem *item; - fu = (ShellFieldUpdate *) data; + fu = (ShellFieldUpdate *)data; g_return_val_if_fail(fu != NULL, FALSE); DEBUG("update_field [%s]", fu->field_name); - iter = g_hash_table_lookup(update_tbl, fu->field_name); - if (!iter) { + item = g_hash_table_lookup(update_tbl, fu->field_name); + if (!item) { return FALSE; } /* if the entry is still selected, update it */ - if (iter && fu->entry->selected && fu->entry->fieldfunc) { - GtkTreeStore *store = GTK_TREE_STORE(shell->info->model); - gchar *value = fu->entry->fieldfunc(fu->field_name); - - /* - * this function is also used to feed the load graph when ViewType - * is SHELL_VIEW_LOAD_GRAPH - */ - if (shell->view_type == SHELL_VIEW_LOAD_GRAPH && - gtk_tree_selection_iter_is_selected(shell->info->selection, - iter)) { - load_graph_update(shell->loadgraph, atof(value)); - } + if (fu->entry->selected && fu->entry->fieldfunc) { + gchar *value = fu->entry->fieldfunc(fu->field_name); + + if (item->is_iter) { + /* + * this function is also used to feed the load graph when ViewType + * is SHELL_VIEW_LOAD_GRAPH + */ + if (shell->view_type == SHELL_VIEW_LOAD_GRAPH && + gtk_tree_selection_iter_is_selected(shell->info_tree->selection, + item->iter)) { + + load_graph_set_title(shell->loadgraph, fu->field_name); + load_graph_update(shell->loadgraph, atof(value)); + } - gtk_tree_store_set(store, iter, INFO_TREE_COL_VALUE, value, -1); + GtkTreeStore *store = GTK_TREE_STORE(shell->info_tree->model); + gtk_tree_store_set(store, item->iter, INFO_TREE_COL_VALUE, value, -1); + } else { + GList *children = gtk_container_get_children(GTK_CONTAINER(item->widget)); + gtk_label_set_markup(GTK_LABEL(children->next->data), value); + g_list_free(children); + } - g_free(value); - return TRUE; + g_free(value); + return TRUE; } if (update_sfusrc) { - GSList *sfu; + GSList *sfu; - for (sfu = update_sfusrc; sfu; sfu = sfu->next) { - g_free(sfu->data); - } + for (sfu = update_sfusrc; sfu; sfu = sfu->next) { + g_free(sfu->data); + } - g_slist_free(update_sfusrc); - update_sfusrc = NULL; + g_slist_free(update_sfusrc); + update_sfusrc = NULL; } /* otherwise, cleanup and destroy the timeout */ @@ -841,77 +905,101 @@ static gboolean update_field(gpointer data) return FALSE; } -#define RANGE_SET_VALUE(tree,scrollbar,value) \ - do { \ - GtkRange CONCAT(*range, __LINE__) = GTK_RANGE(GTK_SCROLLED_WINDOW(shell->tree->scroll)->scrollbar); \ - gtk_range_set_value(CONCAT(range, __LINE__), value); \ - gtk_adjustment_value_changed(GTK_ADJUSTMENT(gtk_range_get_adjustment(CONCAT(range, __LINE__)))); \ - } while (0) -#define RANGE_GET_VALUE(tree,scrollbar) \ - gtk_range_get_value(GTK_RANGE \ - (GTK_SCROLLED_WINDOW(shell->tree->scroll)-> \ - scrollbar)) +#if GTK_CHECK_VERSION(3, 0, 0) +#define RANGE_SET_VALUE(...) +#define RANGE_GET_VALUE(...) 0 +#else +#define RANGE_SET_VALUE(tree, scrollbar, value) \ + do { \ + GtkRange CONCAT(*range, __LINE__) = \ + GTK_RANGE(GTK_SCROLLED_WINDOW(shell->tree->scroll)->scrollbar); \ + gtk_range_set_value(CONCAT(range, __LINE__), value); \ + gtk_adjustment_value_changed(GTK_ADJUSTMENT( \ + gtk_range_get_adjustment(CONCAT(range, __LINE__)))); \ + } while (0) +#define RANGE_GET_VALUE(tree, scrollbar) \ + gtk_range_get_value( \ + GTK_RANGE(GTK_SCROLLED_WINDOW(shell->tree->scroll)->scrollbar)) +#endif + +static void +destroy_widget(GtkWidget *widget, gpointer user_data) +{ + gtk_widget_destroy(widget); +} + +static void detail_view_clear(DetailView *detail_view) +{ + gtk_container_forall(GTK_CONTAINER(shell->detail_view->view), + destroy_widget, NULL); + RANGE_SET_VALUE(detail_view, vscrollbar, 0.0); + RANGE_SET_VALUE(detail_view, hscrollbar, 0.0); +} static gboolean reload_section(gpointer data) { - ShellModuleEntry *entry = (ShellModuleEntry *) data; + ShellModuleEntry *entry = (ShellModuleEntry *)data; #if GTK_CHECK_VERSION(2, 14, 0) GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(shell->window)); #endif /* if the entry is still selected, update it */ if (entry->selected) { - GtkTreePath *path = NULL; - GtkTreeIter iter; - double pos_info_scroll, pos_more_scroll; + GtkTreePath *path = NULL; + GtkTreeIter iter; + double pos_info_scroll; + double pos_detail_scroll; - /* save current position */ + /* save current position */ #if GTK_CHECK_VERSION(3, 0, 0) - /* TODO:GTK3 */ + /* TODO:GTK3 */ #else - pos_info_scroll = RANGE_GET_VALUE(info, vscrollbar); - pos_more_scroll = RANGE_GET_VALUE(moreinfo, vscrollbar); + pos_info_scroll = RANGE_GET_VALUE(info_tree, vscrollbar); + pos_detail_scroll = RANGE_GET_VALUE(detail_view, vscrollbar); #endif - /* avoid drawing the window while we reload */ + /* avoid drawing the window while we reload */ #if GTK_CHECK_VERSION(2, 14, 0) - gdk_window_freeze_updates(gdk_window); + gdk_window_freeze_updates(gdk_window); #else - gdk_window_freeze_updates(shell->window->window); + gdk_window_freeze_updates(shell->window->window); #endif - /* gets the current selected path */ - if (gtk_tree_selection_get_selected - (shell->info->selection, &shell->info->model, &iter)) { - path = gtk_tree_model_get_path(shell->info->model, &iter); + /* gets the current selected path */ + if (gtk_tree_selection_get_selected(shell->info_tree->selection, + &shell->info_tree->model, &iter)) { + path = gtk_tree_model_get_path(shell->info_tree->model, &iter); } - /* update the information, clear the treeview and populate it again */ - module_entry_reload(entry); - info_selected_show_extra(NULL); /* clears the more info store */ - module_selected_show_info(entry, TRUE); - - /* if there was a selection, reselect it */ - if (path) { - gtk_tree_selection_select_path(shell->info->selection, path); - gtk_tree_view_set_cursor(GTK_TREE_VIEW(shell->info->view), path, NULL, - FALSE); - gtk_tree_path_free(path); + /* update the information, clear the treeview and populate it again */ + module_entry_reload(entry); + detail_view_clear(shell->detail_view); + module_selected_show_info(entry, TRUE); + + /* if there was a selection, reselect it */ + if (path) { + gtk_tree_selection_select_path(shell->info_tree->selection, path); + gtk_tree_view_set_cursor(GTK_TREE_VIEW(shell->info_tree->view), + path, NULL, FALSE); + gtk_tree_path_free(path); } else { /* restore position */ #if GTK_CHECK_VERSION(3, 0, 0) - /* TODO:GTK3 */ + /* TODO:GTK3 */ #else - RANGE_SET_VALUE(info, vscrollbar, pos_info_scroll); - RANGE_SET_VALUE(moreinfo, vscrollbar, pos_more_scroll); + RANGE_SET_VALUE(info_tree, vscrollbar, pos_info_scroll); #endif } - /* make the window drawable again */ +#if !GTK_CHECK_VERSION(3, 0, 0) + RANGE_SET_VALUE(detail_view, vscrollbar, pos_detail_scroll); +#endif + + /* make the window drawable again */ #if GTK_CHECK_VERSION(2, 14, 0) - gdk_window_thaw_updates(gdk_window); + gdk_window_thaw_updates(gdk_window); #else - gdk_window_thaw_updates(shell->window->window); + gdk_window_thaw_updates(shell->window->window); #endif } @@ -967,331 +1055,334 @@ static void set_view_type(ShellViewType viewtype, gboolean reload) #if GTK_CHECK_VERSION(2, 18, 0) GtkAllocation* alloc; #endif + gboolean type_changed = FALSE; + if (viewtype != shell->view_type) + type_changed = TRUE; if (viewtype < SHELL_VIEW_NORMAL || viewtype >= SHELL_VIEW_N_VIEWS) - viewtype = SHELL_VIEW_NORMAL; + viewtype = SHELL_VIEW_NORMAL; shell->normalize_percentage = TRUE; shell->view_type = viewtype; shell->_order_type = SHELL_ORDER_DESCENDING; /* use an unsorted tree model */ - GtkTreeSortable *sortable = GTK_TREE_SORTABLE(shell->info->model); + GtkTreeSortable *sortable = GTK_TREE_SORTABLE(shell->info_tree->model); gtk_tree_sortable_set_sort_column_id(sortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, GTK_SORT_ASCENDING); - gtk_tree_view_set_model(GTK_TREE_VIEW(shell->info->view), + gtk_tree_view_set_model(GTK_TREE_VIEW(shell->info_tree->view), GTK_TREE_MODEL(sortable)); /* reset to the default view columns */ if (!reload) { - gtk_tree_view_column_set_visible(shell->info->col_extra1, FALSE); - gtk_tree_view_column_set_visible(shell->info->col_extra2, FALSE); - gtk_tree_view_column_set_visible(shell->info->col_progress, FALSE); - gtk_tree_view_column_set_visible(shell->info->col_value, TRUE); + gtk_tree_view_column_set_visible(shell->info_tree->col_extra1, FALSE); + gtk_tree_view_column_set_visible(shell->info_tree->col_extra2, FALSE); + gtk_tree_view_column_set_visible(shell->info_tree->col_progress, FALSE); + gtk_tree_view_column_set_visible(shell->info_tree->col_value, TRUE); } /* turn off the rules hint */ #if GTK_CHECK_VERSION(3, 0, 0) #else - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(shell->info->view), FALSE); + gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(shell->info_tree->view), FALSE); #endif close_note(NULL, NULL); + detail_view_clear(shell->detail_view); switch (viewtype) { default: case SHELL_VIEW_NORMAL: - gtk_widget_show(shell->info->scroll); - gtk_widget_hide(shell->notebook); + gtk_widget_show(shell->info_tree->scroll); + gtk_widget_hide(shell->notebook); - if (!reload) { - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(shell->info->view), FALSE); + if (!reload) { + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(shell->info_tree->view), FALSE); } - break; + break; case SHELL_VIEW_DUAL: - gtk_widget_show(shell->info->scroll); - gtk_widget_show(shell->moreinfo->scroll); - gtk_notebook_set_current_page(GTK_NOTEBOOK(shell->notebook), 0); + gtk_widget_show(shell->info_tree->scroll); + gtk_notebook_set_current_page(GTK_NOTEBOOK(shell->notebook), 1); gtk_widget_show(shell->notebook); + if (type_changed) { #if GTK_CHECK_VERSION(2, 18, 0) - alloc = g_new(GtkAllocation, 1); - gtk_widget_get_allocation(shell->hpaned, alloc); - gtk_paned_set_position(GTK_PANED(shell->vpaned), alloc->height / 2); - g_free(alloc); + alloc = g_new(GtkAllocation, 1); + gtk_widget_get_allocation(shell->hbox, alloc); + gtk_paned_set_position(GTK_PANED(shell->vpaned), alloc->height / 2); + g_free(alloc); #else - gtk_paned_set_position(GTK_PANED(shell->vpaned), - shell->hpaned->allocation.height / 2); + gtk_paned_set_position(GTK_PANED(shell->vpaned), + shell->hbox->allocation.height / 2); #endif + } break; case SHELL_VIEW_LOAD_GRAPH: - gtk_widget_show(shell->info->scroll); - gtk_notebook_set_current_page(GTK_NOTEBOOK(shell->notebook), 1); + gtk_widget_show(shell->info_tree->scroll); + gtk_notebook_set_current_page(GTK_NOTEBOOK(shell->notebook), 0); gtk_widget_show(shell->notebook); load_graph_clear(shell->loadgraph); + if (type_changed) { #if GTK_CHECK_VERSION(2, 18, 0) - alloc = g_new(GtkAllocation, 1); - gtk_widget_get_allocation(shell->hpaned, alloc); - gtk_paned_set_position(GTK_PANED(shell->vpaned), - alloc->height - load_graph_get_height(shell->loadgraph) - 16); - g_free(alloc); + alloc = g_new(GtkAllocation, 1); + gtk_widget_get_allocation(shell->hbox, alloc); + gtk_paned_set_position(GTK_PANED(shell->vpaned), + alloc->height - load_graph_get_height(shell->loadgraph) - 16); + g_free(alloc); #else - gtk_paned_set_position(GTK_PANED(shell->vpaned), - shell->hpaned->allocation.height - - load_graph_get_height(shell->loadgraph) - 16); + gtk_paned_set_position(GTK_PANED(shell->vpaned), + shell->hbox->allocation.height - + load_graph_get_height(shell->loadgraph) - 16); #endif - - break; + } + break; case SHELL_VIEW_PROGRESS_DUAL: gtk_widget_show(shell->notebook); - gtk_widget_show(shell->moreinfo->scroll); - gtk_notebook_set_current_page(GTK_NOTEBOOK(shell->notebook), 0); + gtk_notebook_set_current_page(GTK_NOTEBOOK(shell->notebook), 1); /* fallthrough */ case SHELL_VIEW_PROGRESS: - gtk_widget_show(shell->info->scroll); + gtk_widget_show(shell->info_tree->scroll); if (!reload) { - gtk_tree_view_column_set_visible(shell->info->col_progress, TRUE); - gtk_tree_view_column_set_visible(shell->info->col_value, FALSE); + gtk_tree_view_column_set_visible(shell->info_tree->col_progress, TRUE); + gtk_tree_view_column_set_visible(shell->info_tree->col_value, FALSE); } if (viewtype == SHELL_VIEW_PROGRESS) gtk_widget_hide(shell->notebook); break; - case SHELL_VIEW_SUMMARY: - gtk_notebook_set_current_page(GTK_NOTEBOOK(shell->notebook), 2); + case SHELL_VIEW_DETAIL: + gtk_notebook_set_current_page(GTK_NOTEBOOK(shell->notebook), 1); gtk_widget_show(shell->notebook); - gtk_widget_hide(shell->info->scroll); - gtk_widget_hide(shell->moreinfo->scroll); + gtk_widget_hide(shell->info_tree->scroll); } } -static void -group_handle_special(GKeyFile * key_file, ShellModuleEntry * entry, - gchar * group, gchar ** keys, gboolean reload) +static void group_handle_special(GKeyFile *key_file, + ShellModuleEntry *entry, + const gchar *group, + gchar **keys) { - if (g_str_equal(group, "$ShellParam$")) { - gboolean headers_visible = FALSE; - gint i; - - for (i = 0; keys[i]; i++) { - gchar *key = keys[i]; - - if (g_str_has_prefix(key, "UpdateInterval")) { - ShellFieldUpdate *fu = g_new0(ShellFieldUpdate, 1); - ShellFieldUpdateSource *sfutbl; - gint ms; - - ms = g_key_file_get_integer(key_file, group, key, NULL); - - fu->field_name = g_strdup(g_utf8_strchr(key, -1, '$') + 1); - fu->entry = entry; - - sfutbl = g_new0(ShellFieldUpdateSource, 1); - sfutbl->source_id = g_timeout_add(ms, update_field, fu); - sfutbl->sfu = fu; - - update_sfusrc = g_slist_prepend(update_sfusrc, sfutbl); - } else if (g_str_equal(key, "NormalizePercentage")) { - shell->normalize_percentage = g_key_file_get_boolean(key_file, group, key, NULL); - } else if (g_str_equal(key, "LoadGraphSuffix")) { - gchar *suffix = - g_key_file_get_value(key_file, group, key, NULL); - load_graph_set_data_suffix(shell->loadgraph, suffix); - g_free(suffix); - } else if (g_str_equal(key, "ReloadInterval")) { - gint ms; - - ms = g_key_file_get_integer(key_file, group, key, NULL); - - g_timeout_add(ms, reload_section, entry); - } else if (g_str_equal(key, "RescanInterval")) { - gint ms; - - ms = g_key_file_get_integer(key_file, group, key, NULL); - - g_timeout_add(ms, rescan_section, entry); - } else if (g_str_equal(key, "ShowColumnHeaders")) { - headers_visible = g_key_file_get_boolean(key_file, group, key, NULL); - } else if (g_str_has_prefix(key, "ColumnTitle")) { - GtkTreeViewColumn *column = NULL; - gchar *value, *title = g_utf8_strchr(key, -1, '$') + 1; - - value = g_key_file_get_value(key_file, group, key, NULL); - - if (g_str_equal(title, "Extra1")) { - column = shell->info->col_extra1; - } else if (g_str_equal(title, "Extra2")) { - column = shell->info->col_extra2; - } else if (g_str_equal(title, "Value")) { - column = shell->info->col_value; - } else if (g_str_equal(title, "TextValue")) { - column = shell->info->col_textvalue; - } else if (g_str_equal(title, "Progress")) { - column = shell->info->col_progress; - } + if (!g_str_equal(group, "$ShellParam$")) { + g_warning("Unknown parameter group: ``%s''", group); + return; + } - if (column) { - gtk_tree_view_column_set_title(column, value); - gtk_tree_view_column_set_visible(column, TRUE); - } + gboolean headers_visible = FALSE; + gint i; - g_free(value); - } else if (g_str_equal(key, "OrderType")) { - shell->_order_type = g_key_file_get_integer(key_file, - group, - key, NULL); - } else if (g_str_equal(key, "ViewType")) { - set_view_type(g_key_file_get_integer(key_file, group, - key, NULL), reload); - } else if (g_str_has_prefix(key, "Icon")) { - GtkTreeIter *iter = g_hash_table_lookup(update_tbl, - g_utf8_strchr(key, - -1, '$') + 1); - - if (iter) { - gchar *file = - g_key_file_get_value(key_file, group, key, NULL); - gtk_tree_store_set(GTK_TREE_STORE(shell->info->model), - iter, INFO_TREE_COL_PBUF, - icon_cache_get_pixbuf_at_size(file, - 22, - 22), - -1); - g_free(file); - } - } else if (g_str_equal(key, "Zebra")) { + for (i = 0; keys[i]; i++) { + gchar *key = keys[i]; + + if (g_str_has_prefix(key, "UpdateInterval$")) { + ShellFieldUpdate *fu = g_new0(ShellFieldUpdate, 1); + ShellFieldUpdateSource *sfutbl; + gint ms; + + ms = g_key_file_get_integer(key_file, group, key, NULL); + + /* Old style used just the label which has to be checked by translating it, + * and potentially could by ambiguous. + * New style can use tag or label. If new style including a tag, + * send both tag and label and let the hi_get_field() function use + * key_get_components() to split it. */ + const gchar *chk = g_utf8_strchr(key, -1, '$'); + fu->field_name = g_strdup(key_is_flagged(chk) ? chk : chk + 1); + fu->entry = entry; + + sfutbl = g_new0(ShellFieldUpdateSource, 1); + sfutbl->source_id = g_timeout_add(ms, update_field, fu); + sfutbl->sfu = fu; + + update_sfusrc = g_slist_prepend(update_sfusrc, sfutbl); + } else if (g_str_equal(key, "NormalizePercentage")) { + shell->normalize_percentage = + g_key_file_get_boolean(key_file, group, key, NULL); + } else if (g_str_equal(key, "LoadGraphSuffix")) { + gchar *suffix = g_key_file_get_value(key_file, group, key, NULL); + load_graph_set_data_suffix(shell->loadgraph, suffix); + g_free(suffix); + } else if (g_str_equal(key, "ReloadInterval")) { + gint ms; + + ms = g_key_file_get_integer(key_file, group, key, NULL); + + g_timeout_add(ms, reload_section, entry); + } else if (g_str_equal(key, "RescanInterval")) { + gint ms; + + ms = g_key_file_get_integer(key_file, group, key, NULL); + + g_timeout_add(ms, rescan_section, entry); + } else if (g_str_equal(key, "ShowColumnHeaders")) { + headers_visible = + g_key_file_get_boolean(key_file, group, key, NULL); + } else if (g_str_has_prefix(key, "ColumnTitle")) { + GtkTreeViewColumn *column = NULL; + gchar *value, *title = g_utf8_strchr(key, -1, '$') + 1; + + value = g_key_file_get_value(key_file, group, key, NULL); + + if (g_str_equal(title, "Extra1")) { + column = shell->info_tree->col_extra1; + } else if (g_str_equal(title, "Extra2")) { + column = shell->info_tree->col_extra2; + } else if (g_str_equal(title, "Value")) { + column = shell->info_tree->col_value; + } else if (g_str_equal(title, "TextValue")) { + column = shell->info_tree->col_textvalue; + } else if (g_str_equal(title, "Progress")) { + column = shell->info_tree->col_progress; + } + + if (column) { + gtk_tree_view_column_set_title(column, value); + gtk_tree_view_column_set_visible(column, TRUE); + } + + g_free(value); + } else if (g_str_equal(key, "OrderType")) { + shell->_order_type = + g_key_file_get_integer(key_file, group, key, NULL); + } else if (g_str_has_prefix(key, "Icon$")) { + struct UpdateTableItem *item; + + const gchar *ikey = g_utf8_strchr(key, -1, '$'); + gchar *tag, *name; + key_get_components(ikey, NULL, &tag, &name, NULL, NULL, TRUE); + + if (tag) + item = g_hash_table_lookup(update_tbl, tag); + else + item = g_hash_table_lookup(update_tbl, name); + g_free(name); + g_free(tag); + + if (item) { + gchar *file = g_key_file_get_value(key_file, group, key, NULL); + GdkPixbuf *pixbuf = icon_cache_get_pixbuf_at_size(file, 22, 22); + + g_free(file); + + if (item->is_iter) { + gtk_tree_store_set( + GTK_TREE_STORE(shell->info_tree->model), item->iter, + INFO_TREE_COL_PBUF, pixbuf, -1); + } else { + GList *children = gtk_container_get_children(GTK_CONTAINER(item->widget)); + gtk_image_set_from_pixbuf(GTK_IMAGE(children->data), pixbuf); + gtk_widget_show(GTK_WIDGET(children->data)); + g_list_free(children); + } + } + } else if (g_str_equal(key, "Zebra")) { #if GTK_CHECK_VERSION(3, 0, 0) #else - gtk_tree_view_set_rules_hint(GTK_TREE_VIEW - (shell->info->view), - g_key_file_get_boolean - (key_file, group, key, NULL)); + gtk_tree_view_set_rules_hint( + GTK_TREE_VIEW(shell->info_tree->view), + g_key_file_get_boolean(key_file, group, key, NULL)); #endif - } - } - - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(shell->info->view), headers_visible); - } else { - g_warning("Unknown parameter group: ``%s''", group); + } } + + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(shell->info_tree->view), + headers_visible); } -static void -group_handle_normal(GKeyFile * key_file, ShellModuleEntry * entry, - gchar * group, gchar ** keys, gsize ngroups) +static void group_handle_normal(GKeyFile *key_file, + ShellModuleEntry *entry, + const gchar *group, + gchar **keys, + gsize ngroups) { GtkTreeIter parent; - GtkTreeStore *store = GTK_TREE_STORE(shell->info->model); - gchar *tmp = g_strdup(group); + GtkTreeStore *store = GTK_TREE_STORE(shell->info_tree->model); gint i; if (ngroups > 1) { - gtk_tree_store_append(store, &parent, NULL); + gtk_tree_store_append(store, &parent, NULL); - strend(tmp, '#'); - gtk_tree_store_set(store, &parent, INFO_TREE_COL_NAME, tmp, -1); - g_free(tmp); - } - - for (i = 0; keys[i]; i++) { - gchar *key = keys[i]; - gchar *value; - GtkTreeIter child; - - value = g_key_file_get_value(key_file, group, key, NULL); - if (entry->fieldfunc && value && g_str_equal(value, "...")) { - g_free(value); - value = entry->fieldfunc(key); + gchar *tmp = g_strdup(group); + strend(tmp, '#'); + gtk_tree_store_set(store, &parent, INFO_TREE_COL_NAME, tmp, -1); + g_free(tmp); } - if ((key && value) && g_utf8_validate(key, -1, NULL) && g_utf8_validate(value, -1, NULL)) { - if (ngroups == 1) { - gtk_tree_store_append(store, &child, NULL); - } else { - gtk_tree_store_append(store, &child, &parent); - } - - /* FIXME: use g_key_file_get_string_list? */ - if (g_utf8_strchr(value, -1, '|')) { - gchar **columns = g_strsplit(value, "|", 0); - - gtk_tree_store_set(store, &child, INFO_TREE_COL_VALUE, columns[0], -1); - if (columns[1]) { - gtk_tree_store_set(store, &child, INFO_TREE_COL_EXTRA1, columns[1], -1); - if (columns[2]) { - gtk_tree_store_set(store, &child, INFO_TREE_COL_EXTRA2, columns[2], -1); - } - } - - g_strfreev(columns); - } else { - gtk_tree_store_set(store, &child, INFO_TREE_COL_VALUE, value, -1); - } - - strend(key, '#'); - - if (*key == '$') { - gchar **tmp; - - tmp = g_strsplit(++key, "$", 0); - - gtk_tree_store_set(store, &child, INFO_TREE_COL_NAME, - tmp[1], INFO_TREE_COL_DATA, tmp[0], -1); - - g_strfreev(tmp); - } else { - gtk_tree_store_set(store, &child, INFO_TREE_COL_NAME, _(key), - INFO_TREE_COL_DATA, NULL, -1); - } - - g_hash_table_insert(update_tbl, g_strdup(key), - gtk_tree_iter_copy(&child)); - - } - - g_free(value); - } -} - -static void -moreinfo_handle_normal(GKeyFile * key_file, gchar * group, gchar ** keys) -{ - GtkTreeIter parent; - GtkTreeStore *store = GTK_TREE_STORE(shell->moreinfo->model); - gint i; - - gtk_tree_store_append(store, &parent, NULL); - gtk_tree_store_set(store, &parent, INFO_TREE_COL_NAME, group, -1); + g_key_file_set_list_separator(key_file, '|'); for (i = 0; keys[i]; i++) { - gchar *key = keys[i]; - GtkTreeIter child; - gchar *value; + gchar *key = keys[i]; + gchar **values; + gsize vcount = 0; + GtkTreeIter child; + + values = g_key_file_get_string_list(key_file, group, key, &vcount, NULL); + if (!vcount) { + /* Check for empty value */ + values = g_new0(gchar*, 2); + values[0] = g_key_file_get_string(key_file, group, key, NULL); + if (values[0]) { + vcount = 1; + } else { + g_strfreev(values); + continue; + } + } - value = g_key_file_get_value(key_file, group, key, NULL); + if (entry->fieldfunc && values[0] && g_str_equal(values[0], "...")) { + g_free(values[0]); + values[0] = entry->fieldfunc(key); + } - if (g_utf8_validate(key, -1, NULL) - && g_utf8_validate(value, -1, NULL)) { - strend(key, '#'); + if (ngroups == 1) { + gtk_tree_store_append(store, &child, NULL); + } else { + gtk_tree_store_append(store, &child, &parent); + } - gtk_tree_store_append(store, &child, &parent); - gtk_tree_store_set(store, &child, INFO_TREE_COL_VALUE, - value, INFO_TREE_COL_NAME, key, -1); - } + if (vcount > 0) + gtk_tree_store_set(store, &child, INFO_TREE_COL_VALUE, + values[0], -1); + if (vcount > 1) + gtk_tree_store_set(store, &child, INFO_TREE_COL_EXTRA1, + values[1], -1); + if (vcount > 2) + gtk_tree_store_set(store, &child, INFO_TREE_COL_EXTRA2, + values[2], -1); + + struct UpdateTableItem *item = g_new0(struct UpdateTableItem, 1); + item->is_iter = TRUE; + item->iter = gtk_tree_iter_copy(&child); + gchar *flags, *tag, *name, *label; + key_get_components(key, &flags, &tag, &name, &label, NULL, TRUE); + + if (flags) { + //TODO: name was formerly used where label is here. Check all uses + //for problems. + gtk_tree_store_set(store, &child, INFO_TREE_COL_NAME, label, + INFO_TREE_COL_DATA, flags, -1); + g_hash_table_insert(update_tbl, tag, item); + g_free(label); + } else { + gtk_tree_store_set(store, &child, INFO_TREE_COL_NAME, key, + INFO_TREE_COL_DATA, NULL, -1); + g_hash_table_insert(update_tbl, name, item); + g_free(tag); + } + g_free(flags); - g_free(value); + g_strfreev(values); } } static void update_progress() { - GtkTreeModel *model = shell->info->model; + GtkTreeModel *model = shell->info_tree->model; GtkTreeStore *store = GTK_TREE_STORE(model); GtkTreeIter iter, fiter; gchar *tmp; @@ -1354,13 +1445,13 @@ static void update_progress() } while (gtk_tree_model_iter_next(model, &iter)); /* now sort everything up. that wasn't as hard as i thought :) */ - GtkTreeSortable *sortable = GTK_TREE_SORTABLE(shell->info->model); + GtkTreeSortable *sortable = GTK_TREE_SORTABLE(shell->info_tree->model); gtk_tree_sortable_set_sort_func(sortable, INFO_TREE_COL_VALUE, info_tree_compare_val_func, 0, NULL); gtk_tree_sortable_set_sort_column_id(sortable, INFO_TREE_COL_VALUE, GTK_SORT_DESCENDING); - gtk_tree_view_set_model(GTK_TREE_VIEW(shell->info->view), + gtk_tree_view_set_model(GTK_TREE_VIEW(shell->info_tree->view), GTK_TREE_MODEL(sortable)); } @@ -1404,133 +1495,290 @@ select_first_item(gpointer data) { GtkTreeIter first; - if (gtk_tree_model_get_iter_first(shell->info->model, &first)) - gtk_tree_selection_select_iter(shell->info->selection, &first); + if (gtk_tree_model_get_iter_first(shell->info_tree->model, &first)) + gtk_tree_selection_select_iter(shell->info_tree->selection, &first); return FALSE; } -static gboolean -select_marked_or_first_item(gpointer data) +static gboolean select_marked_or_first_item(gpointer data) { GtkTreeIter first, it; gboolean found_selection = FALSE; gchar *datacol; - if ( gtk_tree_model_get_iter_first(shell->info->model, &first) ) { + if (gtk_tree_model_get_iter_first(shell->info_tree->model, &first)) { it = first; - while ( gtk_tree_model_iter_next(shell->info->model, &it) ) { - gtk_tree_model_get(shell->info->model, &it, INFO_TREE_COL_DATA, &datacol, -1); - if (datacol != NULL && *datacol == '*') { - gtk_tree_selection_select_iter(shell->info->selection, &it); + while (gtk_tree_model_iter_next(shell->info_tree->model, &it)) { + gtk_tree_model_get(shell->info_tree->model, &it, INFO_TREE_COL_DATA, + &datacol, -1); + if (key_is_highlighted(datacol)) { + gtk_tree_selection_select_iter(shell->info_tree->selection, + &it); found_selection = TRUE; } g_free(datacol); } if (!found_selection) - gtk_tree_selection_select_iter(shell->info->selection, &first); + gtk_tree_selection_select_iter(shell->info_tree->selection, &first); } return FALSE; } -static void -module_selected_show_info(ShellModuleEntry * entry, gboolean reload) +static void module_selected_show_info_list(GKeyFile *key_file, + ShellModuleEntry *entry, + gchar **groups, + gsize ngroups) { - GKeyFile *key_file = g_key_file_new(); - GtkTreeStore *store; - gchar *key_data, **groups; - gboolean has_shell_param = FALSE; + GtkTreeStore *store = GTK_TREE_STORE(shell->info_tree->model); gint i; - gsize ngroups; -#if GTK_CHECK_VERSION(2, 14, 0) - GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(shell->info->view)); -#endif - module_entry_scan(entry); - key_data = module_entry_function(entry); + gtk_tree_store_clear(store); - /* */ -#if GTK_CHECK_VERSION(2, 14, 0) - gdk_window_freeze_updates(gdk_window); -#else - gdk_window_freeze_updates(shell->info->view->window); -#endif + g_object_ref(shell->info_tree->model); + gtk_tree_view_set_model(GTK_TREE_VIEW(shell->info_tree->view), NULL); - g_object_ref(shell->info->model); - gtk_tree_view_set_model(GTK_TREE_VIEW(shell->info->view), NULL); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(shell->info_tree->view), + FALSE); - /* reset the view type to normal */ - set_view_type(SHELL_VIEW_NORMAL, reload); + for (i = 0; groups[i]; i++) { + gchar **keys = g_key_file_get_keys(key_file, groups[i], NULL, NULL); - if (!reload) { - /* recreate the iter hash table */ - h_hash_table_remove_all(update_tbl); + if (groups[i][0] == '$') { + group_handle_special(key_file, entry, groups[i], keys); + } else { + group_handle_normal(key_file, entry, groups[i], keys, ngroups); + } + + g_strfreev(keys); } - shell_clear_field_updates(); + g_object_unref(shell->info_tree->model); + gtk_tree_view_set_model(GTK_TREE_VIEW(shell->info_tree->view), + shell->info_tree->model); + gtk_tree_view_expand_all(GTK_TREE_VIEW(shell->info_tree->view)); + gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(shell->info_tree->view), + ngroups > 1); +} - store = GTK_TREE_STORE(shell->info->model); +static gboolean detail_activate_link (GtkLabel *label, gchar *uri, gpointer user_data) { + return uri_open(uri); +} - gtk_tree_store_clear(store); +static gchar *vendor_info_markup(const Vendor *v) { + if (!v) return NULL; + gchar *ven_mt = NULL; + gchar *full_link = NULL, *p = NULL; + gchar *ven_tag = v->name_short ? g_strdup(v->name_short) : g_strdup(v->name); + tag_vendor(&ven_tag, 0, ven_tag, v->ansi_color, FMT_OPT_PANGO); + //if (v->name_short) + // ven_mt = appf(ven_mt, "\n", "%s", v->name); + ven_mt = appf(ven_mt, "\n", "%s", ven_tag); + if (v->url) { + if (!g_str_has_prefix(v->url, "http") ) + full_link = g_strdup_printf("http://%s", v->url); + ven_mt = appf(ven_mt, "\n", "<b>%s:</b> <a href=\"%s\">%s</a>", _("URL"), full_link ? full_link : v->url, v->url); + g_free(full_link); + full_link = NULL; + } + if (v->url_support) { + if (!g_str_has_prefix(v->url_support, "http") ) + full_link = g_strdup_printf("http://%s", v->url_support); + ven_mt = appf(ven_mt, "\n", "<b>%s:</b> <a href=\"%s\">%s</a>", _("Support URL"), full_link ? full_link : v->url_support, v->url_support); + g_free(full_link); + full_link = NULL; + } + if (v->wikipedia) { + /* sending the title to wikipedia.com/wiki will autmatically handle the language and section parts, + * but perhaps that shouldn't be relied on so much? */ + full_link = g_strdup_printf("http://wikipedia.com/wiki/%s", v->wikipedia); + for(p = full_link; *p; p++) { + if (*p == ' ') *p = '_'; + } + ven_mt = appf(ven_mt, "\n", "<b>%s:</b> <a href=\"%s\">%s</a>", _("Wikipedia"), full_link ? full_link : v->wikipedia, v->wikipedia); + g_free(full_link); + full_link = NULL; + } + g_free(ven_tag); + return ven_mt; +} - g_key_file_load_from_data(key_file, key_data, strlen(key_data), 0, - NULL); - groups = g_key_file_get_groups(key_file, &ngroups); +static void module_selected_show_info_detail(GKeyFile *key_file, + ShellModuleEntry *entry, + gchar **groups) +{ + gint i; - for (i = 0; groups[i]; i++) - if (groups[i][0] == '$') - ngroups--; + detail_view_clear(shell->detail_view); for (i = 0; groups[i]; i++) { - gchar *group = groups[i]; - gchar **keys = g_key_file_get_keys(key_file, group, NULL, NULL); + gsize nkeys; + gchar **keys = g_key_file_get_keys(key_file, groups[i], &nkeys, NULL); + gchar *group_label = g_strdup(groups[i]); + strend(group_label, '#'); - if (*group == '$') { - group_handle_special(key_file, entry, group, keys, reload); - has_shell_param = TRUE; - } else { - group_handle_normal(key_file, entry, group, keys, ngroups); - } + if (entry && groups[i][0] == '$') { + group_handle_special(key_file, entry, groups[i], keys); + } else { + gchar *tmp = g_strdup_printf("<b>%s</b>", group_label); + GtkWidget *label = gtk_label_new(tmp); + gtk_label_set_use_markup(GTK_LABEL(label), TRUE); + GtkWidget *frame = gtk_frame_new(NULL); + gtk_frame_set_label_widget(GTK_FRAME(frame), label); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE); + g_free(tmp); + + gtk_container_set_border_width(GTK_CONTAINER(frame), 6); + gtk_box_pack_start(GTK_BOX(shell->detail_view->view), frame, FALSE, + FALSE, 0); + + GtkWidget *table = gtk_table_new(nkeys, 2, FALSE); + gtk_container_set_border_width(GTK_CONTAINER(table), 4); + gtk_container_add(GTK_CONTAINER(frame), table); + + gint j, a = 0; + for (j = 0; keys[j]; j++) { + gchar *key_markup; + gchar *value; + gchar *name, *label, *tag, *flags; + key_get_components(keys[j], &flags, &tag, &name, &label, NULL, TRUE); + + value = g_key_file_get_string(key_file, groups[i], keys[j], NULL); + + if (entry && entry->fieldfunc && value && g_str_equal(value, "...")) { + g_free(value); + value = entry->fieldfunc(keys[j]); + } + + gboolean has_ven = key_value_has_vendor_string(flags); + const Vendor *v = has_ven ? vendor_match(value, NULL) : NULL; + + key_markup = + g_strdup_printf("<span color=\"#666\">%s</span>", label); + + GtkWidget *key_label = gtk_label_new(key_markup); + gtk_label_set_use_markup(GTK_LABEL(key_label), TRUE); + gtk_misc_set_alignment(GTK_MISC(key_label), 1.0f, 0.5f); - g_strfreev(keys); + GtkWidget *value_label = gtk_label_new(value); + gtk_label_set_use_markup(GTK_LABEL(value_label), TRUE); + gtk_label_set_selectable(GTK_LABEL(value_label), TRUE); +#if !GTK_CHECK_VERSION(3, 0, 0) + gtk_label_set_line_wrap(GTK_LABEL(value_label), TRUE); +#endif + gtk_misc_set_alignment(GTK_MISC(value_label), 0.0f, 0.5f); + + GtkWidget *value_icon = gtk_image_new(); + + GtkWidget *value_box = gtk_hbox_new(FALSE, 4); + gtk_box_pack_start(GTK_BOX(value_box), value_icon, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(value_box), value_label, TRUE, TRUE, 0); + + g_signal_connect(key_label, "activate-link", G_CALLBACK(detail_activate_link), NULL); + g_signal_connect(value_label, "activate-link", G_CALLBACK(detail_activate_link), NULL); + + gtk_widget_show(key_label); + gtk_widget_show(value_box); + gtk_widget_show(value_label); + + gtk_table_attach(GTK_TABLE(table), key_label, 0, 1, j + a, j + a + 1, + GTK_FILL, GTK_FILL, 6, 4); + gtk_table_attach(GTK_TABLE(table), value_box, 1, 2, j + a, j + a + 1, + GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 4); + + if (v) { + a++; /* insert a row */ + gchar *vendor_markup = vendor_info_markup(v); + GtkWidget *vendor_label = gtk_label_new(vendor_markup); + gtk_label_set_use_markup(GTK_LABEL(vendor_label), TRUE); + gtk_label_set_selectable(GTK_LABEL(vendor_label), TRUE); + gtk_misc_set_alignment(GTK_MISC(vendor_label), 0.0f, 0.5f); + g_signal_connect(vendor_label, "activate-link", G_CALLBACK(detail_activate_link), NULL); + GtkWidget *vendor_box = gtk_hbox_new(FALSE, 4); + gtk_box_pack_start(GTK_BOX(vendor_box), vendor_label, TRUE, TRUE, 0); + gtk_table_attach(GTK_TABLE(table), vendor_box, 1, 2, j + a, j + a + 1, + GTK_FILL | GTK_EXPAND, GTK_FILL, 0, 4); + gtk_widget_show(vendor_box); + gtk_widget_show(vendor_label); + g_free(vendor_markup); + } + + struct UpdateTableItem *item = g_new0(struct UpdateTableItem, 1); + item->is_iter = FALSE; + item->widget = g_object_ref(value_box); + + if (tag) { + g_hash_table_insert(update_tbl, tag, item); + g_free(name); + } else { + g_hash_table_insert(update_tbl, name, item); + g_free(tag); + } + + g_free(flags); + g_free(value); + g_free(key_markup); + g_free(label); + } + + gtk_widget_show(table); + gtk_widget_show(label); + gtk_widget_show(frame); + } + + g_strfreev(keys); + g_free(group_label); } +} - /* */ - if (!has_shell_param) { - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(shell->info->view), FALSE); +static void +module_selected_show_info(ShellModuleEntry *entry, gboolean reload) +{ + GdkWindow *gdk_window = gtk_widget_get_window(GTK_WIDGET(shell->info_tree->view)); + gsize ngroups; + gint i; + + gdk_window_freeze_updates(gdk_window); + + module_entry_scan(entry); + if (!reload) { + /* recreate the iter hash table */ + h_hash_table_remove_all(update_tbl); } + shell_clear_field_updates(); - /* */ - g_object_unref(shell->info->model); - gtk_tree_view_set_model(GTK_TREE_VIEW(shell->info->view), shell->info->model); - gtk_tree_view_expand_all(GTK_TREE_VIEW(shell->info->view)); + GKeyFile *key_file = g_key_file_new(); + gchar *key_data = module_entry_function(entry); -#if GTK_CHECK_VERSION(2, 14, 0) - gdk_window_thaw_updates(gdk_window); -#else - gdk_window_thaw_updates(shell->info->view->window); -#endif - shell_set_note_from_entry(entry); + g_key_file_load_from_data(key_file, key_data, strlen(key_data), 0, NULL); + set_view_type(g_key_file_get_integer(key_file, "$ShellParam$", + "ViewType", NULL), reload); - if (shell->view_type == SHELL_VIEW_PROGRESS || shell->view_type == SHELL_VIEW_PROGRESS_DUAL) { - update_progress(); + gchar **groups = g_key_file_get_groups(key_file, &ngroups); + + for (i = 0; groups[i]; i++) { + if (groups[i][0] == '$') + ngroups--; } -#if GTK_CHECK_VERSION(2,12,0) - if (ngroups == 1) { - gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(shell->info->view), - FALSE); + if (shell->view_type == SHELL_VIEW_DETAIL) { + module_selected_show_info_detail(key_file, entry, groups); } else { - gtk_tree_view_set_show_expanders(GTK_TREE_VIEW(shell->info->view), - TRUE); + module_selected_show_info_list(key_file, entry, groups, ngroups); } -#endif g_strfreev(groups); g_key_file_free(key_file); g_free(key_data); + switch (shell->view_type) { + case SHELL_VIEW_PROGRESS_DUAL: + case SHELL_VIEW_PROGRESS: + update_progress(); + break; + } + if (!reload) { switch (shell->view_type) { case SHELL_VIEW_DUAL: @@ -1539,48 +1787,31 @@ module_selected_show_info(ShellModuleEntry * entry, gboolean reload) g_idle_add(select_marked_or_first_item, NULL); } } + shell_set_note_from_entry(entry); + + gdk_window_thaw_updates(gdk_window); } -static void info_selected_show_extra(gchar * data) +static void info_selected_show_extra(const gchar *tag) { - GtkTreeStore *store; + if (!tag || !shell->selected->morefunc) + return; - store = GTK_TREE_STORE(shell->moreinfo->model); - gtk_tree_store_clear(store); + GKeyFile *key_file = g_key_file_new(); + gchar *key_data = shell->selected->morefunc((gchar *)tag); + gchar **groups; - if (!shell->selected->morefunc) - return; + g_key_file_load_from_data(key_file, key_data, strlen(key_data), 0, NULL); + groups = g_key_file_get_groups(key_file, NULL); - if (data) { - /* skip the select marker */ - if (*data == '*') - data++; - GKeyFile *key_file = g_key_file_new(); - gchar *key_data = shell->selected->morefunc(data); - gchar **groups; - gint i; - - g_key_file_load_from_data(key_file, key_data, strlen(key_data), 0, - NULL); - groups = g_key_file_get_groups(key_file, NULL); - - for (i = 0; groups[i]; i++) { - gchar *group = groups[i]; - gchar **keys = - g_key_file_get_keys(key_file, group, NULL, NULL); - - moreinfo_handle_normal(key_file, group, keys); - } + module_selected_show_info_detail(key_file, NULL, groups); - gtk_tree_view_expand_all(GTK_TREE_VIEW(shell->moreinfo->view)); - - g_strfreev(groups); - g_key_file_free(key_file); - g_free(key_data); - } + g_strfreev(groups); + g_key_file_free(key_file); + g_free(key_data); } -static gchar *shell_summary_clear_value(gchar *value) +static gchar *detail_view_clear_value(gchar *value) { GKeyFile *keyfile; gchar *return_value; @@ -1630,83 +1861,66 @@ static gchar *shell_summary_clear_value(gchar *value) return g_strstrip(return_value); } -static void shell_summary_add_item(ShellSummary *summary, - gchar *icon, - gchar *name, - gchar *value) +static void detail_view_add_item(DetailView *detail_view, + gchar *icon, + gchar *name, + gchar *value) { - GtkWidget *frame; - GtkWidget *frame_label_box; - GtkWidget *frame_image; - GtkWidget *frame_label; - GtkWidget *content; - GtkWidget *alignment; - gchar *temp; + GtkWidget *frame; + GtkWidget *frame_label_box; + GtkWidget *frame_image; + GtkWidget *frame_label; + GtkWidget *content; + GtkWidget *alignment; + gchar *temp; - temp = shell_summary_clear_value(value); + temp = detail_view_clear_value(value); - /* creates the frame */ - frame = gtk_frame_new(NULL); - gtk_frame_set_shadow_type(GTK_FRAME(frame), - GTK_SHADOW_NONE); + /* creates the frame */ + frame = gtk_frame_new(NULL); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_NONE); #if GTK_CHECK_VERSION(3, 0, 0) - frame_label_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + frame_label_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); #else - frame_label_box = gtk_hbox_new(FALSE, 5); + frame_label_box = gtk_hbox_new(FALSE, 5); #endif - frame_image = icon_cache_get_image(icon); - frame_label = gtk_label_new(name); - gtk_label_set_use_markup(GTK_LABEL(frame_label), TRUE); - gtk_box_pack_start(GTK_BOX(frame_label_box), frame_image, FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(frame_label_box), frame_label, FALSE, FALSE, 0); - - content = gtk_label_new(temp); - /* TODO:GTK3 gtk_alignment_new(), etc is deprecated from 3.14 */ + frame_image = icon_cache_get_image(icon); + frame_label = gtk_label_new(name); + gtk_label_set_use_markup(GTK_LABEL(frame_label), TRUE); + gtk_box_pack_start(GTK_BOX(frame_label_box), frame_image, FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(frame_label_box), frame_label, FALSE, FALSE, 0); + + content = gtk_label_new(temp); + /* TODO:GTK3 gtk_alignment_new(), etc is deprecated from 3.14 */ #if GTK_CHECK_VERSION(3, 0, 0) - GtkWidget *frame_box; - frame_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); - gtk_widget_set_margin_start(GTK_WIDGET(frame_box), 48); - gtk_box_pack_start(GTK_BOX(frame_box), content, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(frame), frame_box); + GtkWidget *frame_box; + frame_box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 5); + gtk_widget_set_margin_start(GTK_WIDGET(frame_box), 48); + gtk_box_pack_start(GTK_BOX(frame_box), content, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(frame), frame_box); #else - alignment = gtk_alignment_new(0.5, 0.5, 1, 1); - gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 48, 0); - gtk_widget_show(alignment); - gtk_container_add(GTK_CONTAINER(frame), alignment); - gtk_misc_set_alignment(GTK_MISC(content), 0.0, 0.5); - gtk_container_add(GTK_CONTAINER(alignment), content); + alignment = gtk_alignment_new(0.5, 0.5, 1, 1); + gtk_alignment_set_padding(GTK_ALIGNMENT(alignment), 0, 0, 48, 0); + gtk_widget_show(alignment); + gtk_container_add(GTK_CONTAINER(frame), alignment); + gtk_misc_set_alignment(GTK_MISC(content), 0.0, 0.5); + gtk_container_add(GTK_CONTAINER(alignment), content); #endif - gtk_widget_show_all(frame); - gtk_widget_show_all(frame_label_box); - - gtk_frame_set_label_widget(GTK_FRAME(frame), frame_label_box); + gtk_widget_show_all(frame); + gtk_widget_show_all(frame_label_box); - /* pack the item on the summary screen */ - gtk_box_pack_start(GTK_BOX(shell->summary->view), frame, FALSE, FALSE, 4); + gtk_frame_set_label_widget(GTK_FRAME(frame), frame_label_box); - /* add the item to the list of summary items */ - summary->items = g_slist_prepend(summary->items, frame); + /* pack the item on the detail_view screen */ + gtk_box_pack_start(GTK_BOX(shell->detail_view->view), frame, FALSE, FALSE, + 4); - g_free(temp); + g_free(temp); } -static void shell_summary_clear(ShellSummary *summary) -{ - GSList *item; - - for (item = summary->items; item; item = item->next) { - gtk_widget_destroy(GTK_WIDGET(item->data)); - } - - g_slist_free(summary->items); - summary->items = NULL; - - if (summary->header) gtk_widget_destroy(summary->header); - summary->header = NULL; -} -static void shell_summary_create_header(ShellSummary *summary, +static void detail_view_create_header(DetailView *detail_view, gchar *title) { GtkWidget *header, *label; @@ -1721,27 +1935,25 @@ static void shell_summary_create_header(ShellSummary *summary, label = gtk_bin_get_child(GTK_BIN(header)); gtk_label_set_use_markup(GTK_LABEL(label), TRUE); - gtk_box_pack_start(GTK_BOX(shell->summary->view), header, FALSE, FALSE, 4); - - summary->header = header; + gtk_box_pack_start(GTK_BOX(shell->detail_view->view), header, FALSE, FALSE, 4); g_free(temp); } -static void shell_show_summary(void) +static void shell_show_detail_view(void) { GKeyFile *keyfile; - gchar *summary; + gchar *detail; - set_view_type(SHELL_VIEW_SUMMARY, FALSE); - shell_summary_clear(shell->summary); - shell_summary_create_header(shell->summary, shell->selected_module->name); + set_view_type(SHELL_VIEW_DETAIL, FALSE); + detail_view_clear(shell->detail_view); + detail_view_create_header(shell->detail_view, shell->selected_module->name); keyfile = g_key_file_new(); - summary = shell->selected_module->summaryfunc(); + detail = shell->selected_module->summaryfunc(); - if (g_key_file_load_from_data(keyfile, summary, - strlen(summary), 0, NULL)) { + if (g_key_file_load_from_data(keyfile, detail, + strlen(detail), 0, NULL)) { gchar **groups; gint group; @@ -1760,7 +1972,7 @@ static void shell_show_summary(void) method_result = g_strdup("N/A"); } - shell_summary_add_item(shell->summary, + detail_view_add_item(shell->detail_view, icon, groups[group], method_result); shell_status_pulse(); @@ -1771,11 +1983,11 @@ static void shell_show_summary(void) g_strfreev(groups); } else { - DEBUG("error while parsing summary"); + DEBUG("error while parsing detail_view"); set_view_type(SHELL_VIEW_NORMAL, FALSE); } - g_free(summary); + g_free(detail); g_key_file_free(keyfile); shell_view_set_enabled(TRUE); @@ -1789,76 +2001,77 @@ static void module_selected(gpointer data) ShellModuleEntry *entry; static ShellModuleEntry *current = NULL; static gboolean updating = FALSE; - GtkScrollbar *hscrollbar, *vscrollbar; + GtkScrollbar *hscrollbar, *vscrollbar; - /* Gets the currently selected item on the left-side TreeView; if there is no - selection, silently return */ + /* Gets the currently selected item on the left-side TreeView; if there is + no selection, silently return */ if (!gtk_tree_selection_get_selected(shelltree->selection, &model, &iter)) { - return; + return; } - /* Mark the currently selected module as "unselected"; this is used to kill the - update timeout. */ + /* Mark the currently selected module as "unselected"; this is used to kill + the update timeout. */ if (current) { - current->selected = FALSE; + current->selected = FALSE; } if (updating) { - return; + return; } else { - updating = TRUE; + updating = TRUE; } if (!gtk_tree_model_iter_parent(model, &parent, &iter)) { memcpy(&parent, &iter, sizeof(iter)); } - gtk_tree_model_get(model, &parent, TREE_COL_MODULE, &shell->selected_module, -1); + gtk_tree_model_get(model, &parent, TREE_COL_MODULE, &shell->selected_module, + -1); /* Get the current selection and shows its related info */ gtk_tree_model_get(model, &iter, TREE_COL_MODULE_ENTRY, &entry, -1); if (entry && !entry->selected) { - gchar *title; + gchar *title; - shell_status_set_enabled(TRUE); - shell_status_update(_("Updating...")); + shell_status_set_enabled(TRUE); + shell_status_update(_("Updating...")); - entry->selected = TRUE; - shell->selected = entry; - module_selected_show_info(entry, FALSE); + entry->selected = TRUE; + shell->selected = entry; + module_selected_show_info(entry, FALSE); - info_selected_show_extra(NULL); /* clears the more info store */ - gtk_tree_view_columns_autosize(GTK_TREE_VIEW(shell->info->view)); + gtk_tree_view_columns_autosize(GTK_TREE_VIEW(shell->info_tree->view)); - /* urgh. why don't GTK do this when the model is cleared? */ + /* urgh. why don't GTK do this when the model is cleared? */ #if GTK_CHECK_VERSION(3, 0, 0) - /* TODO:GTK3 */ + /* TODO:GTK3 */ #else - RANGE_SET_VALUE(info, vscrollbar, 0.0); - RANGE_SET_VALUE(info, hscrollbar, 0.0); - RANGE_SET_VALUE(moreinfo, vscrollbar, 0.0); - RANGE_SET_VALUE(moreinfo, hscrollbar, 0.0); + RANGE_SET_VALUE(info_tree, vscrollbar, 0.0); + RANGE_SET_VALUE(info_tree, hscrollbar, 0.0); + RANGE_SET_VALUE(detail_view, vscrollbar, 0.0); + RANGE_SET_VALUE(detail_view, hscrollbar, 0.0); #endif - title = g_strdup_printf("%s - %s", shell->selected_module->name, entry->name); - shell_set_title(shell, title); - g_free(title); + title = g_strdup_printf("%s - %s", shell->selected_module->name, + entry->name); + shell_set_title(shell, title); + g_free(title); - shell_action_set_enabled("RefreshAction", TRUE); - shell_action_set_enabled("CopyAction", TRUE); + shell_action_set_enabled("RefreshAction", TRUE); + shell_action_set_enabled("CopyAction", TRUE); - shell_status_update(_("Done.")); - shell_status_set_enabled(FALSE); + shell_status_update(_("Done.")); + shell_status_set_enabled(FALSE); } else { - shell_set_title(shell, NULL); - shell_action_set_enabled("RefreshAction", FALSE); - shell_action_set_enabled("CopyAction", FALSE); + shell_set_title(shell, NULL); + shell_action_set_enabled("RefreshAction", FALSE); + shell_action_set_enabled("CopyAction", FALSE); - gtk_tree_store_clear(GTK_TREE_STORE(shell->info->model)); - set_view_type(SHELL_VIEW_NORMAL, FALSE); + gtk_tree_store_clear(GTK_TREE_STORE(shell->info_tree->model)); + set_view_type(SHELL_VIEW_NORMAL, FALSE); if (shell->selected_module->summaryfunc) { - shell_show_summary(); + shell_show_detail_view(); } } @@ -1871,7 +2084,7 @@ static void info_selected(GtkTreeSelection * ts, gpointer data) ShellInfoTree *info = (ShellInfoTree *) data; GtkTreeModel *model = GTK_TREE_MODEL(info->model); GtkTreeIter parent; - gchar *datacol; + gchar *datacol, *mi_tag; if (!gtk_tree_selection_get_selected(ts, &model, &parent)) return; @@ -1883,11 +2096,12 @@ static void info_selected(GtkTreeSelection * ts, gpointer data) } gtk_tree_model_get(model, &parent, INFO_TREE_COL_DATA, &datacol, -1); - info_selected_show_extra(datacol); - gtk_tree_view_columns_autosize(GTK_TREE_VIEW(shell->moreinfo->view)); + mi_tag = key_mi_tag(datacol); + info_selected_show_extra(mi_tag); + g_free(mi_tag); } -static ShellInfoTree *info_tree_new(gboolean extra) +static ShellInfoTree *info_tree_new(void) { ShellInfoTree *info; GtkWidget *treeview, *scroll; @@ -1974,9 +2188,7 @@ static ShellInfoTree *info_tree_new(gboolean extra) sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)); - if (!extra) - g_signal_connect(G_OBJECT(sel), "changed", - (GCallback) info_selected, info); + g_signal_connect(G_OBJECT(sel), "changed", (GCallback)info_selected, info); gtk_container_add(GTK_CONTAINER(scroll), treeview); @@ -2049,3 +2261,138 @@ static ShellTree *tree_new() return shelltree; } + +gboolean key_is_flagged(const gchar *key) { + return (key && *key == '$' && strchr(key+1, '$')) ? TRUE : FALSE; +} + +gboolean key_is_highlighted(const gchar *key) { + gchar *flags; + key_get_components(key, &flags, NULL, NULL, NULL, NULL, TRUE); + if (flags && strchr(flags, '*')) { + g_free(flags); + return TRUE; + } + return FALSE; +} + +gboolean key_wants_details(const gchar *key) { + gchar *flags; + key_get_components(key, &flags, NULL, NULL, NULL, NULL, TRUE); + if (flags && strchr(flags, '!')) { + g_free(flags); + return TRUE; + } + return FALSE; +} + +gboolean key_value_has_vendor_string(const gchar *key) { + gchar *flags; + key_get_components(key, &flags, NULL, NULL, NULL, NULL, TRUE); + if (flags && strchr(flags, '^')) { + g_free(flags); + return TRUE; + } + return FALSE; +} + +gboolean key_label_is_escaped(const gchar *key) { + gchar *flags; + key_get_components(key, &flags, NULL, NULL, NULL, NULL, TRUE); + if (flags && strchr(flags, '@')) { + g_free(flags); + return TRUE; + } + return FALSE; +} + +gchar *key_mi_tag(const gchar *key) { + static char flag_list[] = "*!^@"; + gchar *p = (gchar*)key, *l, *t; + + if (key_is_flagged(key)) { + l = strchr(key+1, '$'); + if (*p == '$') p++; /* skip first if exists */ + while(p < l && strchr(flag_list, *p)) { + p++; + } + if (strlen(p)) { + t = g_strdup(p); + *(strchr(t, '$')) = 0; + return t; + } + } + return NULL; +} + +const gchar *key_get_name(const gchar *key) { + if (key_is_flagged(key)) + return strchr(key+1, '$')+1; + return key; +} + +/* key syntax: + * [$[<flags>][<tag>]$]<name>[#[<dis>]] + * + * example for key = "$*!Foo$Bar#7": + * flags = "$*!^Foo$" // key_is/wants_*() still works on flags + * tag = "Foo" // the moreinfo/icon tag + * name = "Bar#7" // the full unique name + * label = "Bar" // the label displayed + * dis = "7" + */ +void key_get_components(const gchar *key, + gchar **flags, gchar **tag, gchar **name, gchar **label, gchar **dis, + gboolean null_empty) { + + if (null_empty) { +#define K_NULL_EMPTY(f) if (f) { *f = NULL; } + K_NULL_EMPTY(flags); + K_NULL_EMPTY(tag); + K_NULL_EMPTY(name); + K_NULL_EMPTY(label); + K_NULL_EMPTY(dis); + } + + if (!key || !*key) + return; + + const gchar *np = g_utf8_strchr(key+1, -1, '$') + 1; + if (*key == '$' && np) { + /* is flagged */ + gchar *f = g_strdup(key); + gchar *s = g_utf8_strchr(f+1, -1, '$'); + if(s==NULL) { + DEBUG("ERROR NOT FOUND"); + }else{ + /* if((s-f+1)>strlen(key)) { + DEBUG("ERROR TOO LATE"); + }else{*/ + *(g_utf8_strchr(f+1, -1, '$') + 1) = 0; + if (flags) + *flags = g_strdup(f); + if (tag) + *tag = key_mi_tag(f); + g_free(f); + //} + } + } else + np = key; + + if (name) + *name = g_strdup(np); + if (label) { + *label = g_strdup(np); + gchar *lbp = g_utf8_strchr(*label, -1, '#'); + if (lbp) + *lbp = 0; + if (lbp && dis) + *dis = g_strdup(lbp + 1); + + if (flags && *flags && strchr(*flags, '@')) { + gchar *ol = *label; + *label = g_strcompress(ol); + g_free(ol); + } + } +} diff --git a/shell/stock.c b/shell/stock.c index 86d66778..27b2eedb 100644 --- a/shell/stock.c +++ b/shell/stock.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -25,11 +25,13 @@ static struct { gchar *filename; gchar *stock_id; } stock_icons[] = { + { "clipboard.png", HI_STOCK_CLIPBOARD}, + { "refresh.png", HI_STOCK_REFRESH}, { "report.png", HI_STOCK_REPORT}, { "internet.png", HI_STOCK_INTERNET}, { "module.png", HI_STOCK_MODULE}, { "about-modules.png", HI_STOCK_ABOUT_MODULES}, - { "syncmanager-small.png", HI_STOCK_SYNC_MENU}, + { "server_sync.png", HI_STOCK_SYNC_MENU}, { "face-grin.png", HI_STOCK_DONATE}, { "server.png", HI_STOCK_SERVER}, }; @@ -38,8 +40,6 @@ static GtkIconFactory *icon_factory; void stock_icon_register(gchar * filename, gchar * stock_id) { -#if GTK_CHECK_VERSION(3, 0, 0) -#else GtkIconSet *icon_set; GtkIconSource *icon_source; @@ -54,13 +54,10 @@ void stock_icon_register(gchar * filename, gchar * stock_id) gtk_icon_factory_add(icon_factory, stock_id, icon_set); gtk_icon_set_unref(icon_set); -#endif } void stock_icon_register_pixbuf(GdkPixbuf * pixbuf, gchar * stock_id) { -#if GTK_CHECK_VERSION(3, 0, 0) -#else GtkIconSet *icon_set; GtkIconSource *icon_source; @@ -74,30 +71,23 @@ void stock_icon_register_pixbuf(GdkPixbuf * pixbuf, gchar * stock_id) gtk_icon_factory_add(icon_factory, stock_id, icon_set); gtk_icon_set_unref(icon_set); -#endif } void stock_icons_init(void) { - gint i; + guint i; guint n_stock_icons = G_N_ELEMENTS(stock_icons); DEBUG("initializing stock icons"); -#if GTK_CHECK_VERSION(3, 0, 0) -#else icon_factory = gtk_icon_factory_new(); -#endif for (i = 0; i < n_stock_icons; i++) { stock_icon_register(stock_icons[i].filename, stock_icons[i].stock_id); } -#if GTK_CHECK_VERSION(3, 0, 0) -#else gtk_icon_factory_add_default(icon_factory); -#endif g_object_unref(icon_factory); } diff --git a/shell/syncmanager.c b/shell/syncmanager.c index db94d474..0f08cf87 100644 --- a/shell/syncmanager.c +++ b/shell/syncmanager.c @@ -1,10 +1,10 @@ /* * HardInfo - Displays System Information - * Copyright (C) 2003-2009 Leandro A. F. Pereira <leandro@hardinfo.org> + * Copyright (C) 2003-2009 L. A. F. Pereira <l@tia.mat.br> * * 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. + * the Free Software Foundation, version 2 or later. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -16,17 +16,20 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "syncmanager.h" -#include "iconcache.h" -#include "hardinfo.h" #include "config.h" +#include "hardinfo.h" +#include "iconcache.h" +#include "syncmanager.h" -#ifdef HAS_LIBSOUP #include <libsoup/soup.h> #include <stdarg.h> #include <string.h> +#ifndef SOUP_CHECK_VERSION + #define SOUP_CHECK_VERSION(a,b,c) 0 +#endif + typedef struct _SyncDialog SyncDialog; typedef struct _SyncNetArea SyncNetArea; typedef struct _SyncNetAction SyncNetAction; @@ -36,9 +39,6 @@ struct _SyncNetArea { }; struct _SyncNetAction { - gchar *name; - gboolean(*do_action) (SyncDialog * sd, gpointer sna); - SyncEntry *entry; GError *error; }; @@ -50,12 +50,13 @@ struct _SyncDialog { GtkWidget *button_sync; GtkWidget *button_cancel; GtkWidget *button_close; + GtkWidget *button_priv_policy; GtkWidget *scroll_box; SyncNetArea *sna; - gboolean flag_cancel:1; + gboolean flag_cancel : 1; }; static GSList *entries = NULL; @@ -63,479 +64,385 @@ static SoupSession *session = NULL; static GMainLoop *loop; static GQuark err_quark; -#define XMLRPC_SERVER_URI "https://xmlrpc.hardinfo.org/" -#define XMLRPC_SERVER_API_VERSION 1 +//Note there are personal information involved and very old +//linux systems does not work with HTTPS so use HTTP for now +#define API_SERVER_URI "http://api.hardinfo2.org" -#define LABEL_SYNC_DEFAULT _("<big><b>Synchronize with Central Database</b></big>\n" \ - "The following information may be synchronized " \ - "with the HardInfo central database.") -#define LABEL_SYNC_SYNCING _("<big><b>Synchronizing</b></big>\n" \ - "This may take some time.") +#define LABEL_SYNC_DEFAULT \ + _("<big><b>Synchronize with Central Database</b></big>\n" \ + "The following information may be synchronized\n" \ + "with the HardInfo central database.") +#define LABEL_SYNC_SYNCING \ + _("<big><b>Synchronizing</b></big>\n" \ + "This may take some time.") static SyncDialog *sync_dialog_new(GtkWidget *parent); -static void sync_dialog_destroy(SyncDialog * sd); -static void sync_dialog_start_sync(SyncDialog * sd); +static void sync_dialog_destroy(SyncDialog *sd); +static void sync_dialog_start_sync(SyncDialog *sd); static SyncNetArea *sync_dialog_netarea_new(void); -static void sync_dialog_netarea_destroy(SyncNetArea * sna); -static void sync_dialog_netarea_show(SyncDialog * sd); +static void sync_dialog_netarea_destroy(SyncNetArea *sna); +static void sync_dialog_netarea_show(SyncDialog *sd); #if 0 static void sync_dialog_netarea_hide(SyncDialog * sd); #endif -static void sync_dialog_netarea_start_actions(SyncDialog * sd, - SyncNetAction * sna, gint n); - -#define SNA_ERROR(code,message,...) if (!sna->error) { \ - sna->error = g_error_new(err_quark, code, message, \ - ##__VA_ARGS__); \ - } -#endif /* HAS_LIBSOUP */ +static void +sync_dialog_netarea_start_actions(SyncDialog *sd, SyncNetAction *sna, gint n); +#define SNA_ERROR(code, message, ...) \ + if (!sna->error) { \ + sna->error = g_error_new(err_quark, code, message, ##__VA_ARGS__); \ + } gint sync_manager_count_entries(void) { -#ifdef HAS_LIBSOUP return g_slist_length(entries); -#else - return 0; -#endif } -void sync_manager_add_entry(SyncEntry * entry) +void sync_manager_add_entry(SyncEntry *entry) { -#ifdef HAS_LIBSOUP - DEBUG("registering syncmanager entry ''%s''", entry->fancy_name); + DEBUG("registering syncmanager entry ''%s''", entry->name); entry->selected = TRUE; entries = g_slist_append(entries, entry); -#else - DEBUG("libsoup support is disabled."); -#endif /* HAS_LIBSOUP */ } void sync_manager_clear_entries(void) { -#ifdef HAS_LIBSOUP DEBUG("clearing syncmanager entries"); g_slist_free(entries); entries = NULL; -#else - DEBUG("libsoup support is disabled."); -#endif /* HAS_LIBSOUP */ } void sync_manager_show(GtkWidget *parent) { -#ifndef HAS_LIBSOUP - g_warning - (_("HardInfo was compiled without libsoup support. (Network Updater requires it.)")); -#else /* !HAS_LIBSOUP */ SyncDialog *sd = sync_dialog_new(parent); err_quark = g_quark_from_static_string("syncmanager"); if (gtk_dialog_run(GTK_DIALOG(sd->dialog)) == GTK_RESPONSE_ACCEPT) { - shell_view_set_enabled(FALSE); - shell_status_set_enabled(TRUE); + shell_view_set_enabled(FALSE); + shell_status_set_enabled(TRUE); + shell_set_transient_dialog(GTK_WINDOW(sd->dialog)); - sync_dialog_start_sync(sd); + sync_dialog_start_sync(sd); - shell_status_set_enabled(FALSE); - shell_view_set_enabled(TRUE); + shell_set_transient_dialog(NULL); + shell_status_set_enabled(FALSE); + shell_view_set_enabled(TRUE); } sync_dialog_destroy(sd); -#endif /* HAS_LIBSOUP */ } -#ifdef HAS_LIBSOUP -static gint _soup_get_xmlrpc_value_int(SoupMessage * msg, - SyncNetAction * sna) +static gboolean _cancel_sync(GtkWidget *widget, gpointer data) { - gint int_value = -1; - - sna->error = NULL; - - if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) { - SNA_ERROR(1, _("%s (error #%d)"), msg->reason_phrase, - msg->status_code); - goto bad; - } - - GVariant *value = soup_xmlrpc_parse_response(msg->response_body->data, - msg->response_body->length, - "h", NULL); - if (!value) { - SNA_ERROR(2, _("Could not parse XML-RPC response")); - goto bad; - } - - int_value = g_variant_get_int32(value); - g_variant_unref(value); + SyncDialog *sd = (SyncDialog *)data; -bad: - return int_value; -} - -static gchar *_soup_get_xmlrpc_value_string(SoupMessage * msg, - SyncNetAction * sna) -{ - gchar *string = NULL; - - sna->error = NULL; - - if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) { - SNA_ERROR(1, _("%s (error #%d)"), msg->reason_phrase, - msg->status_code); - goto bad; - } - - GVariant *value = soup_xmlrpc_parse_response(msg->response_body->data, - msg->response_body->length, - "s", NULL); - if (!value) { - SNA_ERROR(2, _("Could not parse XML-RPC response")); - goto bad; + if (session) { + soup_session_abort(session); } - string = g_strdup(g_variant_get_string(value, NULL)); - g_variant_unref(value); - -bad: - return string; -} - -static gboolean _soup_xmlrpc_call(gchar * method, SyncNetAction * sna, - SoupSessionCallback callback) -{ - SoupMessage *msg; - - sna->error = NULL; - - msg = soup_xmlrpc_message_new(XMLRPC_SERVER_URI, method, NULL, NULL); - if (!msg) - return FALSE; - - DEBUG("calling xmlrpc method %s", method); + sd->flag_cancel = TRUE; + g_main_loop_quit(loop); - soup_session_queue_message(session, msg, callback, sna); - g_main_run(loop); + gtk_widget_set_sensitive(widget, FALSE); - return TRUE; + return FALSE; } -static gboolean _soup_xmlrpc_call_with_parameters(gchar * method, - SyncNetAction * sna, - SoupSessionCallback - callback, ...) +static SyncNetAction *sync_manager_get_selected_actions(gint *n) { - SoupMessage *msg; - GVariantBuilder builder; - GVariant *parameters; - gchar *argument, *body; - va_list ap; - - sna->error = NULL; - - msg = soup_message_new("POST", XMLRPC_SERVER_URI); - - DEBUG("calling xmlrpc method %s", method); - if (!msg) - return FALSE; - - g_variant_builder_init(&builder, G_VARIANT_TYPE_ARRAY); - va_start(ap, callback); - while ((argument = va_arg(ap, gchar *))) { - g_variant_builder_add(&builder, "s", argument); - DEBUG("with parameter: %s", argument); - } - va_end(ap); - parameters = g_variant_builder_end(&builder); - g_variant_builder_unref(&builder); + gint i; + GSList *entry; + SyncNetAction *actions; - body = soup_xmlrpc_build_request(method, parameters, NULL); - g_variant_unref(parameters); - if (body) { - soup_message_set_request(msg, "text/xml", - SOUP_MEMORY_TAKE, body, strlen(body)); + actions = g_new0(SyncNetAction, g_slist_length(entries)); - soup_session_queue_message(session, msg, callback, sna); - g_main_run(loop); + for (entry = entries, i = 0; entry; entry = entry->next) { + SyncEntry *e = (SyncEntry *)entry->data; - return TRUE; + if (e->selected) { + SyncNetAction sna = {.entry = e}; + actions[i++] = sna; + } } - return FALSE; + *n = i; + return actions; } -static void _action_check_api_version_got_response(SoupSession * session, - SoupMessage * msg, - gpointer user_data) +#if !SOUP_CHECK_VERSION(3,0,0) +static SoupURI *sync_manager_get_proxy(void) { - SyncNetAction *sna = (SyncNetAction *) user_data; - gint version = _soup_get_xmlrpc_value_int(msg, sna); + const gchar *conf; - if (version != XMLRPC_SERVER_API_VERSION) { - SNA_ERROR(5, _("Server says it supports API version %d, but " - "this version of HardInfo only supports API " - "version %d."), version, XMLRPC_SERVER_API_VERSION); + if (!(conf = g_getenv("HTTP_PROXY"))) { + if (!(conf = g_getenv("http_proxy"))) { + return NULL; + } } - g_main_quit(loop); -} - -static gboolean _action_check_api_version(SyncDialog * sd, - gpointer user_data) -{ - SyncNetAction *sna = (SyncNetAction *) user_data; - - if (!_soup_xmlrpc_call("server.getAPIVersion", sna, - _action_check_api_version_got_response)) - return FALSE; - - return sna->error ? FALSE : TRUE; + return soup_uri_new(conf); } +#endif -static void _action_call_function_got_response(SoupSession * session, - SoupMessage * msg, - gpointer user_data) +static void ensure_soup_session(void) { - SyncNetAction *sna = (SyncNetAction *) user_data; - gchar *string; - - if ((string = _soup_get_xmlrpc_value_string(msg, sna)) && - sna->entry->save_to) { - DEBUG("received string: %s\n", string); - gchar *filename = g_build_filename(g_get_home_dir(), ".hardinfo", - sna->entry->save_to, NULL); - - DEBUG("saving to %s", filename); - - g_file_set_contents(filename, string, -1, NULL); - g_free(filename); - } + if (!session) { +#if SOUP_CHECK_VERSION(3,0,0) + session = soup_session_new_with_options("timeout", 10, NULL); +#else +#if SOUP_CHECK_VERSION(2,42,0) + SoupURI *proxy = sync_manager_get_proxy(); - if (sna->entry->callback) { - sna->entry->callback(sna->entry, string); + session = soup_session_new_with_options( + SOUP_SESSION_TIMEOUT, 10, SOUP_SESSION_PROXY_URI, proxy, NULL); +#else + SoupURI *proxy = sync_manager_get_proxy(); + session = soup_session_async_new_with_options( + SOUP_SESSION_TIMEOUT, 10, SOUP_SESSION_PROXY_URI, proxy, NULL); +#endif +#endif } - - g_free(string); - g_main_quit(loop); } -static gboolean _action_call_function(SyncDialog * sd, gpointer user_data) +static void sync_dialog_start_sync(SyncDialog *sd) { - SyncNetAction *sna = (SyncNetAction *) user_data; - - if (sna->entry) { - gchar *str_data = NULL; - - if (sna->entry->get_data) - str_data = sna->entry->get_data(); + gint nactions; + SyncNetAction *actions; - if (!_soup_xmlrpc_call_with_parameters("sync.callFunctionEx", sna, - _action_call_function_got_response, - VERSION, ARCH, - sna->entry->name, - str_data, NULL)) { - g_free(str_data); + ensure_soup_session(); - return FALSE; - } + loop = g_main_loop_new(NULL, FALSE); - g_free(str_data); - } + gtk_widget_hide(sd->button_sync); + gtk_widget_hide(sd->button_priv_policy); + sync_dialog_netarea_show(sd); + g_signal_connect(G_OBJECT(sd->button_cancel), "clicked", + (GCallback)_cancel_sync, sd); - return sna->error ? FALSE : TRUE; -} + actions = sync_manager_get_selected_actions(&nactions); + sync_dialog_netarea_start_actions(sd, actions, nactions); + g_free(actions); -static gboolean _cancel_sync(GtkWidget * widget, gpointer data) -{ - SyncDialog *sd = (SyncDialog *) data; + if (sd->flag_cancel) { + gtk_widget_hide(sd->button_cancel); + gtk_widget_show(sd->button_close); - if (session) { - soup_session_abort(session); + /* wait for the user to close the dialog */ + g_main_loop_run(loop); } - sd->flag_cancel = TRUE; - g_main_quit(loop); - - gtk_widget_set_sensitive(widget, FALSE); - - return FALSE; + g_main_loop_unref(loop); } -static SyncNetAction *sync_manager_get_selected_actions(gint * n) +#if SOUP_CHECK_VERSION(2,42,0) +static void got_response(GObject *source, GAsyncResult *res, gpointer user_data) +#else +static void got_response(SoupSession *source, SoupMessage *res, gpointer user_data) +#endif { - gint i; - GSList *entry; - SyncNetAction *actions; - SyncNetAction - action_check_api = { _("Contacting HardInfo Central Database"), _action_check_api_version }, - action_clean_up = { _("Cleaning up"), NULL}; - - actions = g_new0(SyncNetAction, 2 + g_slist_length(entries)); + SyncNetAction *sna = user_data; + GInputStream *is; +#if SOUP_CHECK_VERSION(2,42,0) +#else + const guint8 *buf=NULL; + gsize len,datawritten; + SoupBuffer *soupmsg=NULL; +#endif - for (entry = entries, i = 1; entry; entry = entry->next) { - SyncEntry *e = (SyncEntry *) entry->data; +#if SOUP_CHECK_VERSION(2,42,0) + is = soup_session_send_finish(session, res, &sna->error); + if (is == NULL) + goto out; + if (sna->error != NULL) + goto out; +#endif - if (e->selected) { - SyncNetAction sna = - { e->fancy_name, _action_call_function, e }; + if (sna->entry->file_name != NULL) { + //check for missing config dirs + g_mkdir(g_get_user_config_dir(), 0766); + g_mkdir(g_build_filename(g_get_user_config_dir(),"hardinfo2",NULL), 0766); + // + gchar *path = g_build_filename(g_get_user_config_dir(), "hardinfo2", + sna->entry->file_name, NULL); + GFile *file = g_file_new_for_path(path); + GFileOutputStream *output = + g_file_replace(file, NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, + NULL, &sna->error); + + if (output != NULL) { +#if SOUP_CHECK_VERSION(2,42,0) + g_output_stream_splice(G_OUTPUT_STREAM(output), is, + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET, NULL, + &sna->error); +#else + soupmsg=soup_message_body_flatten(res->response_body); + if(soupmsg){ + soup_buffer_get_data(soupmsg,&buf,&len); + DEBUG("got file with len: %u", (unsigned int)len); + if(len>0){ + g_output_stream_write_all(G_OUTPUT_STREAM(output),buf,len,&datawritten,NULL,&sna->error); + soup_buffer_free(soupmsg); + } + } +#endif + } - actions[i++] = sna; - } + g_free(path); + g_object_unref(file); } - actions[0] = action_check_api; - actions[i++] = action_clean_up; - - *n = i; - return actions; +out: + g_main_loop_quit(loop); +#if SOUP_CHECK_VERSION(2,42,0) + g_object_unref(is); +#endif } -static SoupURI *sync_manager_get_proxy(void) +static gboolean send_request_for_net_action(SyncNetAction *sna) { - const gchar *conf; + gchar *uri; + SoupMessage *msg; + guint response_code; - if (!(conf = g_getenv("HTTP_PROXY"))) { - if (!(conf = g_getenv("http_proxy"))) { - return NULL; - } - } + uri = g_strdup_printf("%s/%s", API_SERVER_URI, sna->entry->file_name); - return soup_uri_new(conf); -} + if (sna->entry->generate_contents_for_upload == NULL) { + msg = soup_message_new("GET", uri); + } else { + gsize size; + gchar *contents = sna->entry->generate_contents_for_upload(&size); -static void sync_dialog_start_sync(SyncDialog * sd) -{ - gint nactions; - SyncNetAction *actions; + msg = soup_message_new("POST", uri); - if (!session) { - SoupURI *proxy = sync_manager_get_proxy(); - - session = soup_session_new_with_options(SOUP_SESSION_TIMEOUT, 10, - SOUP_SESSION_PROXY_URI, - proxy, NULL); - /* Crashes if we unref the proxy? O_o */ - /*if (proxy) - g_object_unref(proxy); */ +#if SOUP_CHECK_VERSION(3, 0, 0) + GBytes *cont = g_bytes_new_static(contents,size); + soup_message_set_request_body_from_bytes(msg, "application/octet-stream", cont); +#else + soup_message_set_request(msg, "application/octet-stream", + SOUP_MEMORY_TAKE, contents, size); +#endif } - loop = g_main_loop_new(NULL, TRUE); - - gtk_widget_hide(sd->button_sync); - sync_dialog_netarea_show(sd); - g_signal_connect(G_OBJECT(sd->button_cancel), "clicked", - (GCallback) _cancel_sync, sd); - - actions = sync_manager_get_selected_actions(&nactions); - sync_dialog_netarea_start_actions(sd, actions, nactions); - g_free(actions); +#if SOUP_CHECK_VERSION(3, 0, 0) + soup_session_send_async(session, msg, G_PRIORITY_DEFAULT, NULL, got_response, sna); +#else +#if SOUP_CHECK_VERSION(2,42,0) + soup_session_send_async(session, msg, NULL, got_response, sna); +#else + soup_session_queue_message(session, msg, got_response, sna); +#endif +#endif + g_main_loop_run(loop); - if (sd->flag_cancel) { - gtk_widget_hide(sd->button_cancel); - gtk_widget_show(sd->button_close); + g_object_unref(msg); + g_free(uri); - /* wait for the user to close the dialog */ - g_main_run(loop); + if (sna->error != NULL) { + DEBUG("Error while sending request: %s", sna->error->message); + g_error_free(sna->error); + sna->error = NULL; + return FALSE; } - g_main_loop_unref(loop); + return TRUE; } -static void sync_dialog_netarea_start_actions(SyncDialog * sd, - SyncNetAction sna[], gint n) +static void +sync_dialog_netarea_start_actions(SyncDialog *sd, SyncNetAction sna[], gint n) { gint i; GtkWidget **labels; GtkWidget **status_labels; - const gchar *done_str = "\342\234\223"; + const gchar *done_str = "\342\234\223"; const gchar *error_str = "\342\234\227"; - const gchar *curr_str = "\342\226\266"; + const gchar *curr_str = "\342\226\266"; const gchar *empty_str = "\302\240\302\240"; labels = g_new0(GtkWidget *, n); status_labels = g_new0(GtkWidget *, n); for (i = 0; i < n; i++) { - GtkWidget *hbox; + GtkWidget *hbox; - hbox = gtk_hbox_new(FALSE, 5); + hbox = gtk_hbox_new(FALSE, 5); - labels[i] = gtk_label_new(sna[i].name); - status_labels[i] = gtk_label_new(empty_str); + labels[i] = gtk_label_new(_(sna[i].entry->name)); + status_labels[i] = gtk_label_new(empty_str); - gtk_label_set_use_markup(GTK_LABEL(labels[i]), TRUE); - gtk_label_set_use_markup(GTK_LABEL(status_labels[i]), TRUE); + gtk_label_set_use_markup(GTK_LABEL(labels[i]), TRUE); + gtk_label_set_use_markup(GTK_LABEL(status_labels[i]), TRUE); - gtk_misc_set_alignment(GTK_MISC(labels[i]), 0.0, 0.5); - gtk_misc_set_alignment(GTK_MISC(status_labels[i]), 1.0, 0.5); + gtk_misc_set_alignment(GTK_MISC(labels[i]), 0.0, 0.5); + gtk_misc_set_alignment(GTK_MISC(status_labels[i]), 1.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), status_labels[i], FALSE, FALSE, 0); - gtk_box_pack_start(GTK_BOX(hbox), labels[i], TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(sd->sna->vbox), hbox, FALSE, FALSE, 3); + gtk_box_pack_start(GTK_BOX(hbox), status_labels[i], FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), labels[i], TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(sd->sna->vbox), hbox, FALSE, FALSE, 3); - gtk_widget_show_all(hbox); + gtk_widget_show_all(hbox); } while (gtk_events_pending()) - gtk_main_iteration(); + gtk_main_iteration(); for (i = 0; i < n; i++) { - gchar *markup; + gchar *markup; - if (sd->flag_cancel) { - markup = - g_strdup_printf("<s>%s</s> <i>%s</i>", - sna[i].name, _("(canceled)")); - gtk_label_set_markup(GTK_LABEL(labels[i]), markup); - g_free(markup); + if (sd->flag_cancel) { + markup = g_strdup_printf("<s>%s</s> <i>%s</i>", + _(sna[i].entry->name), + _("(canceled)")); + gtk_label_set_markup(GTK_LABEL(labels[i]), markup); + g_free(markup); - gtk_label_set_markup(GTK_LABEL(status_labels[i]), error_str); - break; - } + gtk_label_set_markup(GTK_LABEL(status_labels[i]), error_str); + break; + } - markup = g_strdup_printf("<b>%s</b>", sna[i].name); - gtk_label_set_markup(GTK_LABEL(labels[i]), markup); - g_free(markup); + markup = g_strdup_printf("<b>%s</b>", _(sna[i].entry->name)); + gtk_label_set_markup(GTK_LABEL(labels[i]), markup); + g_free(markup); gtk_label_set_markup(GTK_LABEL(status_labels[i]), curr_str); - if (sna[i].do_action && !sna[i].do_action(sd, &sna[i])) { - markup = - g_strdup_printf("<b><s>%s</s></b> <i>%s</i>", - sna[i].name, _("(failed)")); - gtk_label_set_markup(GTK_LABEL(labels[i]), markup); - g_free(markup); - - sd->flag_cancel = TRUE; - - gtk_label_set_markup(GTK_LABEL(status_labels[i]), error_str); - if (sna[i].error) { - if (sna[i].error->code != 1) { - /* the user has not cancelled something... */ - g_warning - (_("Failed while performing \"%s\". Please file a bug report " - "if this problem persists. (Use the Help\342\206\222Report" - " bug option.)\n\nDetails: %s"), sna[i].name, - sna[i].error->message); - } - - g_error_free(sna[i].error); - } else { - g_warning - (_("Failed while performing \"%s\". Please file a bug report " - "if this problem persists. (Use the Help\342\206\222Report" - " bug option.)"), sna[i].name); - } - break; - } + if (sna[i].entry && !send_request_for_net_action(&sna[i])) { + markup = g_strdup_printf("<b><s>%s</s></b> <i>%s</i>", + _(sna[i].entry->name), _("(failed)")); + gtk_label_set_markup(GTK_LABEL(labels[i]), markup); + g_free(markup); + + sd->flag_cancel = TRUE; + + gtk_label_set_markup(GTK_LABEL(status_labels[i]), error_str); + if (sna[i].error) { + if (sna[i].error->code != 1) { + /* the user has not cancelled something... */ + g_warning(_("Failed while performing \"%s\". Please file a " + "bug report " + "if this problem persists. (Use the " + "Help\342\206\222Report" + " bug option.)\n\nDetails: %s"), + _(sna[i].entry->name), sna[i].error->message); + } + + g_error_free(sna[i].error); + } else { + g_warning(_("Failed while performing \"%s\". Please file a bug " + "report " + "if this problem persists. (Use the " + "Help\342\206\222Report" + " bug option.)"), + _(sna[i].entry->name)); + } + break; + } gtk_label_set_markup(GTK_LABEL(status_labels[i]), done_str); - gtk_label_set_markup(GTK_LABEL(labels[i]), sna[i].name); + gtk_label_set_markup(GTK_LABEL(labels[i]), _(sna[i].entry->name)); } g_free(labels); @@ -556,14 +463,14 @@ static SyncNetArea *sync_dialog_netarea_new(void) return sna; } -static void sync_dialog_netarea_destroy(SyncNetArea * sna) +static void sync_dialog_netarea_destroy(SyncNetArea *sna) { g_return_if_fail(sna != NULL); g_free(sna); } -static void sync_dialog_netarea_show(SyncDialog * sd) +static void sync_dialog_netarea_show(SyncDialog *sd) { g_return_if_fail(sd && sd->sna); @@ -575,8 +482,7 @@ static void sync_dialog_netarea_show(SyncDialog * sd) gtk_window_reshow_with_initial_size(GTK_WINDOW(sd->dialog)); } -#if 0 -static void sync_dialog_netarea_hide(SyncDialog * sd) +static void sync_dialog_netarea_hide(SyncDialog *sd) { g_return_if_fail(sd && sd->sna); @@ -586,9 +492,8 @@ static void sync_dialog_netarea_hide(SyncDialog * sd) gtk_label_set_markup(GTK_LABEL(sd->label), LABEL_SYNC_DEFAULT); gtk_window_reshow_with_initial_size(GTK_WINDOW(sd->dialog)); } -#endif -static void populate_store(GtkListStore * store) +static void populate_store(GtkListStore *store) { GSList *entry; SyncEntry *e; @@ -596,21 +501,20 @@ static void populate_store(GtkListStore * store) gtk_list_store_clear(store); for (entry = entries; entry; entry = entry->next) { - GtkTreeIter iter; + GtkTreeIter iter; - e = (SyncEntry *) entry->data; + e = (SyncEntry *)entry->data; - e->selected = TRUE; + e->selected = TRUE; - gtk_list_store_append(store, &iter); - gtk_list_store_set(store, &iter, 0, TRUE, 1, e->fancy_name, 2, e, - -1); + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, TRUE, 1, _(e->name), 2, e, -1); } } -static void -sel_toggle(GtkCellRendererToggle * cellrenderertoggle, - gchar * path_str, GtkTreeModel * model) +static void sel_toggle(GtkCellRendererToggle *cellrenderertoggle, + gchar *path_str, + GtkTreeModel *model) { GtkTreeIter iter; GtkTreePath *path = gtk_tree_path_new_from_string(path_str); @@ -626,10 +530,7 @@ sel_toggle(GtkCellRendererToggle * cellrenderertoggle, gtk_tree_path_free(path); } -static void close_clicked(void) -{ - g_main_quit(loop); -} +static void close_clicked(void) { g_main_loop_quit(loop); } static SyncDialog *sync_dialog_new(GtkWidget *parent) { @@ -642,6 +543,7 @@ static SyncDialog *sync_dialog_new(GtkWidget *parent) GtkWidget *button8; GtkWidget *button7; GtkWidget *button6; + GtkWidget *priv_policy_btn; GtkWidget *label; GtkWidget *hbox; @@ -655,15 +557,13 @@ static SyncDialog *sync_dialog_new(GtkWidget *parent) dialog = gtk_dialog_new(); gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent)); - gtk_window_set_title(GTK_WINDOW(dialog), _("Network Updater")); + gtk_window_set_title(GTK_WINDOW(dialog), _("Synchronize")); gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); gtk_window_set_icon(GTK_WINDOW(dialog), - icon_cache_get_pixbuf("syncmanager.png")); + icon_cache_get_pixbuf("syncmanager.png")); gtk_window_set_default_size(GTK_WINDOW(dialog), 420, 260); - gtk_window_set_position(GTK_WINDOW(dialog), - GTK_WIN_POS_CENTER_ON_PARENT); - gtk_window_set_type_hint(GTK_WINDOW(dialog), - GDK_WINDOW_TYPE_HINT_DIALOG); + gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER_ON_PARENT); + gtk_window_set_type_hint(GTK_WINDOW(dialog), GDK_WINDOW_TYPE_HINT_DIALOG); gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); @@ -691,30 +591,24 @@ static SyncDialog *sync_dialog_new(GtkWidget *parent) gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); #endif - gtk_box_pack_start(GTK_BOX(hbox), - icon_cache_get_image("syncmanager.png"), - FALSE, FALSE, 0); + gtk_box_pack_start(GTK_BOX(hbox), icon_cache_get_image("syncmanager.png"), + FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, TRUE, 0); gtk_widget_show_all(hbox); - - gtk_box_pack_start(GTK_BOX(dialog1_vbox), sd->sna->vbox, TRUE, TRUE, - 0); + gtk_box_pack_start(GTK_BOX(dialog1_vbox), sd->sna->vbox, TRUE, TRUE, 0); scrolledwindow2 = gtk_scrolled_window_new(NULL, NULL); gtk_widget_show(scrolledwindow2); - gtk_box_pack_start(GTK_BOX(dialog1_vbox), scrolledwindow2, TRUE, TRUE, - 0); + gtk_box_pack_start(GTK_BOX(dialog1_vbox), scrolledwindow2, TRUE, TRUE, 0); gtk_widget_set_size_request(scrolledwindow2, -1, 200); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwindow2), - GTK_POLICY_AUTOMATIC, - GTK_POLICY_AUTOMATIC); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW - (scrolledwindow2), GTK_SHADOW_IN); + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolledwindow2), + GTK_SHADOW_IN); store = - gtk_list_store_new(3, G_TYPE_BOOLEAN, G_TYPE_STRING, - G_TYPE_POINTER); + gtk_list_store_new(3, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_POINTER); model = GTK_TREE_MODEL(store); treeview2 = gtk_tree_view_new_with_model(model); @@ -736,6 +630,12 @@ static SyncDialog *sync_dialog_new(GtkWidget *parent) populate_store(store); + priv_policy_btn = gtk_link_button_new_with_label( + "https://github.com/hardinfo2/hardinfo2?tab=readme-ov-file#privacy-policy", + _("Privacy Policy")); + gtk_widget_show(priv_policy_btn); + gtk_box_pack_start(GTK_BOX(dialog1_vbox), priv_policy_btn, FALSE, FALSE, 0); + #if GTK_CHECK_VERSION(2, 14, 0) dialog1_action_area = gtk_dialog_get_action_area(GTK_DIALOG(dialog)); #else @@ -743,12 +643,12 @@ static SyncDialog *sync_dialog_new(GtkWidget *parent) #endif gtk_widget_show(dialog1_action_area); gtk_button_box_set_layout(GTK_BUTTON_BOX(dialog1_action_area), - GTK_BUTTONBOX_END); + GTK_BUTTONBOX_END); button8 = gtk_button_new_with_mnemonic(_("_Cancel")); gtk_widget_show(button8); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button8, - GTK_RESPONSE_CANCEL); + GTK_RESPONSE_CANCEL); #if GTK_CHECK_VERSION(2, 18, 0) gtk_widget_set_can_default(button8, TRUE); #else @@ -757,17 +657,17 @@ static SyncDialog *sync_dialog_new(GtkWidget *parent) button7 = gtk_button_new_with_mnemonic(_("_Synchronize")); gtk_widget_show(button7); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button7, - GTK_RESPONSE_ACCEPT); + GTK_RESPONSE_ACCEPT); #if GTK_CHECK_VERSION(2, 18, 0) gtk_widget_set_can_default(button7, TRUE); #else GTK_WIDGET_SET_FLAGS(button7, GTK_CAN_DEFAULT); #endif button6 = gtk_button_new_from_stock(GTK_STOCK_CLOSE); - g_signal_connect(G_OBJECT(button6), "clicked", - (GCallback) close_clicked, NULL); + g_signal_connect(G_OBJECT(button6), "clicked", (GCallback)close_clicked, + NULL); gtk_dialog_add_action_widget(GTK_DIALOG(dialog), button6, - GTK_RESPONSE_ACCEPT); + GTK_RESPONSE_ACCEPT); #if GTK_CHECK_VERSION(2, 18, 0) gtk_widget_set_can_default(button6, TRUE); #else @@ -778,16 +678,57 @@ static SyncDialog *sync_dialog_new(GtkWidget *parent) sd->button_sync = button7; sd->button_cancel = button8; sd->button_close = button6; + sd->button_priv_policy = priv_policy_btn; sd->scroll_box = scrolledwindow2; sd->label = label; return sd; } -static void sync_dialog_destroy(SyncDialog * sd) +static void sync_dialog_destroy(SyncDialog *sd) { gtk_widget_destroy(sd->dialog); sync_dialog_netarea_destroy(sd->sna); g_free(sd); } -#endif /* HAS_LIBSOUP */ + +static gboolean sync_one(gpointer data) +{ + SyncNetAction *sna = data; + + if (sna->entry->generate_contents_for_upload) + goto out; + + DEBUG("Syncronizing: %s", sna->entry->name); + + gchar *msg = g_strdup_printf(_("Synchronizing: %s"), _(sna->entry->name)); + shell_status_update(msg); + shell_status_pulse(); + g_free(msg); + + send_request_for_net_action(sna); + +out: + g_main_loop_unref(loop); + idle_free(sna); + + return FALSE; +} + +void sync_manager_update_on_startup(void) +{ + GSList *entry; + + ensure_soup_session(); + + loop = g_main_loop_new(NULL, FALSE); + + for (entry = entries; entry; entry = entry->next) { + SyncNetAction *action = g_new0(SyncNetAction, 1); + + action->entry = entry->data; + loop = g_main_loop_ref(loop); + + g_idle_add(sync_one, action); + } +} |