X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkaboutdialog.c;h=6d64f6de0e05012bbc833ffa8a5fb8031a8e75ca;hb=10862a344aa8fb44e6045343ddf65eb0d14cc1b2;hp=c012cffff0118027d6385f26548c7b2157112572;hpb=ce2e7b87980be3490bd2e4fc97b4e24230e2bec1;p=~andy%2Fgtk diff --git a/gtk/gtkaboutdialog.c b/gtk/gtkaboutdialog.c index c012cffff..6d64f6de0 100644 --- a/gtk/gtkaboutdialog.c +++ b/gtk/gtkaboutdialog.c @@ -30,9 +30,9 @@ #include -#include +#include -#include "gtkalias.h" +#include #include "gtkaboutdialog.h" #include "gtkbutton.h" @@ -41,17 +41,21 @@ #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 "gtkviewport.h" #include "gtkiconfactory.h" +#include "gtkprivate.h" #include "gtkintl.h" -#include +#include "gtkalias.h" + +static GdkColor default_link_color = { 0, 0, 0, 0xeeee }; +static GdkColor default_visited_link_color = { 0, 0x5555, 0x1a1a, 0x8b8b }; typedef struct _GtkAboutDialogPrivate GtkAboutDialogPrivate; struct _GtkAboutDialogPrivate @@ -82,7 +86,11 @@ struct _GtkAboutDialogPrivate GdkCursor *hand_cursor; GdkCursor *regular_cursor; - gboolean hovering_over_link; + + GSList *visited_links; + + 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)) @@ -103,7 +111,8 @@ enum PROP_TRANSLATOR_CREDITS, PROP_ARTISTS, PROP_LOGO, - PROP_LOGO_ICON_NAME + PROP_LOGO_ICON_NAME, + PROP_WRAP_LICENSE }; static void gtk_about_dialog_finalize (GObject *object); @@ -119,15 +128,8 @@ static void update_name_version (GtkAboutDialog static GtkIconSet * icon_set_new_from_pixbufs (GList *pixbufs); static void activate_url (GtkWidget *widget, gpointer data); -static void set_link_button_text (GtkWidget *about, - GtkWidget *button, - gchar *text); -static GtkWidget * create_link_button (GtkWidget *about, - gchar *text, - gchar *url, - GCallback callback, - gpointer data); static void follow_if_link (GtkAboutDialog *about, + GtkTextView *text_view, GtkTextIter *iter); static void set_cursor_if_appropriate (GtkAboutDialog *about, GtkTextView *text_view, @@ -153,6 +155,7 @@ static void display_credits_dialog (GtkWidget gpointer data); static void display_license_dialog (GtkWidget *button, gpointer data); +static void close_cb (GtkAboutDialog *about); static GtkAboutDialogActivateLinkFunc activate_email_hook = NULL; @@ -163,24 +166,23 @@ static GtkAboutDialogActivateLinkFunc activate_url_hook = NULL; static gpointer activate_url_hook_data = NULL; static GDestroyNotify activate_url_hook_destroy = NULL; -G_DEFINE_TYPE (GtkAboutDialog, gtk_about_dialog, GTK_TYPE_DIALOG); +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; - GtkDialogClass *dialog_class; object_class = (GObjectClass *)klass; widget_class = (GtkWidgetClass *)klass; - dialog_class = (GtkDialogClass *)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; + /** * GtkAboutDialog:name: * @@ -195,7 +197,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) P_("Program name"), P_("The name of the program. If this is not set, it defaults to g_get_application_name()"), NULL, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkAboutDialog:version: @@ -210,7 +212,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) P_("Program version"), P_("The version of the program"), NULL, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkAboutDialog:copyright: @@ -225,7 +227,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) P_("Copyright string"), P_("Copyright information for the program"), NULL, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** @@ -243,15 +245,16 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) P_("Comments string"), P_("Comments about the program"), NULL, - G_PARAM_READWRITE)); + 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 not wrapped - * in the text view, thus it must contain the intended linebreaks. + * 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. * * Since: 2.6 */ @@ -261,7 +264,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) _("License"), _("The license of the program"), NULL, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkAboutDialog:website: @@ -277,7 +280,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) P_("Website URL"), P_("The URL for the link to the website of the program"), NULL, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkAboutDialog:website-label: @@ -290,11 +293,11 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) */ g_object_class_install_property (object_class, PROP_WEBSITE_LABEL, - g_param_spec_string ("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, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkAboutDialog:authors: @@ -311,7 +314,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) P_("Authors"), P_("List of authors of the program"), G_TYPE_STRV, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkAboutDialog:documenters: @@ -328,7 +331,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) P_("Documenters"), P_("List of people documenting the program"), G_TYPE_STRV, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkAboutDialog:artists: @@ -345,7 +348,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) P_("Artists"), P_("List of people who have contributed artwork to the program"), G_TYPE_STRV, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** @@ -359,11 +362,11 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) */ g_object_class_install_property (object_class, PROP_TRANSLATOR_CREDITS, - g_param_spec_string ("translator_credits", + g_param_spec_string ("translator-credits", P_("Translator credits"), P_("Credits to the translators. This string should be marked as translatable"), NULL, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkAboutDialog:logo: @@ -379,7 +382,7 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) 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, - G_PARAM_READWRITE)); + GTK_PARAM_READWRITE)); /** * GtkAboutDialog:logo-icon-name: @@ -391,19 +394,26 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) */ g_object_class_install_property (object_class, PROP_LOGO_ICON_NAME, - g_param_spec_string ("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, - G_PARAM_READWRITE)); + 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)); - /* Style properties */ - gtk_widget_class_install_style_property (widget_class, - g_param_spec_boxed ("link_color", - P_("Link Color"), - P_("Color of hyperlinks"), - GDK_TYPE_COLOR, - G_PARAM_READABLE)); g_type_class_add_private (object_class, sizeof (GtkAboutDialogPrivate)); } @@ -411,8 +421,9 @@ gtk_about_dialog_class_init (GtkAboutDialogClass *klass) static void gtk_about_dialog_init (GtkAboutDialog *about) { + GtkDialog *dialog = GTK_DIALOG (about); GtkAboutDialogPrivate *priv; - GtkWidget *vbox, *hbox, *button; + GtkWidget *vbox, *hbox, *button, *close_button, *image; /* Data */ priv = GTK_ABOUT_DIALOG_GET_PRIVATE (about); @@ -433,15 +444,19 @@ gtk_about_dialog_init (GtkAboutDialog *about) 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; + + gtk_dialog_set_has_separator (dialog, FALSE); + gtk_container_set_border_width (GTK_CONTAINER (dialog), 5); + gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */ + gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5); - gtk_dialog_set_has_separator (GTK_DIALOG (about), FALSE); - /* Widgets */ gtk_widget_push_composite_child (); - vbox = gtk_vbox_new (FALSE, 8); - gtk_container_set_border_width (GTK_CONTAINER (vbox), 8); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (about)->vbox), vbox, TRUE, TRUE, 0); + vbox = gtk_vbox_new (FALSE, 8); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + gtk_box_pack_start (GTK_BOX (dialog->vbox), vbox, TRUE, TRUE, 0); priv->logo_image = gtk_image_new (); gtk_box_pack_start (GTK_BOX (vbox), priv->logo_image, FALSE, FALSE, 0); @@ -462,8 +477,9 @@ gtk_about_dialog_init (GtkAboutDialog *about) 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); - button = create_link_button (GTK_WIDGET (about), "", "", - G_CALLBACK (activate_url), about); + button = gtk_link_button_new (""); + g_signal_connect (G_OBJECT (button), "clicked", + G_CALLBACK (activate_url), about); hbox = gtk_hbox_new (TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); @@ -476,11 +492,16 @@ gtk_about_dialog_init (GtkAboutDialog *about) gtk_widget_show (hbox); /* Add the OK 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); + 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_from_stock (_("C_redits")); + button = gtk_button_new_with_mnemonic (_("C_redits")); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + 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 (GTK_DIALOG (about)->action_area), button, FALSE, TRUE, 0); gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (GTK_DIALOG (about)->action_area), button, TRUE); @@ -490,6 +511,8 @@ gtk_about_dialog_init (GtkAboutDialog *about) /* Add the license button */ button = gtk_button_new_from_stock (_("_License")); + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_widget_set_no_show_all (button, TRUE); gtk_box_pack_end (GTK_BOX (GTK_DIALOG (about)->action_area), button, FALSE, TRUE, 0); gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (GTK_DIALOG (about)->action_area), button, TRUE); @@ -500,6 +523,13 @@ gtk_about_dialog_init (GtkAboutDialog *about) 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_name (about, NULL); + gtk_about_dialog_set_logo (about, NULL); } static void @@ -521,8 +551,11 @@ gtk_about_dialog_finalize (GObject *object) 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); + gdk_cursor_unref (priv->regular_cursor); G_OBJECT_CLASS (gtk_about_dialog_parent_class)->finalize (object); } @@ -534,6 +567,7 @@ gtk_about_dialog_set_property (GObject *object, GParamSpec *pspec) { GtkAboutDialog *about = GTK_ABOUT_DIALOG (object); + GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data; switch (prop_id) { @@ -576,6 +610,9 @@ gtk_about_dialog_set_property (GObject *object, 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; @@ -643,6 +680,9 @@ gtk_about_dialog_get_property (GObject *object, 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; @@ -769,8 +809,8 @@ gtk_about_dialog_set_version (GtkAboutDialog *about, priv = (GtkAboutDialogPrivate *)about->private_data; tmp = priv->version; - priv->version = version ? g_strdup (version) : NULL; - g_free (tmp); + priv->version = g_strdup (version); + g_free (tmp); update_name_version (about); @@ -822,7 +862,7 @@ gtk_about_dialog_set_copyright (GtkAboutDialog *about, priv = (GtkAboutDialogPrivate *)about->private_data; tmp = priv->copyright; - priv->copyright = copyright ? g_strdup (copyright) : NULL; + priv->copyright = g_strdup (copyright); g_free (tmp); if (priv->copyright != NULL) @@ -963,6 +1003,59 @@ gtk_about_dialog_set_license (GtkAboutDialog *about, g_object_notify (G_OBJECT (about), "license"); } +/** + * 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) +{ + GtkAboutDialogPrivate *priv; + + g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), FALSE); + + priv = (GtkAboutDialogPrivate *)about->private_data; + + return 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 = (GtkAboutDialogPrivate *)about->private_data; + + 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 @@ -1012,8 +1105,7 @@ gtk_about_dialog_set_website (GtkAboutDialog *about, priv->website = g_strdup (website); if (activate_url_hook != NULL) { - g_object_set_data_full (G_OBJECT (priv->website_button), - "url", g_strdup (website), g_free); + gtk_link_button_set_uri (GTK_LINK_BUTTON (priv->website_button), website); if (priv->website_label == NULL) gtk_about_dialog_set_website_label (about, website); } @@ -1030,7 +1122,6 @@ gtk_about_dialog_set_website (GtkAboutDialog *about, else { priv->website = NULL; - g_object_set_data (G_OBJECT (priv->website_button), "url", NULL); gtk_widget_hide (priv->website_button); } g_free (tmp); @@ -1088,8 +1179,7 @@ gtk_about_dialog_set_website_label (GtkAboutDialog *about, if (website_label != NULL) { priv->website_label = g_strdup (website_label); - set_link_button_text (GTK_WIDGET (about), - priv->website_button, + gtk_button_set_label (GTK_BUTTON (priv->website_button), priv->website_label); gtk_widget_show (priv->website_button); } @@ -1101,7 +1191,7 @@ gtk_about_dialog_set_website_label (GtkAboutDialog *about, } g_free (tmp); - g_object_notify (G_OBJECT (about), "website_label"); + g_object_notify (G_OBJECT (about), "website-label"); } /** @@ -1129,6 +1219,24 @@ gtk_about_dialog_get_authors (GtkAboutDialog *about) return (const gchar * const *) priv->authors; } +static void +update_credits_button_visibility (GtkAboutDialog *about) +{ + GtkAboutDialogPrivate *priv = about->private_data; + 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 @@ -1154,8 +1262,7 @@ gtk_about_dialog_set_authors (GtkAboutDialog *about, priv->authors = g_strdupv ((gchar **)authors); g_strfreev (tmp); - if (priv->authors != NULL) - gtk_widget_show (priv->credits_button); + update_credits_button_visibility (about); g_object_notify (G_OBJECT (about), "authors"); } @@ -1210,8 +1317,7 @@ gtk_about_dialog_set_documenters (GtkAboutDialog *about, priv->documenters = g_strdupv ((gchar **)documenters); g_strfreev (tmp); - if (priv->documenters != NULL) - gtk_widget_show (priv->credits_button); + update_credits_button_visibility (about); g_object_notify (G_OBJECT (about), "documenters"); } @@ -1266,8 +1372,7 @@ gtk_about_dialog_set_artists (GtkAboutDialog *about, priv->artists = g_strdupv ((gchar **)artists); g_strfreev (tmp); - if (priv->artists != NULL) - gtk_widget_show (priv->credits_button); + update_credits_button_visibility (about); g_object_notify (G_OBJECT (about), "artists"); } @@ -1333,8 +1438,7 @@ gtk_about_dialog_set_translator_credits (GtkAboutDialog *about, priv->translator_credits = g_strdup (translator_credits); g_free (tmp); - if (priv->translator_credits != NULL) - gtk_widget_show (priv->credits_button); + update_credits_button_visibility (about); g_object_notify (G_OBJECT (about), "translator-credits"); } @@ -1409,7 +1513,7 @@ gtk_about_dialog_set_logo (GtkAboutDialog *about, 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"); + g_object_notify (G_OBJECT (about), "logo-icon-name"); if (logo != NULL) gtk_image_set_from_pixbuf (GTK_IMAGE (priv->logo_image), logo); @@ -1491,7 +1595,7 @@ gtk_about_dialog_set_logo_icon_name (GtkAboutDialog *about, 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_notify (G_OBJECT (about), "logo-icon-name"); g_object_thaw_notify (G_OBJECT (about)); } @@ -1501,83 +1605,61 @@ activate_url (GtkWidget *widget, gpointer data) { GtkAboutDialog *about = GTK_ABOUT_DIALOG (data); - gchar *url = g_object_get_data (G_OBJECT (widget), "url"); + const gchar *url = gtk_link_button_get_uri (GTK_LINK_BUTTON (widget)); if (activate_url_hook != NULL) (* activate_url_hook) (about, url, activate_url_hook_data); } -static void -set_link_button_text (GtkWidget *about, - GtkWidget *button, - gchar *text) -{ - GtkWidget *label; - gchar *link; - GdkColor *style_link_color; - GdkColor link_color = { 0, 0, 0, 0xffff }; - - gtk_widget_ensure_style (about); - gtk_widget_style_get (about, "link_color", &style_link_color, NULL); - if (style_link_color) - { - link_color = *style_link_color; - gdk_color_free (style_link_color); - } - - link = g_markup_printf_escaped ("%s", - link_color.red, link_color.green, link_color.blue, text); - - label = gtk_bin_get_child (GTK_BIN (button)); - gtk_label_set_markup (GTK_LABEL (label), link); - g_free (link); -} - -static GtkWidget * -create_link_button (GtkWidget *about, - gchar *text, - gchar *url, - GCallback callback, - gpointer data) -{ - GtkWidget *button; - - button = gtk_button_new_with_label (""); - GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT); - gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE); - - g_object_set_data_full (G_OBJECT (button), "url", g_strdup (url), g_free); - set_link_button_text (about, button, text); - - g_signal_connect (button, "clicked", callback, data); - - return button; -} - static void follow_if_link (GtkAboutDialog *about, + GtkTextView *text_view, GtkTextIter *iter) { GSList *tags = NULL, *tagp = NULL; + GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data; + gchar *url = NULL; tags = gtk_text_iter_get_tags (iter); - for (tagp = tags; tagp != NULL; tagp = tagp->next) + for (tagp = tags; tagp != NULL && !url; 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 && activate_email_hook != NULL) + if (activate_email_hook != NULL) { - (* activate_email_hook) (about, email, activate_email_hook_data); - break; + url = g_object_get_data (G_OBJECT (tag), "email"); + if (url) + (* activate_email_hook) (about, url, activate_email_hook_data); } - if (url != NULL && activate_url_hook != NULL) + if (!url && activate_url_hook != NULL) { - (* activate_url_hook) (about, url, activate_url_hook_data); - break; + url = g_object_get_data (G_OBJECT (tag), "url"); + if (url) + (* activate_url_hook) (about, url, activate_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) @@ -1599,7 +1681,7 @@ credits_key_press_event (GtkWidget *text_view, 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, &iter); + follow_if_link (about, GTK_TEXT_VIEW (text_view), &iter); break; default: @@ -1640,7 +1722,7 @@ credits_event_after (GtkWidget *text_view, gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y); - follow_if_link (about, &iter); + follow_if_link (about, GTK_TEXT_VIEW (text_view), &iter); return FALSE; } @@ -1653,12 +1735,9 @@ set_cursor_if_appropriate (GtkAboutDialog *about, { GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data; GSList *tags = NULL, *tagp = NULL; - GtkTextBuffer *buffer; GtkTextIter iter; gboolean hovering_over_link = FALSE; - buffer = gtk_text_view_get_buffer (text_view); - gtk_text_view_get_iter_at_location (text_view, &iter, x, y); tags = gtk_text_iter_get_tags (&iter); @@ -1702,7 +1781,7 @@ credits_motion_notify_event (GtkWidget *text_view, set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), x, y); - gdk_window_get_pointer (text_view->window, NULL, NULL, NULL); + gdk_event_request_motions (event); return FALSE; } @@ -1727,7 +1806,9 @@ credits_visibility_notify_event (GtkWidget *text_view, } static void -text_view_style_set (GtkWidget *widget, GtkStyle *prev_style, GtkWidget *text_view) +text_view_style_set (GtkWidget *widget, + GtkStyle *prev_style, + GtkWidget *text_view) { gtk_widget_modify_base (text_view, GTK_STATE_NORMAL, &widget->style->bg[GTK_STATE_NORMAL]); @@ -1745,39 +1826,59 @@ add_credits_page (GtkAboutDialog *about, GtkTextBuffer *buffer; gboolean linkify_email, linkify_urls; GdkColor *style_link_color; - GdkColor link_color = { 0, 0, 0, 0xffff }; - + GdkColor *style_visited_link_color; + GdkColor color; + GdkColor link_color; + GdkColor visited_link_color; + GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data; + linkify_email = (activate_email_hook != NULL); linkify_urls = (activate_url_hook != NULL); gtk_widget_ensure_style (GTK_WIDGET (about)); - gtk_widget_style_get (GTK_WIDGET (about), "link_color", &style_link_color, NULL); + 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 (); - g_signal_connect (about, "style_set", - G_CALLBACK (text_view_style_set), view); + g_signal_connect_object (about, "style_set", + G_CALLBACK (text_view_style_set), view, 0); buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)); gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE); gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE); + gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 8); gtk_text_view_set_right_margin (GTK_TEXT_VIEW (view), 8); - g_signal_connect (view, "key-press-event", + g_signal_connect (view, "key_press_event", G_CALLBACK (credits_key_press_event), about); - g_signal_connect (view, "event-after", + g_signal_connect (view, "event_after", G_CALLBACK (credits_event_after), about); - g_signal_connect (view, "motion-notify-event", + g_signal_connect (view, "motion_notify_event", G_CALLBACK (credits_motion_notify_event), about); - g_signal_connect (view, "visibility-notify-event", + g_signal_connect (view, "visibility_notify_event", G_CALLBACK (credits_visibility_notify_event), about); 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); @@ -1821,7 +1922,7 @@ add_credits_page (GtkAboutDialog *about, { GtkTextIter end; gchar *link; - gchar *link_type; + const gchar *link_type; GtkTextTag *tag; gtk_text_buffer_insert_at_cursor (buffer, q0, q1 - q0); @@ -1833,19 +1934,25 @@ add_credits_page (GtkAboutDialog *about, { q1++; q0++; - link_type = "email"; + link_type = I_("email"); } else - link_type = "url"; + link_type = I_("url"); 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", &link_color, + "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 @@ -1867,6 +1974,7 @@ display_credits_dialog (GtkWidget *button, GtkAboutDialog *about = (GtkAboutDialog *)data; GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data; GtkWidget *dialog, *notebook; + GtkDialog *credits_dialog; if (priv->credits_dialog != NULL) { @@ -1877,13 +1985,17 @@ display_credits_dialog (GtkWidget *button, dialog = gtk_dialog_new_with_buttons (_("Credits"), GTK_WINDOW (about), GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, + GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL, NULL); - gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); - + credits_dialog = GTK_DIALOG (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 (credits_dialog->vbox), 2); /* 2 * 5 + 2 = 12 */ + gtk_container_set_border_width (GTK_CONTAINER (credits_dialog->action_area), 5); + 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_default_response (credits_dialog, GTK_RESPONSE_CANCEL); gtk_window_set_modal (GTK_WINDOW (dialog), gtk_window_get_modal (GTK_WINDOW (about))); @@ -1895,7 +2007,7 @@ display_credits_dialog (GtkWidget *button, &(priv->credits_dialog)); notebook = gtk_notebook_new (); - gtk_container_set_border_width (GTK_CONTAINER (notebook), 8); + gtk_container_set_border_width (GTK_CONTAINER (notebook), 5); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), notebook, TRUE, TRUE, 0); if (priv->authors != NULL) @@ -1923,6 +2035,14 @@ display_credits_dialog (GtkWidget *button, 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) @@ -1930,6 +2050,7 @@ display_license_dialog (GtkWidget *button, GtkAboutDialog *about = (GtkAboutDialog *)data; GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data; GtkWidget *dialog, *view, *sw; + GtkDialog *licence_dialog; if (priv->license_dialog != NULL) { @@ -1940,12 +2061,17 @@ display_license_dialog (GtkWidget *button, dialog = gtk_dialog_new_with_buttons (_("License"), GTK_WINDOW (about), GTK_DIALOG_DESTROY_WITH_PARENT, - GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, + GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL, NULL); - gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); + licence_dialog = GTK_DIALOG (dialog); + gtk_dialog_set_has_separator (licence_dialog, FALSE); + gtk_container_set_border_width (GTK_CONTAINER (licence_dialog), 5); + gtk_box_set_spacing (GTK_BOX (licence_dialog->vbox), 2); /* 2 * 5 + 2 = 12 */ + gtk_container_set_border_width (GTK_CONTAINER (licence_dialog->action_area), 5); + priv->license_dialog = dialog; gtk_window_set_default_size (GTK_WINDOW (dialog), 420, 320); - gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE); + gtk_dialog_set_default_response (licence_dialog, GTK_RESPONSE_CANCEL); gtk_window_set_modal (GTK_WINDOW (dialog), gtk_window_get_modal (GTK_WINDOW (about))); @@ -1957,21 +2083,24 @@ display_license_dialog (GtkWidget *button, &(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_container_set_border_width (GTK_CONTAINER (sw), 8); gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), sw, TRUE, TRUE, 0); view = gtk_text_view_new (); + gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (view), + priv->wrap_license ? GTK_WRAP_WORD : GTK_WRAP_NONE); gtk_text_buffer_set_text (gtk_text_view_get_buffer (GTK_TEXT_VIEW (view)), priv->license, -1); gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (view), FALSE); gtk_text_view_set_editable (GTK_TEXT_VIEW (view), FALSE); + gtk_text_view_set_left_margin (GTK_TEXT_VIEW (view), 8); gtk_text_view_set_right_margin (GTK_TEXT_VIEW (view), 8); @@ -1980,27 +2109,6 @@ display_license_dialog (GtkWidget *button, gtk_widget_show_all (dialog); } -static void -close_cb (GtkAboutDialog *about) -{ - GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data; - - 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_about_dialog_new: * @@ -2015,16 +2123,6 @@ gtk_about_dialog_new (void) { GtkAboutDialog *dialog = g_object_new (GTK_TYPE_ABOUT_DIALOG, NULL); - /* force defaults */ - gtk_about_dialog_set_name (dialog, NULL); - gtk_about_dialog_set_logo (dialog, NULL); - - /* Close dialog on user response */ - g_signal_connect (dialog, - "response", - G_CALLBACK (close_cb), - NULL); - return GTK_WIDGET (dialog); } @@ -2092,6 +2190,27 @@ gtk_about_dialog_set_url_hook (GtkAboutDialogActivateLinkFunc func, return old; } +static void +close_cb (GtkAboutDialog *about) +{ + GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data; + + 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: transient parent, or %NULL for none @@ -2122,11 +2241,13 @@ gtk_show_about_dialog (GtkWindow *parent, { dialog = gtk_about_dialog_new (); - g_object_ref (dialog); - gtk_object_sink (GTK_OBJECT (dialog)); + 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); @@ -2135,7 +2256,8 @@ gtk_show_about_dialog (GtkWindow *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), "gtk-about-dialog", + g_object_set_data_full (G_OBJECT (parent), + I_("gtk-about-dialog"), dialog, g_object_unref); } else @@ -2145,3 +2267,6 @@ gtk_show_about_dialog (GtkWindow *parent, gtk_window_present (GTK_WINDOW (dialog)); } + +#define __GTK_ABOUT_DIALOG_C__ +#include "gtkaliasdef.c"