]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkaboutdialog.c
Fix a compiler warning.
[~andy/gtk] / gtk / gtkaboutdialog.c
index c012cffff0118027d6385f26548c7b2157112572..6d64f6de0e05012bbc833ffa8a5fb8031a8e75ca 100644 (file)
@@ -30,9 +30,9 @@
 
 #include <config.h>
 
-#include <gdk/gdkkeysyms.h>
+#include <string.h>
 
-#include "gtkalias.h"
+#include <gdk/gdkkeysyms.h>
 
 #include "gtkaboutdialog.h"
 #include "gtkbutton.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 "gtkviewport.h"
 #include "gtkiconfactory.h"
+#include "gtkprivate.h"
 #include "gtkintl.h"
 
-#include <string.h>
+#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 ("<span foreground=\"#%04x%04x%04x\" underline=\"single\">%s</span>", 
-                                 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"