diff options
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); +    } +}  | 
