gtk2/gtk/gtkaboutdialog.c
Claudio Saavedra e4a83370c4 Improve the looks of the license text in GtkAboutDialog
It is not safe to assume that copyright text in applications is
one liner, therefore it's better to split it from the program name.

Also, the license text should be in a paragraph of its own, so
add an extra '\n' above it.

https://bugzilla.gnome.org/show_bug.cgi?id=626514
2010-08-12 14:23:58 +03:00

2601 lines
78 KiB
C

/* GTK - The GIMP Toolkit
* Copyright (C) 2001 CodeFactory AB
* Copyright (C) 2001, 2002 Anders Carlsson
* Copyright (C) 2003, 2004 Matthias Clasen <mclasen@redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
/*
* Author: Anders Carlsson <andersca@gnome.org>
*
* Modified by the GTK+ Team and others 1997-2004. See the AUTHORS
* file for a list of people on the GTK+ Team. See the ChangeLog
* files for a list of changes. These files are distributed with
* GTK+ at ftp://ftp.gtk.org/pub/gtk/.
*/
#include "config.h"
#include <string.h>
#include <gdk/gdkkeysyms.h>
#include "gtkaboutdialog.h"
#include "gtkbutton.h"
#include "gtkbbox.h"
#include "gtkdialog.h"
#include "gtkhbox.h"
#include "gtkimage.h"
#include "gtklabel.h"
#include "gtklinkbutton.h"
#include "gtkmarshalers.h"
#include "gtknotebook.h"
#include "gtkscrolledwindow.h"
#include "gtkstock.h"
#include "gtktextview.h"
#include "gtkvbox.h"
#include "gtkiconfactory.h"
#include "gtkshow.h"
#include "gtkmain.h"
#include "gtkmessagedialog.h"
#include "gtkprivate.h"
#include "gtkintl.h"
/**
* SECTION:gtkaboutdialog
* @Short_description: Display information about an application
* @Title: GtkAboutDialog
* @See_also:#GTK_STOCK_ABOUT
*
* The #GtkAboutDialog offers a simple way to display information about
* a program like its logo, name, copyright, website and license. It is
* also possible to give credits to the authors, documenters, translators
* and artists who have worked on the program. An about dialog is typically
* opened when the user selects the <literal>About</literal> option from
* the <literal>Help</literal> menu. All parts of the dialog are optional.
*
* About dialog often contain links and email addresses. #GtkAboutDialog
* supports this by offering global hooks, which are called when the user
* clicks on a link or email address, see gtk_about_dialog_set_email_hook()
* and gtk_about_dialog_set_url_hook(). Email addresses in the
* authors, documenters and artists properties are recognized by looking for
* <literal>&lt;user@<!-- -->host&gt;</literal>, URLs are
* recognized by looking for <literal>http://url</literal>, with
* <literal>url</literal> extending to the next space, tab or line break.
*
* <para id="gtk-about-dialog-hook-setup">
* Since 2.18 #GtkAboutDialog provides default website and email hooks that
* use gtk_show_uri().
* </para>
*
* If you want provide your own hooks overriding the default ones, it is
* important to do so before setting the website and email URL properties,
* like this:
* <informalexample><programlisting>
* gtk_about_dialog_set_url_hook (GTK_ABOUT_DIALOG (dialog), launch_url, NULL, NULL);
* gtk_about_dialog_set_website (GTK_ABOUT_DIALOG (dialog), app_url);
* </programlisting></informalexample>
* To disable the default hooks, you can pass %NULL as the hook func. Then,
* the #GtkAboutDialog widget will not display the website or the
* email addresses as clickable.
*
* To make constructing a #GtkAboutDialog as convenient as possible, you can
* use the function gtk_show_about_dialog() which constructs and shows a dialog
* and keeps it around so that it can be shown again.
*
* Note that GTK+ sets a default title of <literal>_("About &percnt;s")</literal>
* on the dialog window (where &percnt;s is replaced by the name of the
* application, but in order to ensure proper translation of the title,
* applications should set the title property explicitly when constructing
* a #GtkAboutDialog, as shown in the following example:
* <informalexample><programlisting>
* gtk_show_about_dialog (NULL,
* "program-name", "ExampleCode",
* "logo", example_logo,
* "title" _("About ExampleCode"),
* NULL);
* </programlisting></informalexample>
* Note that prior to GTK+ 2.12, the #GtkAboutDialog:program-name property
* was called "name". This was changed to avoid the conflict with the
* #GtkWidget:name property.
*/
static GdkColor default_link_color = { 0, 0, 0, 0xeeee };
static GdkColor default_visited_link_color = { 0, 0x5555, 0x1a1a, 0x8b8b };
/* Translators: this is the license preamble; the string at the end
* contains the URL of the license.
*/
static const gchar *gtk_license_preamble = N_("This program comes with ABSOLUTELY NO WARRANTY; for details, visit %s");
/* URLs for each GtkLicense type; keep in the same order as the enumeration */
static const gchar *gtk_license_urls[] = {
NULL,
NULL,
"http://www.gnu.org/licenses/old-licenses/gpl-2.0.html",
"http://www.gnu.org/licenses/gpl.html",
"http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html",
"http://www.gnu.org/licenses/lgpl.html",
"http://opensource.org/licenses/bsd-license.php",
"http://opensource.org/licenses/mit-license.php",
"http://opensource.org/licenses/artistic-license-2.0.php"
};
struct _GtkAboutDialogPrivate
{
gchar *name;
gchar *version;
gchar *copyright;
gchar *comments;
gchar *website_url;
gchar *website_text;
gchar *translator_credits;
gchar *license;
gchar **authors;
gchar **documenters;
gchar **artists;
GtkWidget *logo_image;
GtkWidget *name_label;
GtkWidget *comments_label;
GtkWidget *copyright_label;
GtkWidget *website_label;
GtkWidget *credits_button;
GtkWidget *credits_dialog;
GtkWidget *license_button;
GtkWidget *license_dialog;
GdkCursor *hand_cursor;
GdkCursor *regular_cursor;
GSList *visited_links;
GtkLicense license_type;
guint hovering_over_link : 1;
guint wrap_license : 1;
};
#define GTK_ABOUT_DIALOG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ABOUT_DIALOG, GtkAboutDialogPrivate))
enum
{
PROP_0,
PROP_NAME,
PROP_VERSION,
PROP_COPYRIGHT,
PROP_COMMENTS,
PROP_WEBSITE,
PROP_WEBSITE_LABEL,
PROP_LICENSE,
PROP_AUTHORS,
PROP_DOCUMENTERS,
PROP_TRANSLATOR_CREDITS,
PROP_ARTISTS,
PROP_LOGO,
PROP_LOGO_ICON_NAME,
PROP_WRAP_LICENSE,
PROP_LICENSE_TYPE
};
static void gtk_about_dialog_finalize (GObject *object);
static void gtk_about_dialog_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static void gtk_about_dialog_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gtk_about_dialog_show (GtkWidget *widge);
static void update_name_version (GtkAboutDialog *about);
static GtkIconSet * icon_set_new_from_pixbufs (GList *pixbufs);
static void follow_if_link (GtkAboutDialog *about,
GtkTextView *text_view,
GtkTextIter *iter);
static void set_cursor_if_appropriate (GtkAboutDialog *about,
GtkTextView *text_view,
GdkDevice *device,
gint x,
gint y);
static void display_credits_dialog (GtkWidget *button,
gpointer data);
static void display_license_dialog (GtkWidget *button,
gpointer data);
static void close_cb (GtkAboutDialog *about);
static void default_url_hook (GtkAboutDialog *about,
const gchar *uri,
gpointer user_data);
static void default_email_hook (GtkAboutDialog *about,
const gchar *email_address,
gpointer user_data);
static gboolean activate_email_hook_set = FALSE;
static GtkAboutDialogActivateLinkFunc activate_email_hook = NULL;
static gpointer activate_email_hook_data = NULL;
static GDestroyNotify activate_email_hook_destroy = NULL;
static gboolean activate_url_hook_set = FALSE;
static GtkAboutDialogActivateLinkFunc activate_url_hook = NULL;
static gpointer activate_url_hook_data = NULL;
static GDestroyNotify activate_url_hook_destroy = NULL;
static void
default_url_hook (GtkAboutDialog *about,
const gchar *uri,
gpointer user_data)
{
GdkScreen *screen;
GError *error = NULL;
screen = gtk_widget_get_screen (GTK_WIDGET (about));
if (!gtk_show_uri (screen, uri, gtk_get_current_event_time (), &error))
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (about),
GTK_DIALOG_DESTROY_WITH_PARENT |
GTK_DIALOG_MODAL,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_CLOSE,
"%s", _("Could not show link"));
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", error->message);
g_error_free (error);
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), NULL);
gtk_window_present (GTK_WINDOW (dialog));
}
}
static void
default_email_hook (GtkAboutDialog *about,
const gchar *email_address,
gpointer user_data)
{
char *escaped, *uri;
escaped = g_uri_escape_string (email_address, NULL, FALSE);
uri = g_strdup_printf ("mailto:%s", escaped);
g_free (escaped);
default_url_hook (about, uri, user_data);
g_free (uri);
}
G_DEFINE_TYPE (GtkAboutDialog, gtk_about_dialog, GTK_TYPE_DIALOG)
static void
gtk_about_dialog_class_init (GtkAboutDialogClass *klass)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
object_class = (GObjectClass *)klass;
widget_class = (GtkWidgetClass *)klass;
object_class->set_property = gtk_about_dialog_set_property;
object_class->get_property = gtk_about_dialog_get_property;
object_class->finalize = gtk_about_dialog_finalize;
widget_class->show = gtk_about_dialog_show;
/**
* GtkAboutDialog:program-name:
*
* The name of the program.
* If this is not set, it defaults to g_get_application_name().
*
* Since: 2.12
*/
g_object_class_install_property (object_class,
PROP_NAME,
g_param_spec_string ("program-name",
P_("Program name"),
P_("The name of the program. If this is not set, it defaults to g_get_application_name()"),
NULL,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:version:
*
* The version of the program.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_VERSION,
g_param_spec_string ("version",
P_("Program version"),
P_("The version of the program"),
NULL,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:copyright:
*
* Copyright information for the program.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_COPYRIGHT,
g_param_spec_string ("copyright",
P_("Copyright string"),
P_("Copyright information for the program"),
NULL,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:comments:
*
* Comments about the program. This string is displayed in a label
* in the main dialog, thus it should be a short explanation of
* the main purpose of the program, not a detailed list of features.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_COMMENTS,
g_param_spec_string ("comments",
P_("Comments string"),
P_("Comments about the program"),
NULL,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:license:
*
* The license of the program. This string is displayed in a
* text view in a secondary dialog, therefore it is fine to use
* a long multi-paragraph text. Note that the text is only wrapped
* in the text view if the "wrap-license" property is set to %TRUE;
* otherwise the text itself must contain the intended linebreaks.
* When setting this property to a non-%NULL value, the
* #GtkAboutDialog:license-type property is set to %GTK_LICENSE_CUSTOM
* as a side effect.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_LICENSE,
g_param_spec_string ("license",
_("License"),
_("The license of the program"),
NULL,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:license-type:
*
* The license of the program, as a value of the %GtkLicense enumeration.
*
* The #GtkAboutDialog will automatically fill out a standard disclaimer
* and link the user to the appropriate online resource for the license
* text.
*
* If %GTK_LICENSE_UNKNOWN is used, the link used will be the same
* specified in the #GtkAboutDialog:website property.
*
* If %GTK_LICENSE_CUSTOM is used, the current contents of the
* #GtkAboutDialog:license property are used.
*
* For any other #GtkLicense value, the contents of the
* #GtkAboutDialog:license property are also set by this property as
* a side effect.
*
* Since: 3.0
*/
g_object_class_install_property (object_class,
PROP_LICENSE_TYPE,
g_param_spec_enum ("license-type",
P_("License Type"),
P_("The license type of the program"),
GTK_TYPE_LICENSE,
GTK_LICENSE_UNKNOWN,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:website:
*
* The URL for the link to the website of the program.
* This should be a string starting with "http://.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_WEBSITE,
g_param_spec_string ("website",
P_("Website URL"),
P_("The URL for the link to the website of the program"),
NULL,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:website-label:
*
* The label for the link to the website of the program. If this is not set,
* it defaults to the URL specified in the #GtkAboutDialog:website property.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_WEBSITE_LABEL,
g_param_spec_string ("website-label",
P_("Website label"),
P_("The label for the link to the website of the program. If this is not set, it defaults to the URL"),
NULL,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:authors:
*
* The authors of the program, as a %NULL-terminated array of strings.
* Each string may contain email addresses and URLs, which will be displayed
* as links, see the introduction for more details.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_AUTHORS,
g_param_spec_boxed ("authors",
P_("Authors"),
P_("List of authors of the program"),
G_TYPE_STRV,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:documenters:
*
* The people documenting the program, as a %NULL-terminated array of strings.
* Each string may contain email addresses and URLs, which will be displayed
* as links, see the introduction for more details.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_DOCUMENTERS,
g_param_spec_boxed ("documenters",
P_("Documenters"),
P_("List of people documenting the program"),
G_TYPE_STRV,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:artists:
*
* The people who contributed artwork to the program, as a %NULL-terminated
* array of strings. Each string may contain email addresses and URLs, which
* will be displayed as links, see the introduction for more details.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_ARTISTS,
g_param_spec_boxed ("artists",
P_("Artists"),
P_("List of people who have contributed artwork to the program"),
G_TYPE_STRV,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:translator-credits:
*
* Credits to the translators. This string should be marked as translatable.
* The string may contain email addresses and URLs, which will be displayed
* as links, see the introduction for more details.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_TRANSLATOR_CREDITS,
g_param_spec_string ("translator-credits",
P_("Translator credits"),
P_("Credits to the translators. This string should be marked as translatable"),
NULL,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:logo:
*
* A logo for the about box. If this is not set, it defaults to
* gtk_window_get_default_icon_list().
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_LOGO,
g_param_spec_object ("logo",
P_("Logo"),
P_("A logo for the about box. If this is not set, it defaults to gtk_window_get_default_icon_list()"),
GDK_TYPE_PIXBUF,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:logo-icon-name:
*
* A named icon to use as the logo for the about box. This property
* overrides the #GtkAboutDialog:logo property.
*
* Since: 2.6
*/
g_object_class_install_property (object_class,
PROP_LOGO_ICON_NAME,
g_param_spec_string ("logo-icon-name",
P_("Logo Icon Name"),
P_("A named icon to use as the logo for the about box."),
NULL,
GTK_PARAM_READWRITE));
/**
* GtkAboutDialog:wrap-license:
*
* Whether to wrap the text in the license dialog.
*
* Since: 2.8
*/
g_object_class_install_property (object_class,
PROP_WRAP_LICENSE,
g_param_spec_boolean ("wrap-license",
P_("Wrap license"),
P_("Whether to wrap the license text."),
FALSE,
GTK_PARAM_READWRITE));
g_type_class_add_private (object_class, sizeof (GtkAboutDialogPrivate));
}
static gboolean
website_clicked (GtkLabel *label,
const gchar *uri,
GtkAboutDialog *about)
{
GtkAboutDialogActivateLinkFunc url_hook;
gpointer url_hook_data;
if (activate_url_hook_set)
{
url_hook = activate_url_hook;
url_hook_data = activate_url_hook_data;
}
else
{
url_hook = default_url_hook;
url_hook_data = NULL;
}
url_hook (about, uri, url_hook_data);
return TRUE;
}
static void
gtk_about_dialog_init (GtkAboutDialog *about)
{
GtkDialog *dialog = GTK_DIALOG (about);
GtkAboutDialogPrivate *priv;
GtkWidget *vbox, *hbox, *button, *close_button, *image;
GtkWidget *content_area, *action_area;
/* Data */
priv = GTK_ABOUT_DIALOG_GET_PRIVATE (about);
about->priv = priv;
priv->name = NULL;
priv->version = NULL;
priv->copyright = NULL;
priv->comments = NULL;
priv->website_url = NULL;
priv->website_text = NULL;
priv->translator_credits = NULL;
priv->license = NULL;
priv->authors = NULL;
priv->documenters = NULL;
priv->artists = NULL;
priv->hand_cursor = gdk_cursor_new (GDK_HAND2);
priv->regular_cursor = gdk_cursor_new (GDK_XTERM);
priv->hovering_over_link = FALSE;
priv->wrap_license = FALSE;
priv->license_type = GTK_LICENSE_UNKNOWN;
content_area = gtk_dialog_get_content_area (dialog);
action_area = gtk_dialog_get_action_area (dialog);
gtk_dialog_set_has_separator (dialog, FALSE);
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
/* Widgets */
gtk_widget_push_composite_child ();
vbox = gtk_vbox_new (FALSE, 8);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
gtk_box_pack_start (GTK_BOX (content_area), vbox, TRUE, TRUE, 0);
priv->logo_image = gtk_image_new ();
gtk_box_pack_start (GTK_BOX (vbox), priv->logo_image, FALSE, FALSE, 0);
priv->name_label = gtk_label_new (NULL);
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 (NULL);
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 (NULL);
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);
hbox = gtk_hbox_new (TRUE, 0);
gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 0);
priv->website_label = button = gtk_label_new ("");
gtk_widget_set_no_show_all (button, TRUE);
gtk_label_set_selectable (GTK_LABEL (button), TRUE);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "activate-link",
G_CALLBACK (website_clicked), about);
gtk_widget_show (vbox);
gtk_widget_show (priv->logo_image);
gtk_widget_show (priv->name_label);
gtk_widget_show (hbox);
/* Add the close button */
close_button = gtk_dialog_add_button (GTK_DIALOG (about), GTK_STOCK_CLOSE,
GTK_RESPONSE_CANCEL);
gtk_dialog_set_default_response (GTK_DIALOG (about), GTK_RESPONSE_CANCEL);
/* Add the credits button */
button = gtk_button_new_with_mnemonic (_("C_redits"));
gtk_widget_set_can_default (button, TRUE);
image = gtk_image_new_from_stock (GTK_STOCK_ABOUT, GTK_ICON_SIZE_BUTTON);
gtk_button_set_image (GTK_BUTTON (button), image);
gtk_widget_set_no_show_all (button, TRUE);
gtk_box_pack_end (GTK_BOX (action_area),
button, FALSE, TRUE, 0);
gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (action_area), button, TRUE);
g_signal_connect (button, "clicked",
G_CALLBACK (display_credits_dialog), about);
priv->credits_button = button;
priv->credits_dialog = NULL;
/* Add the license button */
button = gtk_button_new_from_stock (_("_License"));
gtk_widget_set_can_default (button, TRUE);
gtk_widget_set_no_show_all (button, TRUE);
gtk_box_pack_end (GTK_BOX (action_area),
button, FALSE, TRUE, 0);
gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (action_area), button, TRUE);
g_signal_connect (button, "clicked",
G_CALLBACK (display_license_dialog), about);
priv->license_button = button;
priv->license_dialog = NULL;
gtk_window_set_resizable (GTK_WINDOW (about), FALSE);
gtk_widget_pop_composite_child ();
gtk_widget_grab_default (close_button);
gtk_widget_grab_focus (close_button);
/* force defaults */
gtk_about_dialog_set_program_name (about, NULL);
gtk_about_dialog_set_logo (about, NULL);
}
static void
gtk_about_dialog_finalize (GObject *object)
{
GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
GtkAboutDialogPrivate *priv = about->priv;
g_free (priv->name);
g_free (priv->version);
g_free (priv->copyright);
g_free (priv->comments);
g_free (priv->license);
g_free (priv->website_url);
g_free (priv->website_text);
g_free (priv->translator_credits);
g_strfreev (priv->authors);
g_strfreev (priv->documenters);
g_strfreev (priv->artists);
g_slist_foreach (priv->visited_links, (GFunc)g_free, NULL);
g_slist_free (priv->visited_links);
gdk_cursor_unref (priv->hand_cursor);
gdk_cursor_unref (priv->regular_cursor);
G_OBJECT_CLASS (gtk_about_dialog_parent_class)->finalize (object);
}
static void
gtk_about_dialog_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
GtkAboutDialogPrivate *priv = about->priv;
switch (prop_id)
{
case PROP_NAME:
gtk_about_dialog_set_program_name (about, g_value_get_string (value));
break;
case PROP_VERSION:
gtk_about_dialog_set_version (about, g_value_get_string (value));
break;
case PROP_COMMENTS:
gtk_about_dialog_set_comments (about, g_value_get_string (value));
break;
case PROP_WEBSITE:
gtk_about_dialog_set_website (about, g_value_get_string (value));
break;
case PROP_WEBSITE_LABEL:
gtk_about_dialog_set_website_label (about, g_value_get_string (value));
break;
case PROP_LICENSE:
gtk_about_dialog_set_license (about, g_value_get_string (value));
break;
case PROP_LICENSE_TYPE:
gtk_about_dialog_set_license_type (about, g_value_get_enum (value));
break;
case PROP_COPYRIGHT:
gtk_about_dialog_set_copyright (about, g_value_get_string (value));
break;
case PROP_LOGO:
gtk_about_dialog_set_logo (about, g_value_get_object (value));
break;
case PROP_AUTHORS:
gtk_about_dialog_set_authors (about, (const gchar**)g_value_get_boxed (value));
break;
case PROP_DOCUMENTERS:
gtk_about_dialog_set_documenters (about, (const gchar**)g_value_get_boxed (value));
break;
case PROP_ARTISTS:
gtk_about_dialog_set_artists (about, (const gchar**)g_value_get_boxed (value));
break;
case PROP_TRANSLATOR_CREDITS:
gtk_about_dialog_set_translator_credits (about, g_value_get_string (value));
break;
case PROP_LOGO_ICON_NAME:
gtk_about_dialog_set_logo_icon_name (about, g_value_get_string (value));
break;
case PROP_WRAP_LICENSE:
priv->wrap_license = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gtk_about_dialog_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
GtkAboutDialogPrivate *priv = about->priv;
switch (prop_id)
{
case PROP_NAME:
g_value_set_string (value, priv->name);
break;
case PROP_VERSION:
g_value_set_string (value, priv->version);
break;
case PROP_COPYRIGHT:
g_value_set_string (value, priv->copyright);
break;
case PROP_COMMENTS:
g_value_set_string (value, priv->comments);
break;
case PROP_WEBSITE:
g_value_set_string (value, priv->website_url);
break;
case PROP_WEBSITE_LABEL:
g_value_set_string (value, priv->website_text);
break;
case PROP_LICENSE:
g_value_set_string (value, priv->license);
break;
case PROP_LICENSE_TYPE:
g_value_set_enum (value, priv->license_type);
break;
case PROP_TRANSLATOR_CREDITS:
g_value_set_string (value, priv->translator_credits);
break;
case PROP_AUTHORS:
g_value_set_boxed (value, priv->authors);
break;
case PROP_DOCUMENTERS:
g_value_set_boxed (value, priv->documenters);
break;
case PROP_ARTISTS:
g_value_set_boxed (value, priv->artists);
break;
case PROP_LOGO:
if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
g_value_set_object (value, gtk_image_get_pixbuf (GTK_IMAGE (priv->logo_image)));
else
g_value_set_object (value, NULL);
break;
case PROP_LOGO_ICON_NAME:
if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_ICON_NAME)
{
const gchar *icon_name;
gtk_image_get_icon_name (GTK_IMAGE (priv->logo_image), &icon_name, NULL);
g_value_set_string (value, icon_name);
}
else
g_value_set_string (value, NULL);
break;
case PROP_WRAP_LICENSE:
g_value_set_boolean (value, priv->wrap_license);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
update_website (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv = about->priv;
gtk_widget_show (priv->website_label);
if (priv->website_url && (!activate_url_hook_set || activate_url_hook != NULL))
{
gchar *markup;
if (priv->website_text)
{
gchar *escaped;
escaped = g_markup_escape_text (priv->website_text, -1);
markup = g_strdup_printf ("<a href=\"%s\">%s</a>",
priv->website_url, escaped);
g_free (escaped);
}
else
{
markup = g_strdup_printf ("<a href=\"%s\">%s</a>",
priv->website_url, priv->website_url);
}
gtk_label_set_markup (GTK_LABEL (priv->website_label), markup);
g_free (markup);
}
else
{
if (priv->website_url)
gtk_label_set_text (GTK_LABEL (priv->website_label), priv->website_url);
else if (priv->website_text)
gtk_label_set_text (GTK_LABEL (priv->website_label), priv->website_text);
else
gtk_widget_hide (priv->website_label);
}
}
static void
gtk_about_dialog_show (GtkWidget *widget)
{
update_website (GTK_ABOUT_DIALOG (widget));
GTK_WIDGET_CLASS (gtk_about_dialog_parent_class)->show (widget);
}
/**
* gtk_about_dialog_get_program_name:
* @about: a #GtkAboutDialog
*
* Returns the program name displayed in the about dialog.
*
* Return value: The program name. The string is owned by the about
* dialog and must not be modified.
*
* Since: 2.12
*/
G_CONST_RETURN gchar *
gtk_about_dialog_get_program_name (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv;
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
priv = about->priv;
return priv->name;
}
static void
update_name_version (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv;
gchar *title_string, *name_string;
priv = about->priv;
title_string = g_strdup_printf (_("About %s"), priv->name);
gtk_window_set_title (GTK_WINDOW (about), title_string);
g_free (title_string);
if (priv->version != NULL)
name_string = g_markup_printf_escaped ("<span size=\"xx-large\" weight=\"bold\">%s %s</span>",
priv->name, priv->version);
else
name_string = g_markup_printf_escaped ("<span size=\"xx-large\" weight=\"bold\">%s</span>",
priv->name);
gtk_label_set_markup (GTK_LABEL (priv->name_label), name_string);
g_free (name_string);
}
/**
* gtk_about_dialog_set_program_name:
* @about: a #GtkAboutDialog
* @name: the program name
*
* Sets the name to display in the about dialog.
* If this is not set, it defaults to g_get_application_name().
*
* Since: 2.12
*/
void
gtk_about_dialog_set_program_name (GtkAboutDialog *about,
const gchar *name)
{
GtkAboutDialogPrivate *priv;
gchar *tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->name;
priv->name = g_strdup (name ? name : g_get_application_name ());
g_free (tmp);
update_name_version (about);
g_object_notify (G_OBJECT (about), "program-name");
}
/**
* gtk_about_dialog_get_version:
* @about: a #GtkAboutDialog
*
* Returns the version string.
*
* Return value: The version string. The string is owned by the about
* dialog and must not be modified.
*
* Since: 2.6
*/
G_CONST_RETURN gchar *
gtk_about_dialog_get_version (GtkAboutDialog *about)
{
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
return about->priv->version;
}
/**
* gtk_about_dialog_set_version:
* @about: a #GtkAboutDialog
* @version: (allow-none): the version string
*
* Sets the version string to display in the about dialog.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_version (GtkAboutDialog *about,
const gchar *version)
{
GtkAboutDialogPrivate *priv;
gchar *tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->version;
priv->version = g_strdup (version);
g_free (tmp);
update_name_version (about);
g_object_notify (G_OBJECT (about), "version");
}
/**
* gtk_about_dialog_get_copyright:
* @about: a #GtkAboutDialog
*
* Returns the copyright string.
*
* Return value: The copyright string. The string is owned by the about
* dialog and must not be modified.
*
* Since: 2.6
*/
G_CONST_RETURN gchar *
gtk_about_dialog_get_copyright (GtkAboutDialog *about)
{
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
return about->priv->copyright;
}
/**
* gtk_about_dialog_set_copyright:
* @about: a #GtkAboutDialog
* @copyright: (allow-none) the copyright string
*
* Sets the copyright string to display in the about dialog.
* This should be a short string of one or two lines.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_copyright (GtkAboutDialog *about,
const gchar *copyright)
{
GtkAboutDialogPrivate *priv;
gchar *copyright_string, *tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->copyright;
priv->copyright = g_strdup (copyright);
g_free (tmp);
if (priv->copyright != NULL)
{
copyright_string = g_markup_printf_escaped ("<span size=\"small\">%s</span>",
priv->copyright);
gtk_label_set_markup (GTK_LABEL (priv->copyright_label), copyright_string);
g_free (copyright_string);
gtk_widget_show (priv->copyright_label);
}
else
gtk_widget_hide (priv->copyright_label);
g_object_notify (G_OBJECT (about), "copyright");
}
/**
* gtk_about_dialog_get_comments:
* @about: a #GtkAboutDialog
*
* Returns the comments string.
*
* Return value: The comments. The string is owned by the about
* dialog and must not be modified.
*
* Since: 2.6
*/
G_CONST_RETURN gchar *
gtk_about_dialog_get_comments (GtkAboutDialog *about)
{
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
return about->priv->comments;
}
/**
* gtk_about_dialog_set_comments:
* @about: a #GtkAboutDialog
* @comments: (allow-none): a comments string
*
* Sets the comments string to display in the about dialog.
* This should be a short string of one or two lines.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_comments (GtkAboutDialog *about,
const gchar *comments)
{
GtkAboutDialogPrivate *priv;
gchar *tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->comments;
if (comments)
{
priv->comments = g_strdup (comments);
gtk_label_set_text (GTK_LABEL (priv->comments_label), priv->comments);
gtk_widget_show (priv->comments_label);
}
else
{
priv->comments = NULL;
gtk_widget_hide (priv->comments_label);
}
g_free (tmp);
g_object_notify (G_OBJECT (about), "comments");
}
/**
* gtk_about_dialog_get_license:
* @about: a #GtkAboutDialog
*
* Returns the license information.
*
* Return value: The license information. The string is owned by the about
* dialog and must not be modified.
*
* Since: 2.6
*/
G_CONST_RETURN gchar *
gtk_about_dialog_get_license (GtkAboutDialog *about)
{
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
return about->priv->license;
}
/**
* gtk_about_dialog_set_license:
* @about: a #GtkAboutDialog
* @license: (allow-none): the license information or %NULL
*
* Sets the license information to be displayed in the secondary
* license dialog. If @license is %NULL, the license button is
* hidden.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_license (GtkAboutDialog *about,
const gchar *license)
{
GtkAboutDialogPrivate *priv;
gchar *tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->license;
if (license)
{
priv->license = g_strdup (license);
priv->license_type = GTK_LICENSE_CUSTOM;
gtk_widget_show (priv->license_button);
}
else
{
priv->license = NULL;
priv->license_type = GTK_LICENSE_UNKNOWN;
gtk_widget_hide (priv->license_button);
}
g_free (tmp);
g_object_notify (G_OBJECT (about), "license");
g_object_notify (G_OBJECT (about), "license-type");
}
/**
* gtk_about_dialog_get_wrap_license:
* @about: a #GtkAboutDialog
*
* Returns whether the license text in @about is
* automatically wrapped.
*
* Returns: %TRUE if the license text is wrapped
*
* Since: 2.8
*/
gboolean
gtk_about_dialog_get_wrap_license (GtkAboutDialog *about)
{
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), FALSE);
return about->priv->wrap_license;
}
/**
* gtk_about_dialog_set_wrap_license:
* @about: a #GtkAboutDialog
* @wrap_license: whether to wrap the license
*
* Sets whether the license text in @about is
* automatically wrapped.
*
* Since: 2.8
*/
void
gtk_about_dialog_set_wrap_license (GtkAboutDialog *about,
gboolean wrap_license)
{
GtkAboutDialogPrivate *priv;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
wrap_license = wrap_license != FALSE;
if (priv->wrap_license != wrap_license)
{
priv->wrap_license = wrap_license;
g_object_notify (G_OBJECT (about), "wrap-license");
}
}
/**
* gtk_about_dialog_get_website:
* @about: a #GtkAboutDialog
*
* Returns the website URL.
*
* Return value: The website URL. The string is owned by the about
* dialog and must not be modified.
*
* Since: 2.6
*/
G_CONST_RETURN gchar *
gtk_about_dialog_get_website (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv;
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
priv = about->priv;
return priv->website_url;
}
/**
* gtk_about_dialog_set_website:
* @about: a #GtkAboutDialog
* @website: (allow-none): a URL string starting with "http://"
*
* Sets the URL to use for the website link.
*
* Note that that the hook functions need to be set up
* before calling this function.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_website (GtkAboutDialog *about,
const gchar *website)
{
GtkAboutDialogPrivate *priv;
gchar *tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->website_url;
priv->website_url = g_strdup (website);
g_free (tmp);
update_website (about);
g_object_notify (G_OBJECT (about), "website");
}
/**
* gtk_about_dialog_get_website_label:
* @about: a #GtkAboutDialog
*
* Returns the label used for the website link.
*
* Return value: The label used for the website link. The string is
* owned by the about dialog and must not be modified.
*
* Since: 2.6
*/
G_CONST_RETURN gchar *
gtk_about_dialog_get_website_label (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv;
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
priv = about->priv;
return priv->website_text;
}
/**
* gtk_about_dialog_set_website_label:
* @about: a #GtkAboutDialog
* @website_label: the label used for the website link
*
* Sets the label to be used for the website link.
* It defaults to the website URL.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_website_label (GtkAboutDialog *about,
const gchar *website_label)
{
GtkAboutDialogPrivate *priv;
gchar *tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->website_text;
priv->website_text = g_strdup (website_label);
g_free (tmp);
update_website (about);
g_object_notify (G_OBJECT (about), "website-label");
}
/**
* gtk_about_dialog_get_authors:
* @about: a #GtkAboutDialog
*
* Returns the string which are displayed in the authors tab
* of the secondary credits dialog.
*
* Return value: A %NULL-terminated string array containing
* the authors. The array is owned by the about dialog
* and must not be modified.
*
* Since: 2.6
*/
G_CONST_RETURN gchar * G_CONST_RETURN *
gtk_about_dialog_get_authors (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv;
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
priv = about->priv;
return (const gchar * const *) priv->authors;
}
static void
update_credits_button_visibility (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv = about->priv;
gboolean show;
show = priv->authors != NULL ||
priv->documenters != NULL ||
priv->artists != NULL ||
(priv->translator_credits != NULL &&
strcmp (priv->translator_credits, "translator_credits") &&
strcmp (priv->translator_credits, "translator-credits"));
if (show)
gtk_widget_show (priv->credits_button);
else
gtk_widget_hide (priv->credits_button);
}
/**
* gtk_about_dialog_set_authors:
* @about: a #GtkAboutDialog
* @authors: a %NULL-terminated array of strings
*
* Sets the strings which are displayed in the authors tab
* of the secondary credits dialog.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_authors (GtkAboutDialog *about,
const gchar **authors)
{
GtkAboutDialogPrivate *priv;
gchar **tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->authors;
priv->authors = g_strdupv ((gchar **)authors);
g_strfreev (tmp);
update_credits_button_visibility (about);
g_object_notify (G_OBJECT (about), "authors");
}
/**
* gtk_about_dialog_get_documenters:
* @about: a #GtkAboutDialog
*
* Returns the string which are displayed in the documenters
* tab of the secondary credits dialog.
*
* Return value: A %NULL-terminated string array containing
* the documenters. The array is owned by the about dialog
* and must not be modified.
*
* Since: 2.6
*/
G_CONST_RETURN gchar * G_CONST_RETURN *
gtk_about_dialog_get_documenters (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv;
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
priv = about->priv;
return (const gchar * const *)priv->documenters;
}
/**
* gtk_about_dialog_set_documenters:
* @about: a #GtkAboutDialog
* @documenters: a %NULL-terminated array of strings
*
* Sets the strings which are displayed in the documenters tab
* of the secondary credits dialog.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_documenters (GtkAboutDialog *about,
const gchar **documenters)
{
GtkAboutDialogPrivate *priv;
gchar **tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->documenters;
priv->documenters = g_strdupv ((gchar **)documenters);
g_strfreev (tmp);
update_credits_button_visibility (about);
g_object_notify (G_OBJECT (about), "documenters");
}
/**
* gtk_about_dialog_get_artists:
* @about: a #GtkAboutDialog
*
* Returns the string which are displayed in the artists tab
* of the secondary credits dialog.
*
* Return value: A %NULL-terminated string array containing
* the artists. The array is owned by the about dialog
* and must not be modified.
*
* Since: 2.6
*/
G_CONST_RETURN gchar * G_CONST_RETURN *
gtk_about_dialog_get_artists (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv;
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
priv = about->priv;
return (const gchar * const *)priv->artists;
}
/**
* gtk_about_dialog_set_artists:
* @about: a #GtkAboutDialog
* @artists: a %NULL-terminated array of strings
*
* Sets the strings which are displayed in the artists tab
* of the secondary credits dialog.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_artists (GtkAboutDialog *about,
const gchar **artists)
{
GtkAboutDialogPrivate *priv;
gchar **tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->artists;
priv->artists = g_strdupv ((gchar **)artists);
g_strfreev (tmp);
update_credits_button_visibility (about);
g_object_notify (G_OBJECT (about), "artists");
}
/**
* gtk_about_dialog_get_translator_credits:
* @about: a #GtkAboutDialog
*
* Returns the translator credits string which is displayed
* in the translators tab of the secondary credits dialog.
*
* Return value: The translator credits string. The string is
* owned by the about dialog and must not be modified.
*
* Since: 2.6
*/
G_CONST_RETURN gchar *
gtk_about_dialog_get_translator_credits (GtkAboutDialog *about)
{
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
return about->priv->translator_credits;
}
/**
* gtk_about_dialog_set_translator_credits:
* @about: a #GtkAboutDialog
* @translator_credits: (allow-none): the translator credits
*
* Sets the translator credits string which is displayed in
* the translators tab of the secondary credits dialog.
*
* The intended use for this string is to display the translator
* of the language which is currently used in the user interface.
* Using gettext(), a simple way to achieve that is to mark the
* string for translation:
* |[
* gtk_about_dialog_set_translator_credits (about, _("translator-credits"));
* ]|
* It is a good idea to use the customary msgid "translator-credits" for this
* purpose, since translators will already know the purpose of that msgid, and
* since #GtkAboutDialog will detect if "translator-credits" is untranslated
* and hide the tab.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_translator_credits (GtkAboutDialog *about,
const gchar *translator_credits)
{
GtkAboutDialogPrivate *priv;
gchar *tmp;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
tmp = priv->translator_credits;
priv->translator_credits = g_strdup (translator_credits);
g_free (tmp);
update_credits_button_visibility (about);
g_object_notify (G_OBJECT (about), "translator-credits");
}
/**
* gtk_about_dialog_get_logo:
* @about: a #GtkAboutDialog
*
* Returns the pixbuf displayed as logo in the about dialog.
*
* Return value: the pixbuf displayed as logo. The pixbuf is
* owned by the about dialog. If you want to keep a reference
* to it, you have to call g_object_ref() on it.
*
* Since: 2.6
*/
GdkPixbuf *
gtk_about_dialog_get_logo (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv;
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
priv = about->priv;
if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
return gtk_image_get_pixbuf (GTK_IMAGE (priv->logo_image));
else
return NULL;
}
static GtkIconSet *
icon_set_new_from_pixbufs (GList *pixbufs)
{
GtkIconSet *icon_set = gtk_icon_set_new ();
for (; pixbufs; pixbufs = pixbufs->next)
{
GdkPixbuf *pixbuf = GDK_PIXBUF (pixbufs->data);
GtkIconSource *icon_source = gtk_icon_source_new ();
gtk_icon_source_set_pixbuf (icon_source, pixbuf);
gtk_icon_set_add_source (icon_set, icon_source);
gtk_icon_source_free (icon_source);
}
return icon_set;
}
/**
* gtk_about_dialog_set_logo:
* @about: a #GtkAboutDialog
* @logo: (allow-none): a #GdkPixbuf, or %NULL
*
* Sets the pixbuf to be displayed as logo in the about dialog.
* If it is %NULL, the default window icon set with
* gtk_window_set_default_icon() will be used.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_logo (GtkAboutDialog *about,
GdkPixbuf *logo)
{
GtkAboutDialogPrivate *priv;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
g_object_freeze_notify (G_OBJECT (about));
if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_ICON_NAME)
g_object_notify (G_OBJECT (about), "logo-icon-name");
if (logo != NULL)
gtk_image_set_from_pixbuf (GTK_IMAGE (priv->logo_image), logo);
else
{
GList *pixbufs = gtk_window_get_default_icon_list ();
if (pixbufs != NULL)
{
GtkIconSet *icon_set = icon_set_new_from_pixbufs (pixbufs);
gtk_image_set_from_icon_set (GTK_IMAGE (priv->logo_image),
icon_set, GTK_ICON_SIZE_DIALOG);
gtk_icon_set_unref (icon_set);
g_list_free (pixbufs);
}
}
g_object_notify (G_OBJECT (about), "logo");
g_object_thaw_notify (G_OBJECT (about));
}
/**
* gtk_about_dialog_get_logo_icon_name:
* @about: a #GtkAboutDialog
*
* Returns the icon name displayed as logo in the about dialog.
*
* Return value: the icon name displayed as logo. The string is
* owned by the dialog. If you want to keep a reference
* to it, you have to call g_strdup() on it.
*
* Since: 2.6
*/
G_CONST_RETURN gchar *
gtk_about_dialog_get_logo_icon_name (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv;
const gchar *icon_name = NULL;
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
priv = about->priv;
if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_ICON_NAME)
gtk_image_get_icon_name (GTK_IMAGE (priv->logo_image), &icon_name, NULL);
return icon_name;
}
/**
* gtk_about_dialog_set_logo_icon_name:
* @about: a #GtkAboutDialog
* @icon_name: (allow-none): an icon name, or %NULL
*
* Sets the pixbuf to be displayed as logo in the about dialog.
* If it is %NULL, the default window icon set with
* gtk_window_set_default_icon() will be used.
*
* Since: 2.6
*/
void
gtk_about_dialog_set_logo_icon_name (GtkAboutDialog *about,
const gchar *icon_name)
{
GtkAboutDialogPrivate *priv;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
priv = about->priv;
g_object_freeze_notify (G_OBJECT (about));
if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
g_object_notify (G_OBJECT (about), "logo");
gtk_image_set_from_icon_name (GTK_IMAGE (priv->logo_image), icon_name,
GTK_ICON_SIZE_DIALOG);
g_object_notify (G_OBJECT (about), "logo-icon-name");
g_object_thaw_notify (G_OBJECT (about));
}
static void
follow_if_link (GtkAboutDialog *about,
GtkTextView *text_view,
GtkTextIter *iter)
{
GSList *tags = NULL, *tagp = NULL;
GtkAboutDialogPrivate *priv = about->priv;
gchar *url = NULL;
GtkAboutDialogActivateLinkFunc email_hook, url_hook;
gpointer email_hook_data, url_hook_data;
if (activate_email_hook_set)
{
email_hook = activate_email_hook;
email_hook_data = activate_email_hook_data;
}
else
{
email_hook = default_email_hook;
email_hook_data = NULL;
}
if (activate_url_hook_set)
{
url_hook = activate_url_hook;
url_hook_data = activate_url_hook_data;
}
else
{
url_hook = default_url_hook;
url_hook_data = NULL;
}
tags = gtk_text_iter_get_tags (iter);
for (tagp = tags; tagp != NULL && !url; tagp = tagp->next)
{
GtkTextTag *tag = tagp->data;
if (email_hook != NULL)
{
url = g_object_get_data (G_OBJECT (tag), "email");
if (url)
email_hook (about, url, email_hook_data);
}
if (!url && url_hook != NULL)
{
url = g_object_get_data (G_OBJECT (tag), "url");
if (url)
url_hook (about, url, url_hook_data);
}
if (url && !g_slist_find_custom (priv->visited_links, url, (GCompareFunc)strcmp))
{
GdkColor *style_visited_link_color;
GdkColor color;
gtk_widget_ensure_style (GTK_WIDGET (about));
gtk_widget_style_get (GTK_WIDGET (about),
"visited-link-color", &style_visited_link_color,
NULL);
if (style_visited_link_color)
{
color = *style_visited_link_color;
gdk_color_free (style_visited_link_color);
}
else
color = default_visited_link_color;
g_object_set (G_OBJECT (tag), "foreground-gdk", &color, NULL);
priv->visited_links = g_slist_prepend (priv->visited_links, g_strdup (url));
}
}
if (tags)
g_slist_free (tags);
}
static gboolean
text_view_key_press_event (GtkWidget *text_view,
GdkEventKey *event,
GtkAboutDialog *about)
{
GtkTextIter iter;
GtkTextBuffer *buffer;
switch (event->keyval)
{
case GDK_Return:
case GDK_ISO_Enter:
case GDK_KP_Enter:
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
gtk_text_buffer_get_iter_at_mark (buffer, &iter,
gtk_text_buffer_get_insert (buffer));
follow_if_link (about, GTK_TEXT_VIEW (text_view), &iter);
break;
default:
break;
}
return FALSE;
}
static gboolean
text_view_event_after (GtkWidget *text_view,
GdkEvent *event,
GtkAboutDialog *about)
{
GtkTextIter start, end, iter;
GtkTextBuffer *buffer;
GdkEventButton *button_event;
gint x, y;
if (event->type != GDK_BUTTON_RELEASE)
return FALSE;
button_event = (GdkEventButton *)event;
if (button_event->button != 1)
return FALSE;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
/* we shouldn't follow a link if the user has selected something */
gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
return FALSE;
gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
GTK_TEXT_WINDOW_WIDGET,
button_event->x, button_event->y, &x, &y);
gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y);
follow_if_link (about, GTK_TEXT_VIEW (text_view), &iter);
return FALSE;
}
static void
set_cursor_if_appropriate (GtkAboutDialog *about,
GtkTextView *text_view,
GdkDevice *device,
gint x,
gint y)
{
GtkAboutDialogPrivate *priv = about->priv;
GSList *tags = NULL, *tagp = NULL;
GtkTextIter iter;
gboolean hovering_over_link = FALSE;
gtk_text_view_get_iter_at_location (text_view, &iter, x, y);
tags = gtk_text_iter_get_tags (&iter);
for (tagp = tags; tagp != NULL; tagp = tagp->next)
{
GtkTextTag *tag = tagp->data;
gchar *email = g_object_get_data (G_OBJECT (tag), "email");
gchar *url = g_object_get_data (G_OBJECT (tag), "url");
if (email != NULL || url != NULL)
{
hovering_over_link = TRUE;
break;
}
}
if (hovering_over_link != priv->hovering_over_link)
{
priv->hovering_over_link = hovering_over_link;
if (hovering_over_link)
gdk_window_set_device_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), device, priv->hand_cursor);
else
gdk_window_set_device_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), device, priv->regular_cursor);
}
if (tags)
g_slist_free (tags);
}
static gboolean
text_view_motion_notify_event (GtkWidget *text_view,
GdkEventMotion *event,
GtkAboutDialog *about)
{
gint x, y;
gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
GTK_TEXT_WINDOW_WIDGET,
event->x, event->y, &x, &y);
set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), event->device, x, y);
gdk_event_request_motions (event);
return FALSE;
}
static gboolean
text_view_visibility_notify_event (GtkWidget *text_view,
GdkEventVisibility *event,
GtkAboutDialog *about)
{
GdkDeviceManager *device_manager;
GdkDisplay *display;
GList *devices, *d;
gint wx, wy, bx, by;
display = gdk_drawable_get_display (event->window);
device_manager = gdk_display_get_device_manager (display);
devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
for (d = devices; d; d = d->next)
{
GdkDevice *dev = d->data;
gdk_window_get_device_position (text_view->window, dev, &wx, &wy, NULL);
gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
GTK_TEXT_WINDOW_WIDGET,
wx, wy, &bx, &by);
set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), dev, bx, by);
}
return FALSE;
}
static GtkWidget *
text_view_new (GtkAboutDialog *about,
GtkWidget *dialog,
gchar **strings,
GtkWrapMode wrap_mode)
{
gchar **p;
gchar *q0, *q1, *q2, *r1, *r2;
GtkWidget *view;
GtkTextView *text_view;
GtkTextBuffer *buffer;
gboolean linkify_email, linkify_urls;
GdkColor *style_link_color;
GdkColor *style_visited_link_color;
GdkColor color;
GdkColor link_color;
GdkColor visited_link_color;
GtkAboutDialogPrivate *priv = about->priv;
linkify_email = (!activate_email_hook_set || activate_email_hook != NULL);
linkify_urls = (!activate_url_hook_set || activate_url_hook != NULL);
gtk_widget_ensure_style (GTK_WIDGET (about));
gtk_widget_style_get (GTK_WIDGET (about),
"link-color", &style_link_color,
"visited-link-color", &style_visited_link_color,
NULL);
if (style_link_color)
{
link_color = *style_link_color;
gdk_color_free (style_link_color);
}
else
link_color = default_link_color;
if (style_visited_link_color)
{
visited_link_color = *style_visited_link_color;
gdk_color_free (style_visited_link_color);
}
else
visited_link_color = default_visited_link_color;
view = gtk_text_view_new ();
text_view = GTK_TEXT_VIEW (view);
buffer = gtk_text_view_get_buffer (text_view);
gtk_text_view_set_cursor_visible (text_view, FALSE);
gtk_text_view_set_editable (text_view, FALSE);
gtk_text_view_set_wrap_mode (text_view, wrap_mode);
gtk_text_view_set_left_margin (text_view, 8);
gtk_text_view_set_right_margin (text_view, 8);
g_signal_connect (view, "key-press-event",
G_CALLBACK (text_view_key_press_event), about);
g_signal_connect (view, "event-after",
G_CALLBACK (text_view_event_after), about);
g_signal_connect (view, "motion-notify-event",
G_CALLBACK (text_view_motion_notify_event), about);
g_signal_connect (view, "visibility-notify-event",
G_CALLBACK (text_view_visibility_notify_event), about);
if (strings == NULL)
{
gtk_widget_hide (view);
return view;
}
for (p = strings; *p; p++)
{
q0 = *p;
while (*q0)
{
q1 = linkify_email ? strchr (q0, '<') : NULL;
q2 = q1 ? strchr (q1, '>') : NULL;
r1 = linkify_urls ? strstr (q0, "http://") : NULL;
if (r1)
{
r2 = strpbrk (r1, " \n\t");
if (!r2)
r2 = strchr (r1, '\0');
}
else
r2 = NULL;
if (r1 && r2 && (!q1 || !q2 || (r1 < q1)))
{
q1 = r1;
q2 = r2;
}
if (q1 && q2)
{
GtkTextIter end;
gchar *link;
const gchar *link_type;
GtkTextTag *tag;
if (*q1 == '<')
{
gtk_text_buffer_insert_at_cursor (buffer, q0, (q1 - q0) + 1);
gtk_text_buffer_get_end_iter (buffer, &end);
q1++;
link_type = I_("email");
}
else
{
gtk_text_buffer_insert_at_cursor (buffer, q0, q1 - q0);
gtk_text_buffer_get_end_iter (buffer, &end);
link_type = I_("url");
}
q0 = q2;
link = g_strndup (q1, q2 - q1);
if (g_slist_find_custom (priv->visited_links, link, (GCompareFunc)strcmp))
color = visited_link_color;
else
color = link_color;
tag = gtk_text_buffer_create_tag (buffer, NULL,
"foreground-gdk", &color,
"underline", PANGO_UNDERLINE_SINGLE,
NULL);
g_object_set_data_full (G_OBJECT (tag), link_type, g_strdup (link), g_free);
gtk_text_buffer_insert_with_tags (buffer, &end, link, -1, tag, NULL);
g_free (link);
}
else
{
gtk_text_buffer_insert_at_cursor (buffer, q0, -1);
break;
}
}
if (p[1])
gtk_text_buffer_insert_at_cursor (buffer, "\n", 1);
}
gtk_widget_show (view);
return view;
}
static void
add_credits_page (GtkAboutDialog *about,
GtkWidget *credits_dialog,
GtkWidget *notebook,
gchar *title,
gchar **people)
{
GtkWidget *sw, *view;
view = text_view_new (about, credits_dialog, people, GTK_WRAP_NONE);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add (GTK_CONTAINER (sw), view);
gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
sw, gtk_label_new (title));
}
static void
display_credits_dialog (GtkWidget *button,
gpointer data)
{
GtkAboutDialog *about = (GtkAboutDialog *)data;
GtkAboutDialogPrivate *priv = about->priv;
GtkWidget *dialog, *notebook;
GtkDialog *credits_dialog;
GtkWidget *content_area;
GtkWidget *action_area;
if (priv->credits_dialog != NULL)
{
gtk_window_present (GTK_WINDOW (priv->credits_dialog));
return;
}
dialog = gtk_dialog_new_with_buttons (_("Credits"),
GTK_WINDOW (about),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
NULL);
credits_dialog = GTK_DIALOG (dialog);
content_area = gtk_dialog_get_content_area (credits_dialog);
action_area = gtk_dialog_get_action_area (credits_dialog);
gtk_dialog_set_has_separator (credits_dialog, FALSE);
gtk_container_set_border_width (GTK_CONTAINER (credits_dialog), 5);
gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
priv->credits_dialog = dialog;
gtk_window_set_default_size (GTK_WINDOW (dialog), 360, 260);
gtk_dialog_set_default_response (credits_dialog, GTK_RESPONSE_CANCEL);
gtk_window_set_modal (GTK_WINDOW (dialog),
gtk_window_get_modal (GTK_WINDOW (about)));
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), dialog);
g_signal_connect (dialog, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&(priv->credits_dialog));
notebook = gtk_notebook_new ();
gtk_container_set_border_width (GTK_CONTAINER (notebook), 5);
gtk_box_pack_start (GTK_BOX (content_area), notebook, TRUE, TRUE, 0);
if (priv->authors != NULL)
add_credits_page (about, dialog, notebook, _("Written by"), priv->authors);
if (priv->documenters != NULL)
add_credits_page (about, dialog, notebook, _("Documented by"), priv->documenters);
/* Don't show an untranslated gettext msgid */
if (priv->translator_credits != NULL &&
strcmp (priv->translator_credits, "translator_credits") != 0 &&
strcmp (priv->translator_credits, "translator-credits") != 0)
{
gchar *translators[2];
translators[0] = priv->translator_credits;
translators[1] = NULL;
add_credits_page (about, dialog, notebook, _("Translated by"), translators);
}
if (priv->artists != NULL)
add_credits_page (about, dialog, notebook, _("Artwork by"), priv->artists);
gtk_widget_show_all (dialog);
}
static void
set_policy (GtkWidget *sw)
{
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
}
static void
display_license_dialog (GtkWidget *button,
gpointer data)
{
GtkAboutDialog *about = (GtkAboutDialog *)data;
GtkAboutDialogPrivate *priv = about->priv;
GtkWidget *dialog, *view, *sw;
GtkDialog *license_dialog;
GtkWidget *content_area;
GtkWidget *action_area;
gchar *strings[2];
if (priv->license_dialog != NULL)
{
gtk_window_present (GTK_WINDOW (priv->license_dialog));
return;
}
dialog = gtk_dialog_new_with_buttons (_("License"),
GTK_WINDOW (about),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
NULL);
license_dialog = GTK_DIALOG (dialog);
content_area = gtk_dialog_get_content_area (license_dialog);
action_area = gtk_dialog_get_action_area (license_dialog);
gtk_dialog_set_has_separator (license_dialog, FALSE);
gtk_container_set_border_width (GTK_CONTAINER (license_dialog), 5);
gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
priv->license_dialog = dialog;
gtk_window_set_default_size (GTK_WINDOW (dialog), 420, 320);
gtk_dialog_set_default_response (license_dialog, GTK_RESPONSE_CANCEL);
gtk_window_set_modal (GTK_WINDOW (dialog),
gtk_window_get_modal (GTK_WINDOW (about)));
g_signal_connect (dialog, "response",
G_CALLBACK (gtk_widget_destroy), dialog);
g_signal_connect (dialog, "destroy",
G_CALLBACK (gtk_widget_destroyed),
&(priv->license_dialog));
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_container_set_border_width (GTK_CONTAINER (sw), 5);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_NEVER,
GTK_POLICY_AUTOMATIC);
g_signal_connect (sw, "map", G_CALLBACK (set_policy), NULL);
gtk_box_pack_start (GTK_BOX (content_area), sw, TRUE, TRUE, 0);
strings[0] = priv->license;
strings[1] = NULL;
view = text_view_new (about, dialog, strings,
priv->wrap_license ? GTK_WRAP_WORD : GTK_WRAP_NONE);
gtk_container_add (GTK_CONTAINER (sw), view);
gtk_widget_show_all (dialog);
}
/**
* gtk_about_dialog_new:
*
* Creates a new #GtkAboutDialog.
*
* Returns: a newly created #GtkAboutDialog
*
* Since: 2.6
*/
GtkWidget *
gtk_about_dialog_new (void)
{
GtkAboutDialog *dialog = g_object_new (GTK_TYPE_ABOUT_DIALOG, NULL);
return GTK_WIDGET (dialog);
}
/**
* gtk_about_dialog_set_email_hook:
* @func: a function to call when an email link is activated.
* @data: data to pass to @func
* @destroy: #GDestroyNotify for @data
*
* Installs a global function to be called whenever the user activates an
* email link in an about dialog.
*
* Since 2.18 there exists a default function which uses gtk_show_uri(). To
* deactivate it, you can pass %NULL for @func.
*
* Return value: the previous email hook.
*
* Since: 2.6
*/
GtkAboutDialogActivateLinkFunc
gtk_about_dialog_set_email_hook (GtkAboutDialogActivateLinkFunc func,
gpointer data,
GDestroyNotify destroy)
{
GtkAboutDialogActivateLinkFunc old;
if (activate_email_hook_destroy != NULL)
(* activate_email_hook_destroy) (activate_email_hook_data);
old = activate_email_hook;
activate_email_hook_set = TRUE;
activate_email_hook = func;
activate_email_hook_data = data;
activate_email_hook_destroy = destroy;
return old;
}
/**
* gtk_about_dialog_set_url_hook:
* @func: a function to call when a URL link is activated.
* @data: data to pass to @func
* @destroy: #GDestroyNotify for @data
*
* Installs a global function to be called whenever the user activates a
* URL link in an about dialog.
*
* Since 2.18 there exists a default function which uses gtk_show_uri(). To
* deactivate it, you can pass %NULL for @func.
*
* Return value: the previous URL hook.
*
* Since: 2.6
*/
GtkAboutDialogActivateLinkFunc
gtk_about_dialog_set_url_hook (GtkAboutDialogActivateLinkFunc func,
gpointer data,
GDestroyNotify destroy)
{
GtkAboutDialogActivateLinkFunc old;
if (activate_url_hook_destroy != NULL)
(* activate_url_hook_destroy) (activate_url_hook_data);
old = activate_url_hook;
activate_url_hook_set = TRUE;
activate_url_hook = func;
activate_url_hook_data = data;
activate_url_hook_destroy = destroy;
return old;
}
static void
close_cb (GtkAboutDialog *about)
{
GtkAboutDialogPrivate *priv = about->priv;
if (priv->license_dialog != NULL)
{
gtk_widget_destroy (priv->license_dialog);
priv->license_dialog = NULL;
}
if (priv->credits_dialog != NULL)
{
gtk_widget_destroy (priv->credits_dialog);
priv->credits_dialog = NULL;
}
gtk_widget_hide (GTK_WIDGET (about));
}
/**
* gtk_show_about_dialog:
* @parent: (allow-none): transient parent, or %NULL for none
* @first_property_name: the name of the first property
* @Varargs: value of first property, followed by more properties, %NULL-terminated
*
* This is a convenience function for showing an application's about box.
* The constructed dialog is associated with the parent window and
* reused for future invocations of this function.
*
* Since: 2.6
*/
void
gtk_show_about_dialog (GtkWindow *parent,
const gchar *first_property_name,
...)
{
static GtkWidget *global_about_dialog = NULL;
GtkWidget *dialog = NULL;
va_list var_args;
if (parent)
dialog = g_object_get_data (G_OBJECT (parent), "gtk-about-dialog");
else
dialog = global_about_dialog;
if (!dialog)
{
dialog = gtk_about_dialog_new ();
g_object_ref_sink (dialog);
g_signal_connect (dialog, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), NULL);
/* Close dialog on user response */
g_signal_connect (dialog, "response",
G_CALLBACK (close_cb), NULL);
va_start (var_args, first_property_name);
g_object_set_valist (G_OBJECT (dialog), first_property_name, var_args);
va_end (var_args);
if (parent)
{
gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
g_object_set_data_full (G_OBJECT (parent),
I_("gtk-about-dialog"),
dialog, g_object_unref);
}
else
global_about_dialog = dialog;
}
gtk_window_present (GTK_WINDOW (dialog));
}
/**
* gtk_about_dialog_set_license_type:
* @about: a #GtkAboutDialog
* @license_type: the type of license
*
* Sets the license of the application showing the @about dialog from a
* list of known licenses.
*
* This function overrides the license set using
* gtk_about_dialog_set_license().
*
* Since: 3.0
*/
void
gtk_about_dialog_set_license_type (GtkAboutDialog *about,
GtkLicense license_type)
{
GtkAboutDialogPrivate *priv;
g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
g_return_if_fail (license_type >= GTK_LICENSE_UNKNOWN &&
license_type <= GTK_LICENSE_ARTISTIC);
priv = about->priv;
if (priv->license_type != license_type)
{
g_object_freeze_notify (G_OBJECT (about));
priv->license_type = license_type;
/* custom licenses use the contents of the :license property */
if (priv->license_type != GTK_LICENSE_CUSTOM)
{
const gchar *url;
GString *str;
url = gtk_license_urls[priv->license_type];
if (url == NULL)
url = priv->website_url;
/* compose the new license string as:
*
* <program-name>\n
* <copyright line 1>\n
* ...
* <copyright line n>\n
* \n
* license preamble + URL
*
*/
str = g_string_sized_new (256);
g_string_append (str, priv->name);
g_string_append (str, "\n");
g_string_append (str, priv->copyright);
g_string_append (str, "\n\n");
g_string_append_printf (str, gettext (gtk_license_preamble), url);
g_free (priv->license);
priv->license = g_string_free (str, FALSE);
priv->wrap_license = TRUE;
gtk_widget_show (priv->license_button);
g_object_notify (G_OBJECT (about), "wrap-license");
g_object_notify (G_OBJECT (about), "license");
}
g_object_notify (G_OBJECT (about), "license-type");
g_object_thaw_notify (G_OBJECT (about));
}
}
/**
* gtk_about_dialog_get_license_type:
* @about: a #GtkAboutDialog
*
* Retrieves the license set using gtk_about_dialog_set_license_type()
*
* Return value: a #GtkLicense value
*
* Since: 3.0
*/
GtkLicense
gtk_about_dialog_get_license_type (GtkAboutDialog *about)
{
g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), GTK_LICENSE_UNKNOWN);
return about->priv->license_type;
}