/** * @file gnome-cmd-about-plugin.cc * @copyright (C) 2001-2006 Marcus Bjurman\n * @copyright (C) 2007-2012 Piotr Eljasiak\n * @copyright (C) 2013-2023 Uwe Scholz\n * * @copyright 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; either version 2 of the License, or * (at your option) any later version. * * @copyright This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @copyright You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "gnome-cmd-includes.h" #include "gnome-cmd-about-plugin.h" using namespace std; #define CALL_PARENT(parent_class_cast, parent, name, args) \ ((parent_class_cast(parent##_parent_class)->name != nullptr) ? \ parent_class_cast(parent##_parent_class)->name args : (void)0) struct GnomeCmdAboutPluginPrivate { gchar *name; gchar *version; gchar *copyright; gchar *comments; gchar *translator_credits; gchar *webpage; GSList *authors; GSList *documenters; GtkWidget *name_label; GtkWidget *comments_label; GtkWidget *copyright_label; GtkWidget *credits_dialog; GtkWidget *web_button; }; enum { PROP_0, PROP_NAME, PROP_VERSION, PROP_COPYRIGHT, PROP_COMMENTS, PROP_AUTHORS, PROP_DOCUMENTERS, PROP_TRANSLATOR_CREDITS, PROP_WEBPAGE }; #define GNOME_RESPONSE_CREDITS 1 static void gnome_cmd_about_plugin_finalize (GObject *object); static void gnome_cmd_about_plugin_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void gnome_cmd_about_plugin_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); //GNOME_CLASS_BOILERPLATE (GnomeCmdAboutPlugin, gnome_cmd_about_plugin, GtkDialog, (GTypeFlags) GTK_TYPE_DIALOG) G_DEFINE_TYPE (GnomeCmdAboutPlugin, gnome_cmd_about_plugin, GTK_TYPE_DIALOG) static void gnome_cmd_about_plugin_update_authors_label (GnomeCmdAboutPlugin *about, GtkWidget *label) { if (about->priv->authors == nullptr) { gtk_widget_hide (label); return; } else gtk_widget_show (label); GString *string = g_string_new (nullptr); for (GSList *list = about->priv->authors; list; list = list->next) { gchar *tmp = g_markup_escape_text ((gchar *) list->data, -1); g_string_append (string, tmp); if (list->next) g_string_append_c (string, '\n'); g_free (tmp); } gtk_label_set_markup (GTK_LABEL (label), string->str); g_string_free (string, TRUE); } static void gnome_cmd_about_plugin_update_documenters_label (GnomeCmdAboutPlugin *about, GtkWidget *label) { if (about->priv->documenters == nullptr) { gtk_widget_hide (label); return; } gtk_widget_show (label); GString *string = g_string_new (nullptr); for (GSList *list = about->priv->documenters; list; list = list->next) { gchar *tmp = g_markup_escape_text ((gchar *) list->data, -1); g_string_append (string, tmp); if (list->next) g_string_append (string, "\n"); g_free (tmp); } gtk_label_set_markup (GTK_LABEL (label), string->str); g_string_free (string, TRUE); } static void gnome_cmd_about_plugin_update_translation_information_label (GnomeCmdAboutPlugin *about, GtkWidget *label) { if (about->priv->translator_credits == nullptr) { gtk_widget_hide (label); return; } gtk_widget_show (label); GString *string = g_string_new (nullptr); gchar *tmp = g_markup_escape_text (about->priv->translator_credits, -1); g_string_append (string, tmp); g_free (tmp); g_string_append_c (string, '\n'); gtk_label_set_markup (GTK_LABEL (label), string->str); g_string_free (string, TRUE); } inline GtkWidget *_create_label () { GtkWidget *label = gtk_label_new (""); gtk_label_set_selectable (GTK_LABEL (label), TRUE); gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); gtk_misc_set_padding (GTK_MISC (label), 8, 8); gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); return label; } static void gnome_cmd_about_plugin_display_credits_dialog (GnomeCmdAboutPlugin *about) { GtkWidget *dialog, *label, *notebook, *sw; if (about->priv->credits_dialog != nullptr) { gtk_window_present (GTK_WINDOW (about->priv->credits_dialog)); return; } dialog = gtk_dialog_new_with_buttons (_("Credits"), GTK_WINDOW (about), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, nullptr); about->priv->credits_dialog = dialog; gtk_window_set_default_size (GTK_WINDOW (dialog), 360, 260); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), 2); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), dialog); g_signal_connect (dialog, "destroy", G_CALLBACK (gtk_widget_destroyed), &(about->priv->credits_dialog)); notebook = gtk_notebook_new (); gtk_container_set_border_width (GTK_CONTAINER (notebook), 5); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), notebook, TRUE, TRUE, 0); if (about->priv->authors != nullptr) { label = _create_label (); sw = gtk_scrolled_window_new (nullptr, nullptr); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), label); gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (sw))), GTK_SHADOW_NONE); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), sw, gtk_label_new (_("Written by"))); gnome_cmd_about_plugin_update_authors_label (about, label); } if (about->priv->documenters != nullptr) { label = _create_label (); sw = gtk_scrolled_window_new (nullptr, nullptr); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), label); gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (sw))), GTK_SHADOW_NONE); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), sw, gtk_label_new (_("Documented by"))); gnome_cmd_about_plugin_update_documenters_label (about, label); } if (about->priv->translator_credits != nullptr) { label = _create_label (); sw = gtk_scrolled_window_new (nullptr, nullptr); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (sw), label); gtk_viewport_set_shadow_type (GTK_VIEWPORT (gtk_bin_get_child (GTK_BIN (sw))), GTK_SHADOW_NONE); gtk_notebook_append_page (GTK_NOTEBOOK (notebook), sw, gtk_label_new (_("Translated by"))); gnome_cmd_about_plugin_update_translation_information_label (about, label); } gtk_widget_show_all (dialog); } static void link_button_clicked_callback (GtkWidget *widget, gpointer data) { const gchar *link; link = gtk_link_button_get_uri (GTK_LINK_BUTTON (widget)); gtk_show_uri (nullptr, link, gtk_get_current_event_time(), nullptr); } static void gnome_cmd_about_plugin_init (GnomeCmdAboutPlugin *about) { GtkWidget *vbox, *hbox, *image, *label, *alignment, *button; // Data GnomeCmdAboutPluginPrivate *priv = g_new0 (GnomeCmdAboutPluginPrivate, 1); about->priv = priv; // priv->name = nullptr; // priv->version = nullptr; // priv->copyright = nullptr; // priv->comments = nullptr; // priv->translator_credits = nullptr; // priv->authors = nullptr; // priv->documenters = nullptr; // priv->webpage = nullptr; gtk_dialog_set_has_separator (GTK_DIALOG (about), FALSE); gtk_container_set_border_width (GTK_CONTAINER (about), 5); gtk_box_set_spacing (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (about))), 5); // Widgets vbox = gtk_vbox_new (FALSE, 8); gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (about))), vbox, TRUE, TRUE, 0); priv->name_label = gtk_label_new (nullptr); gtk_widget_show (priv->name_label); gtk_label_set_selectable (GTK_LABEL (priv->name_label), TRUE); gtk_label_set_justify (GTK_LABEL (priv->name_label), GTK_JUSTIFY_CENTER); gtk_box_pack_start (GTK_BOX (vbox), priv->name_label, FALSE, FALSE, 0); priv->comments_label = gtk_label_new (nullptr); gtk_widget_show (priv->comments_label); gtk_label_set_selectable (GTK_LABEL (priv->comments_label), TRUE); gtk_label_set_justify (GTK_LABEL (priv->comments_label), GTK_JUSTIFY_CENTER); gtk_label_set_line_wrap (GTK_LABEL (priv->comments_label), TRUE); gtk_box_pack_start (GTK_BOX (vbox), priv->comments_label, FALSE, FALSE, 0); priv->copyright_label = gtk_label_new (nullptr); gtk_widget_show (priv->copyright_label); gtk_label_set_selectable (GTK_LABEL (priv->copyright_label), TRUE); gtk_label_set_justify (GTK_LABEL (priv->copyright_label), GTK_JUSTIFY_CENTER); gtk_box_pack_start (GTK_BOX (vbox), priv->copyright_label, FALSE, FALSE, 0); priv->web_button = gtk_link_button_new_with_label ("", _("Plugin Webpage")); g_signal_connect (priv->web_button, "clicked", G_CALLBACK (link_button_clicked_callback), NULL); gtk_box_pack_start (GTK_BOX (vbox), priv->web_button, FALSE, FALSE, 0); gtk_widget_show (vbox); // Add the close button gtk_dialog_add_button (GTK_DIALOG (about), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); gtk_dialog_set_default_response (GTK_DIALOG (about), GTK_RESPONSE_CLOSE); // Add the credits button image = gtk_image_new_from_stock (GTK_STOCK_ABOUT, GTK_ICON_SIZE_BUTTON); label = gtk_label_new_with_mnemonic (_("C_redits")); hbox = gtk_hbox_new (FALSE, 2); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0); alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0); gtk_container_add (GTK_CONTAINER (alignment), hbox); button = gtk_button_new (); gtk_container_add (GTK_CONTAINER (button), alignment); gtk_widget_show_all (button); gtk_dialog_add_action_widget (GTK_DIALOG (about), button, GNOME_RESPONSE_CREDITS); gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (gtk_dialog_get_action_area (GTK_DIALOG (about))), button, TRUE); gtk_window_set_resizable (GTK_WINDOW (about), FALSE); priv->credits_dialog = nullptr; } static void gnome_cmd_about_plugin_response (GtkDialog *dialog, gint response) { switch (response) { case GNOME_RESPONSE_CREDITS: gnome_cmd_about_plugin_display_credits_dialog (GNOME_CMD_ABOUT_PLUGIN (dialog)); break; default: gtk_widget_destroy (GTK_WIDGET (dialog)); break; } } static void gnome_cmd_about_plugin_class_init (GnomeCmdAboutPluginClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; GtkDialogClass *dialog_class = (GtkDialogClass *) klass; object_class->set_property = gnome_cmd_about_plugin_set_property; object_class->get_property = gnome_cmd_about_plugin_get_property; object_class->finalize = gnome_cmd_about_plugin_finalize; dialog_class->response = gnome_cmd_about_plugin_response; g_object_class_install_property (object_class, PROP_NAME, g_param_spec_string ("name", "Program name", "The name of the program", nullptr, (GParamFlags) G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_VERSION, g_param_spec_string ("version", "Program version", "The version of the program", nullptr, (GParamFlags) G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_COPYRIGHT, g_param_spec_string ("copyright", "Copyright string", "Copyright information for the program", nullptr, (GParamFlags) G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_COMMENTS, g_param_spec_string ("comments", "Comments string", "Comments about the program", nullptr, (GParamFlags) G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_AUTHORS, g_param_spec_value_array ("authors", "Authors", "List of authors of the programs", g_param_spec_string ("author-entry", "Author entry", "A single author entry", nullptr, (GParamFlags) G_PARAM_READWRITE), G_PARAM_WRITABLE)); g_object_class_install_property (object_class, PROP_DOCUMENTERS, g_param_spec_value_array ("documenters", "Documenters", "List of people documenting the program", g_param_spec_string ("documenter-entry", "Documenter entry", "A single documenter entry", nullptr, (GParamFlags) G_PARAM_READWRITE), G_PARAM_WRITABLE)); g_object_class_install_property (object_class, PROP_TRANSLATOR_CREDITS, g_param_spec_string ("translator_credits", "Translator credits", "Credits to the translators. This string should be marked as translatable", nullptr, (GParamFlags) G_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_WEBPAGE, g_param_spec_string ("webpage", "Webpage for the plugin", "Webpage", nullptr, (GParamFlags) G_PARAM_READWRITE)); } inline void gnome_cmd_about_plugin_set_comments (GnomeCmdAboutPlugin *about, const gchar *comments) { g_free (about->priv->comments); about->priv->comments = g_strdup (comments); gtk_label_set_text (GTK_LABEL (about->priv->comments_label), about->priv->comments); } inline void gnome_cmd_about_plugin_set_translator_credits (GnomeCmdAboutPlugin *about, const gchar *translator_credits) { g_free (about->priv->translator_credits); about->priv->translator_credits = g_strdup (translator_credits); } inline void gnome_cmd_about_plugin_set_webpage (GnomeCmdAboutPlugin *about, const gchar *webpage) { if (!webpage) return; g_free (about->priv->webpage); about->priv->webpage = g_strdup (webpage); gtk_link_button_set_uri(GTK_LINK_BUTTON (about->priv->web_button), webpage); gtk_widget_show (about->priv->web_button); } static void gnome_cmd_about_plugin_set_copyright (GnomeCmdAboutPlugin *about, const gchar *copyright) { char *copyright_string = nullptr; g_free (about->priv->copyright); about->priv->copyright = g_strdup (copyright); if (about->priv->copyright) { char *tmp = g_markup_escape_text (about->priv->copyright, -1); copyright_string = g_strdup_printf ("%s", tmp); g_free (tmp); } gtk_label_set_markup (GTK_LABEL (about->priv->copyright_label), copyright_string); g_free (copyright_string); } static void gnome_cmd_about_plugin_set_version (GnomeCmdAboutPlugin *about, const gchar *version) { g_free (about->priv->version); about->priv->version = g_strdup (version); gchar *name_string; gchar *tmp_name = g_markup_escape_text (about->priv->name, -1); if (about->priv->version) { gchar *tmp_version = g_markup_escape_text (about->priv->version, -1); name_string = g_strdup_printf ("%s %s", tmp_name, tmp_version); g_free (tmp_version); } else name_string = g_strdup_printf ("%s", tmp_name); gtk_label_set_markup (GTK_LABEL (about->priv->name_label), name_string); g_free (name_string); g_free (tmp_name); } static void gnome_cmd_about_plugin_set_name (GnomeCmdAboutPlugin *about, const gchar *name) { gchar *title_string; gchar *name_string; gchar *tmp_name; g_free (about->priv->name); about->priv->name = g_strdup (name ? name : ""); title_string = g_strdup_printf (_("About %s"), name); gtk_window_set_title (GTK_WINDOW (about), title_string); g_free (title_string); tmp_name = g_markup_escape_text (about->priv->name, -1); if (about->priv->version) { gchar *tmp_version; tmp_version = g_markup_escape_text (about->priv->version, -1); name_string = g_strdup_printf ("%s %s", tmp_name, tmp_version); g_free (tmp_version); } else name_string = g_strdup_printf ("%s", tmp_name); gtk_label_set_markup (GTK_LABEL (about->priv->name_label), name_string); g_free (name_string); g_free (tmp_name); } inline void gnome_cmd_about_plugin_free_person_list (GSList *list) { if (list == nullptr) return; g_slist_foreach (list, (GFunc) g_free, nullptr); g_slist_free (list); } static void gnome_cmd_about_plugin_finalize (GObject *object) { GnomeCmdAboutPlugin *about = GNOME_CMD_ABOUT_PLUGIN (object); g_free (about->priv->name); g_free (about->priv->version); g_free (about->priv->copyright); g_free (about->priv->comments); gnome_cmd_about_plugin_free_person_list (about->priv->authors); gnome_cmd_about_plugin_free_person_list (about->priv->documenters); g_free (about->priv->translator_credits); g_free (about->priv->webpage); g_free (about->priv); about->priv = nullptr; CALL_PARENT (G_OBJECT_CLASS, gnome_cmd_about_plugin, finalize, (object)); } static void gnome_cmd_about_plugin_set_persons (GnomeCmdAboutPlugin *about, guint prop_id, const GValue *persons) { GSList *list = nullptr; // Free the old list switch (prop_id) { case PROP_AUTHORS: list = about->priv->authors; break; case PROP_DOCUMENTERS: list = about->priv->documenters; break; default: g_assert_not_reached (); } gnome_cmd_about_plugin_free_person_list (list); list = nullptr; GValueArray *value_array = (GValueArray *) g_value_get_boxed (persons); if (!value_array) return; for (guint i = 0; i < value_array->n_values; i++) list = g_slist_prepend (list, g_value_dup_string (&value_array->values[i])); list = g_slist_reverse (list); switch (prop_id) { case PROP_AUTHORS: about->priv->authors = list; break; case PROP_DOCUMENTERS: about->priv->documenters = list; break; default: g_assert_not_reached (); } } static void set_value_array_from_list (GValue *value, GSList *list) { gint length = g_slist_length (list); GArray *array = g_array_sized_new (FALSE, TRUE, sizeof(char*), length); for (GSList *i = list; i; i = i->next) { g_array_append_val (array, i->data); } g_value_set_boxed (value, array); g_array_free (array, TRUE); } static void gnome_cmd_about_plugin_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { switch (prop_id) { case PROP_NAME: gnome_cmd_about_plugin_set_name (GNOME_CMD_ABOUT_PLUGIN (object), g_value_get_string (value)); break; case PROP_VERSION: gnome_cmd_about_plugin_set_version (GNOME_CMD_ABOUT_PLUGIN (object), g_value_get_string (value)); break; case PROP_COMMENTS: gnome_cmd_about_plugin_set_comments (GNOME_CMD_ABOUT_PLUGIN (object), g_value_get_string (value)); break; case PROP_COPYRIGHT: gnome_cmd_about_plugin_set_copyright (GNOME_CMD_ABOUT_PLUGIN (object), g_value_get_string (value)); break; case PROP_AUTHORS: case PROP_DOCUMENTERS: gnome_cmd_about_plugin_set_persons (GNOME_CMD_ABOUT_PLUGIN (object), prop_id, value); break; case PROP_TRANSLATOR_CREDITS: gnome_cmd_about_plugin_set_translator_credits (GNOME_CMD_ABOUT_PLUGIN (object), g_value_get_string (value)); break; case PROP_WEBPAGE: gnome_cmd_about_plugin_set_webpage (GNOME_CMD_ABOUT_PLUGIN (object), g_value_get_string (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void gnome_cmd_about_plugin_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GnomeCmdAboutPlugin *about = GNOME_CMD_ABOUT_PLUGIN (object); switch (prop_id) { case PROP_NAME: g_value_set_string (value, about->priv->name); break; case PROP_VERSION: g_value_set_string (value, about->priv->version); break; case PROP_COPYRIGHT: g_value_set_string (value, about->priv->copyright); break; case PROP_COMMENTS: g_value_set_string (value, about->priv->comments); break; case PROP_TRANSLATOR_CREDITS: g_value_set_string (value, about->priv->translator_credits); break; case PROP_WEBPAGE: g_value_set_string (value, about->priv->webpage); break; case PROP_AUTHORS: set_value_array_from_list (value, about->priv->authors); break; case PROP_DOCUMENTERS: set_value_array_from_list (value, about->priv->documenters); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /** * Similar to gnome_cmd_about_plugin_new() except that the pre-existing * GnomeCmdAboutPlugin widget is used. Note that in this version of the * function, @c authors is not checked to be non-NULL, so callers must * be careful, since bad things will happen if this condition is not * met. * * @param about An existing GnomeCmdAboutPlugin instance. * @param name The name of the application. * @param version The version string of the application. * @param copyright The application's copyright statement. * @param comments A short miscellaneous string. * @param authors An %NULL terminated array of the application authors. * @param documenters An array of the application documenters. * @param translator_credits The translator for the current locale. * @param webpage The plugins's webpage. */ static void gnome_cmd_about_plugin_construct (GnomeCmdAboutPlugin *about, const gchar *name, const gchar *version, const gchar *copyright, const gchar *comments, const gchar **authors, const gchar **documenters, const gchar *translator_credits, const gchar *webpage) { GArray *authors_array = g_array_new (FALSE, FALSE, sizeof(char*)); GArray *documenters_array = nullptr; for (gint i = 0; authors[i] != nullptr; i++) { authors_array = g_array_append_val (authors_array, authors[i]); } if (documenters) { documenters_array = g_array_new (FALSE, FALSE, sizeof(char*)); for (gint i = 0; documenters[i] != nullptr; i++) { documenters_array = g_array_append_val (documenters_array, documenters[i]); } } g_object_set (G_OBJECT (about), "name", name, "version", version, "copyright", copyright, "comments", comments, // "authors", authors_array, // "documenters", documenters_array, "translator_credits", translator_credits, "webpage", webpage, nullptr); if (authors_array) g_array_free (authors_array, TRUE); if (documenters_array) g_array_free (documenters_array, TRUE); } /** * Construct an application's credits box. The authors array cannot be empty * and the translator_credits should be marked as a translatable string (so * that only the translator for the currently active locale is displayed). * * @returns A new "About" dialog. */ GtkWidget *gnome_cmd_about_plugin_new (PluginInfo *info) { g_return_val_if_fail (info != nullptr, nullptr); auto about = static_cast (g_object_new (GNOME_CMD_TYPE_ABOUT_PLUGIN, nullptr)); gnome_cmd_about_plugin_construct(about, info->name, info->version, info->copyright, info->comments, (const gchar**) info->authors, (const gchar**) info->documenters, info->translator, info->webpage); return GTK_WIDGET(about); }