]> Pileus Git - ~andy/gtk/blob - gtk/gtkaboutdialog.c
Merge branch 'master' into client-side-windows
[~andy/gtk] / gtk / gtkaboutdialog.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 2001 CodeFactory AB
3  * Copyright (C) 2001, 2002 Anders Carlsson
4  * Copyright (C) 2003, 2004 Matthias Clasen <mclasen@redhat.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public 
8  * License as published by the Free Software Foundation; either 
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the 
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /*
23  * Author: Anders Carlsson <andersca@gnome.org>
24  *
25  * Modified by the GTK+ Team and others 1997-2004.  See the AUTHORS
26  * file for a list of people on the GTK+ Team.  See the ChangeLog
27  * files for a list of changes.  These files are distributed with
28  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
29  */
30
31 #include "config.h"
32
33 #include <string.h>
34
35 #include <gdk/gdkkeysyms.h>
36
37 #include "gtkaboutdialog.h"
38 #include "gtkbutton.h"
39 #include "gtkbbox.h"
40 #include "gtkdialog.h"
41 #include "gtkhbox.h"
42 #include "gtkimage.h"
43 #include "gtklabel.h"
44 #include "gtklinkbutton.h"
45 #include "gtkmarshalers.h"
46 #include "gtknotebook.h"
47 #include "gtkscrolledwindow.h"
48 #include "gtkstock.h"
49 #include "gtktextview.h"
50 #include "gtkvbox.h"
51 #include "gtkiconfactory.h"
52 #include "gtkshow.h"
53 #include "gtkmain.h"
54 #include "gtkmessagedialog.h"
55 #include "gtkprivate.h"
56 #include "gtkintl.h"
57
58 #include "gtkalias.h"
59
60 static GdkColor default_link_color = { 0, 0, 0, 0xeeee };
61 static GdkColor default_visited_link_color = { 0, 0x5555, 0x1a1a, 0x8b8b };
62
63 typedef struct _GtkAboutDialogPrivate GtkAboutDialogPrivate;
64 struct _GtkAboutDialogPrivate 
65 {
66   gchar *name;
67   gchar *version;
68   gchar *copyright;
69   gchar *comments;
70   gchar *website_url;
71   gchar *website_text;
72   gchar *translator_credits;
73   gchar *license;
74   
75   gchar **authors;
76   gchar **documenters;
77   gchar **artists;
78   
79   GtkWidget *logo_image;
80   GtkWidget *name_label;
81   GtkWidget *comments_label;
82   GtkWidget *copyright_label;
83   GtkWidget *website_button;
84   GtkWidget *website_label;
85
86   GtkWidget *credits_button;
87   GtkWidget *credits_dialog;
88   GtkWidget *license_button;
89   GtkWidget *license_dialog;
90   
91   GdkCursor *hand_cursor;
92   GdkCursor *regular_cursor;
93   
94   GSList *visited_links;
95
96   guint hovering_over_link : 1;
97   guint wrap_license : 1;
98 };
99
100 #define GTK_ABOUT_DIALOG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ABOUT_DIALOG, GtkAboutDialogPrivate))
101
102
103 enum 
104 {
105   PROP_0,
106   PROP_NAME,
107   PROP_VERSION,
108   PROP_COPYRIGHT,
109   PROP_COMMENTS,
110   PROP_WEBSITE,
111   PROP_WEBSITE_LABEL,
112   PROP_LICENSE,
113   PROP_AUTHORS,
114   PROP_DOCUMENTERS,
115   PROP_TRANSLATOR_CREDITS,
116   PROP_ARTISTS,
117   PROP_LOGO,
118   PROP_LOGO_ICON_NAME,
119   PROP_WRAP_LICENSE
120 };
121
122 static void                 gtk_about_dialog_finalize       (GObject            *object);
123 static void                 gtk_about_dialog_get_property   (GObject            *object,
124                                                              guint               prop_id,
125                                                              GValue             *value,
126                                                              GParamSpec         *pspec);
127 static void                 gtk_about_dialog_set_property   (GObject            *object,
128                                                              guint               prop_id,
129                                                              const GValue       *value,
130                                                              GParamSpec         *pspec);
131 static void                 gtk_about_dialog_show           (GtkWidget          *widge);
132 static void                 update_name_version             (GtkAboutDialog     *about);
133 static GtkIconSet *         icon_set_new_from_pixbufs       (GList              *pixbufs);
134 static void                 activate_url                    (GtkWidget          *widget,
135                                                              gpointer            data);
136 static void                 follow_if_link                  (GtkAboutDialog     *about,
137                                                              GtkTextView        *text_view,
138                                                              GtkTextIter        *iter);
139 static void                 set_cursor_if_appropriate       (GtkAboutDialog     *about,
140                                                              GtkTextView        *text_view,
141                                                              gint                x,
142                                                              gint                y);
143 static void                 display_credits_dialog          (GtkWidget          *button,
144                                                              gpointer            data);
145 static void                 display_license_dialog          (GtkWidget          *button,
146                                                              gpointer            data);
147 static void                 close_cb                        (GtkAboutDialog     *about);
148 static void                 default_url_hook                (GtkAboutDialog     *about,
149                                                              const gchar        *uri,
150                                                              gpointer            user_data);
151 static void                 default_email_hook              (GtkAboutDialog     *about,
152                                                              const gchar        *email_address,
153                                                              gpointer            user_data);
154
155 static gboolean activate_email_hook_set = FALSE;
156 static GtkAboutDialogActivateLinkFunc activate_email_hook = NULL;
157 static gpointer activate_email_hook_data = NULL;
158 static GDestroyNotify activate_email_hook_destroy = NULL;
159
160 static gboolean activate_url_hook_set = FALSE;
161 static GtkAboutDialogActivateLinkFunc activate_url_hook = NULL;
162 static gpointer activate_url_hook_data = NULL;
163 static GDestroyNotify activate_url_hook_destroy = NULL;
164
165 static void
166 default_url_hook (GtkAboutDialog *about,
167                   const gchar *uri,
168                   gpointer user_data G_GNUC_UNUSED)
169 {
170   GdkScreen *screen;
171   GError *error = NULL;
172
173   screen = gtk_widget_get_screen (GTK_WIDGET (about));
174
175   if (!gtk_show_uri (screen, uri, gtk_get_current_event_time (), &error)) {
176     GtkWidget *dialog;
177
178     dialog = gtk_message_dialog_new (GTK_WINDOW (about),
179                                      GTK_DIALOG_DESTROY_WITH_PARENT |
180                                      GTK_DIALOG_MODAL,
181                                      GTK_MESSAGE_ERROR,
182                                      GTK_BUTTONS_CLOSE,
183                                      "%s", _("Could not show link"));
184     gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
185                                               "%s", error->message);
186     g_error_free (error);
187
188     g_signal_connect (dialog, "response",
189                       G_CALLBACK (gtk_widget_destroy), NULL);
190
191     gtk_window_present (GTK_WINDOW (dialog));
192   }
193 }
194
195 static void
196 default_email_hook (GtkAboutDialog *about,
197                     const gchar *email_address,
198                     gpointer user_data)
199 {
200   char *escaped, *uri;
201
202   escaped = g_uri_escape_string (email_address, NULL, FALSE);
203   uri = g_strdup_printf ("mailto:%s", escaped);
204   g_free (escaped);
205
206   default_url_hook (about, uri, user_data);
207   g_free (uri);
208 }
209
210 G_DEFINE_TYPE (GtkAboutDialog, gtk_about_dialog, GTK_TYPE_DIALOG)
211
212 static void
213 gtk_about_dialog_class_init (GtkAboutDialogClass *klass)
214 {
215   GObjectClass *object_class;
216   GtkWidgetClass *widget_class;
217         
218   object_class = (GObjectClass *)klass;
219   widget_class = (GtkWidgetClass *)klass;
220         
221   object_class->set_property = gtk_about_dialog_set_property;
222   object_class->get_property = gtk_about_dialog_get_property;
223
224   object_class->finalize = gtk_about_dialog_finalize;
225
226   widget_class->show = gtk_about_dialog_show;
227
228   /**
229    * GtkAboutDialog:program-name:
230    *
231    * The name of the program. 
232    * If this is not set, it defaults to g_get_application_name().
233    *
234    * Since: 2.12
235    */  
236   g_object_class_install_property (object_class,
237                                    PROP_NAME,
238                                    g_param_spec_string ("program-name",
239                                                         P_("Program name"),
240                                                         P_("The name of the program. If this is not set, it defaults to g_get_application_name()"),
241                                                         NULL,
242                                                         GTK_PARAM_READWRITE));
243
244   /**
245    * GtkAboutDialog:version:
246    *
247    * The version of the program. 
248    *
249    * Since: 2.6
250    */  
251   g_object_class_install_property (object_class,
252                                    PROP_VERSION,
253                                    g_param_spec_string ("version",
254                                                         P_("Program version"),
255                                                         P_("The version of the program"),
256                                                         NULL,
257                                                         GTK_PARAM_READWRITE));
258
259   /**
260    * GtkAboutDialog:copyright:
261    *
262    * Copyright information for the program. 
263    *
264    * Since: 2.6
265    */  
266   g_object_class_install_property (object_class,
267                                    PROP_COPYRIGHT,
268                                    g_param_spec_string ("copyright",
269                                                         P_("Copyright string"),
270                                                         P_("Copyright information for the program"),
271                                                         NULL,
272                                                         GTK_PARAM_READWRITE));
273         
274
275   /**
276    * GtkAboutDialog:comments:
277    *
278    * Comments about the program. This string is displayed in a label 
279    * in the main dialog, thus it should be a short explanation of
280    * the main purpose of the program, not a detailed list of features.
281    *
282    * Since: 2.6
283    */  
284   g_object_class_install_property (object_class,
285                                    PROP_COMMENTS,
286                                    g_param_spec_string ("comments",
287                                                         P_("Comments string"),
288                                                         P_("Comments about the program"),
289                                                         NULL,
290                                                         GTK_PARAM_READWRITE));
291
292   /**
293    * GtkAboutDialog:license:
294    *
295    * The license of the program. This string is displayed in a 
296    * text view in a secondary dialog, therefore it is fine to use
297    * a long multi-paragraph text. Note that the text is only wrapped
298    * in the text view if the "wrap-license" property is set to %TRUE;
299    * otherwise the text itself must contain the intended linebreaks.
300    *
301    * Since: 2.6
302    */  
303   g_object_class_install_property (object_class,
304                                    PROP_LICENSE,
305                                    g_param_spec_string ("license",
306                                                         _("License"),
307                                                         _("The license of the program"),
308                                                         NULL,
309                                                         GTK_PARAM_READWRITE));
310
311   /**
312    * GtkAboutDialog:website:
313    *
314    * The URL for the link to the website of the program. 
315    * This should be a string starting with "http://.
316    *
317    * Since: 2.6
318    */  
319   g_object_class_install_property (object_class,
320                                    PROP_WEBSITE,
321                                    g_param_spec_string ("website",
322                                                         P_("Website URL"),
323                                                         P_("The URL for the link to the website of the program"),
324                                                         NULL,
325                                                         GTK_PARAM_READWRITE));
326
327   /**
328    * GtkAboutDialog:website-label:
329    *
330    * The label for the link to the website of the program. If this is not set, 
331    * it defaults to the URL specified in the 
332    * <link linkend="GtkAboutDialog--website">website</link> property.
333    *
334    * Since: 2.6
335    */  
336   g_object_class_install_property (object_class,
337                                    PROP_WEBSITE_LABEL,
338                                    g_param_spec_string ("website-label",
339                                                         P_("Website label"),
340                                                         P_("The label for the link to the website of the program. If this is not set, it defaults to the URL"),
341                                                         NULL,
342                                                         GTK_PARAM_READWRITE));
343
344   /**
345    * GtkAboutDialog:authors:
346    *
347    * The authors of the program, as a %NULL-terminated array of strings.
348    * Each string may contain email addresses and URLs, which will be displayed
349    * as links, see the introduction for more details.
350    *
351    * Since: 2.6
352    */  
353   g_object_class_install_property (object_class,
354                                    PROP_AUTHORS,
355                                    g_param_spec_boxed ("authors",
356                                                        P_("Authors"),
357                                                        P_("List of authors of the program"),
358                                                        G_TYPE_STRV,
359                                                        GTK_PARAM_READWRITE));
360
361   /**
362    * GtkAboutDialog:documenters:
363    *
364    * The people documenting the program, as a %NULL-terminated array of strings.
365    * Each string may contain email addresses and URLs, which will be displayed
366    * as links, see the introduction for more details.
367    *
368    * Since: 2.6
369    */  
370   g_object_class_install_property (object_class,
371                                    PROP_DOCUMENTERS,
372                                    g_param_spec_boxed ("documenters",
373                                                        P_("Documenters"),
374                                                        P_("List of people documenting the program"),
375                                                        G_TYPE_STRV,
376                                                        GTK_PARAM_READWRITE));
377
378   /**
379    * GtkAboutDialog:artists:
380    *
381    * The people who contributed artwork to the program, as a %NULL-terminated array of strings.
382    * Each string may contain email addresses and URLs, which will be displayed
383    * as links, see the introduction for more details.
384    *
385    * Since: 2.6
386    */  
387   g_object_class_install_property (object_class,
388                                    PROP_ARTISTS,
389                                    g_param_spec_boxed ("artists",
390                                                        P_("Artists"),
391                                                        P_("List of people who have contributed artwork to the program"),
392                                                        G_TYPE_STRV,
393                                                        GTK_PARAM_READWRITE));
394
395
396   /**
397    * GtkAboutDialog:translator-credits:
398    *
399    * Credits to the translators. This string should be marked as translatable.
400    * The string may contain email addresses and URLs, which will be displayed
401    * as links, see the introduction for more details.
402    *
403    * Since: 2.6
404    */  
405   g_object_class_install_property (object_class,
406                                    PROP_TRANSLATOR_CREDITS,
407                                    g_param_spec_string ("translator-credits",
408                                                         P_("Translator credits"),
409                                                         P_("Credits to the translators. This string should be marked as translatable"),
410                                                         NULL,
411                                                         GTK_PARAM_READWRITE));
412         
413   /**
414    * GtkAboutDialog:logo:
415    *
416    * A logo for the about box. If this is not set, it defaults to 
417    * gtk_window_get_default_icon_list().
418    *
419    * Since: 2.6
420    */  
421   g_object_class_install_property (object_class,
422                                    PROP_LOGO,
423                                    g_param_spec_object ("logo",
424                                                         P_("Logo"),
425                                                         P_("A logo for the about box. If this is not set, it defaults to gtk_window_get_default_icon_list()"),
426                                                         GDK_TYPE_PIXBUF,
427                                                         GTK_PARAM_READWRITE));
428
429   /**
430    * GtkAboutDialog:logo-icon-name:
431    *
432    * A named icon to use as the logo for the about box. This property
433    * overrides the <link linkend="GtkAboutDialog--logo">logo</link> property.
434    *
435    * Since: 2.6
436    */  
437   g_object_class_install_property (object_class,
438                                    PROP_LOGO_ICON_NAME,
439                                    g_param_spec_string ("logo-icon-name",
440                                                         P_("Logo Icon Name"),
441                                                         P_("A named icon to use as the logo for the about box."),
442                                                         NULL,
443                                                         GTK_PARAM_READWRITE));
444   /**
445    * GtkAboutDialog:wrap-license:
446    *
447    * Whether to wrap the text in the license dialog.
448    *
449    * Since: 2.8
450    */  
451   g_object_class_install_property (object_class,
452                                    PROP_WRAP_LICENSE,
453                                    g_param_spec_boolean ("wrap-license",
454                                                          P_("Wrap license"),
455                                                          P_("Whether to wrap the license text."),
456                                                          FALSE,
457                                                          GTK_PARAM_READWRITE));
458
459
460   g_type_class_add_private (object_class, sizeof (GtkAboutDialogPrivate));
461 }
462
463 static void
464 gtk_about_dialog_init (GtkAboutDialog *about)
465 {
466   GtkDialog *dialog = GTK_DIALOG (about);
467   GtkAboutDialogPrivate *priv;
468   GtkWidget *vbox, *hbox, *button, *close_button, *image;
469
470   /* Data */
471   priv = GTK_ABOUT_DIALOG_GET_PRIVATE (about);
472   about->private_data = priv;
473
474   priv->name = NULL;
475   priv->version = NULL;
476   priv->copyright = NULL;
477   priv->comments = NULL;
478   priv->website_url = NULL;
479   priv->website_text = NULL;
480   priv->translator_credits = NULL;
481   priv->license = NULL;
482   priv->authors = NULL;
483   priv->documenters = NULL;
484   priv->artists = NULL;
485
486   priv->hand_cursor = gdk_cursor_new (GDK_HAND2);
487   priv->regular_cursor = gdk_cursor_new (GDK_XTERM);
488   priv->hovering_over_link = FALSE;
489   priv->wrap_license = FALSE;
490
491   gtk_dialog_set_has_separator (dialog, FALSE);
492   gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
493   gtk_box_set_spacing (GTK_BOX (dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
494   gtk_container_set_border_width (GTK_CONTAINER (dialog->action_area), 5);
495
496   /* Widgets */
497   gtk_widget_push_composite_child ();
498
499   vbox = gtk_vbox_new (FALSE, 8);
500   gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
501   gtk_box_pack_start (GTK_BOX (dialog->vbox), vbox, TRUE, TRUE, 0);
502
503   priv->logo_image = gtk_image_new ();
504   gtk_box_pack_start (GTK_BOX (vbox), priv->logo_image, FALSE, FALSE, 0);
505
506   priv->name_label = gtk_label_new (NULL);
507   gtk_label_set_selectable (GTK_LABEL (priv->name_label), TRUE);
508   gtk_label_set_justify (GTK_LABEL (priv->name_label), GTK_JUSTIFY_CENTER);
509   gtk_box_pack_start (GTK_BOX (vbox), priv->name_label, FALSE, FALSE, 0);
510
511   priv->comments_label = gtk_label_new (NULL);
512   gtk_label_set_selectable (GTK_LABEL (priv->comments_label), TRUE);
513   gtk_label_set_justify (GTK_LABEL (priv->comments_label), GTK_JUSTIFY_CENTER);
514   gtk_label_set_line_wrap (GTK_LABEL (priv->comments_label), TRUE);
515   gtk_box_pack_start (GTK_BOX (vbox), priv->comments_label, FALSE, FALSE, 0);
516
517   priv->copyright_label = gtk_label_new (NULL);
518   gtk_label_set_selectable (GTK_LABEL (priv->copyright_label), TRUE);   
519   gtk_label_set_justify (GTK_LABEL (priv->copyright_label), GTK_JUSTIFY_CENTER);
520   gtk_box_pack_start (GTK_BOX (vbox), priv->copyright_label, FALSE, FALSE, 0);
521
522   hbox = gtk_hbox_new (TRUE, 0);
523   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 0); 
524
525   priv->website_button = button = gtk_link_button_new (""); 
526   gtk_widget_set_no_show_all (button, TRUE);
527   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
528   
529   priv->website_label = button = gtk_label_new ("");
530   gtk_widget_set_no_show_all (button, TRUE);
531   gtk_label_set_selectable (GTK_LABEL (button), TRUE);
532   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
533   
534   gtk_widget_show (vbox);
535   gtk_widget_show (priv->logo_image);
536   gtk_widget_show (priv->name_label);
537   gtk_widget_show (hbox);
538
539   /* Add the OK button */
540   close_button = gtk_dialog_add_button (GTK_DIALOG (about), GTK_STOCK_CLOSE,
541                                         GTK_RESPONSE_CANCEL);
542   gtk_dialog_set_default_response (GTK_DIALOG (about), GTK_RESPONSE_CANCEL);
543
544   /* Add the credits button */
545   button = gtk_button_new_with_mnemonic (_("C_redits"));
546   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
547   image = gtk_image_new_from_stock (GTK_STOCK_ABOUT, GTK_ICON_SIZE_BUTTON);
548   gtk_button_set_image (GTK_BUTTON (button), image);
549   gtk_widget_set_no_show_all (button, TRUE);
550   gtk_box_pack_end (GTK_BOX (GTK_DIALOG (about)->action_area), 
551                     button, FALSE, TRUE, 0); 
552   gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (GTK_DIALOG (about)->action_area), button, TRUE);
553   g_signal_connect (button, "clicked",
554                     G_CALLBACK (display_credits_dialog), about);
555   priv->credits_button = button;
556   priv->credits_dialog = NULL;
557
558   /* Add the license button */
559   button = gtk_button_new_from_stock (_("_License"));
560   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
561   gtk_widget_set_no_show_all (button, TRUE);
562   gtk_box_pack_end (GTK_BOX (GTK_DIALOG (about)->action_area), 
563                     button, FALSE, TRUE, 0); 
564   gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (GTK_DIALOG (about)->action_area), button, TRUE);
565   g_signal_connect (button, "clicked",
566                     G_CALLBACK (display_license_dialog), about);
567   priv->license_button = button;
568   priv->license_dialog = NULL;
569
570   gtk_window_set_resizable (GTK_WINDOW (about), FALSE);
571
572   gtk_widget_pop_composite_child ();
573
574   gtk_widget_grab_default (close_button);
575   gtk_widget_grab_focus (close_button);
576
577   /* force defaults */
578   gtk_about_dialog_set_program_name (about, NULL);
579   gtk_about_dialog_set_logo (about, NULL);
580 }
581
582 static void
583 gtk_about_dialog_finalize (GObject *object)
584 {
585   GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
586   GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data;
587
588   g_free (priv->name);
589   g_free (priv->version);
590   g_free (priv->copyright);
591   g_free (priv->comments);
592   g_free (priv->license);
593   g_free (priv->website_url);
594   g_free (priv->website_text);
595   g_free (priv->translator_credits);
596
597   g_strfreev (priv->authors);
598   g_strfreev (priv->documenters);
599   g_strfreev (priv->artists);
600
601   g_slist_foreach (priv->visited_links, (GFunc)g_free, NULL);
602   g_slist_free (priv->visited_links);
603
604   gdk_cursor_unref (priv->hand_cursor);
605   gdk_cursor_unref (priv->regular_cursor);  
606
607   G_OBJECT_CLASS (gtk_about_dialog_parent_class)->finalize (object);
608 }
609
610 static void
611 gtk_about_dialog_set_property (GObject      *object, 
612                                guint         prop_id, 
613                                const GValue *value, 
614                                GParamSpec   *pspec)
615 {
616   GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
617   GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data;
618
619   switch (prop_id) 
620     {
621     case PROP_NAME:
622       gtk_about_dialog_set_program_name (about, g_value_get_string (value));
623       break;
624     case PROP_VERSION:
625       gtk_about_dialog_set_version (about, g_value_get_string (value));
626       break;
627     case PROP_COMMENTS:
628       gtk_about_dialog_set_comments (about, g_value_get_string (value));
629       break;
630     case PROP_WEBSITE:
631       gtk_about_dialog_set_website (about, g_value_get_string (value));
632       break;
633     case PROP_WEBSITE_LABEL:
634       gtk_about_dialog_set_website_label (about, g_value_get_string (value));
635       break;
636     case PROP_LICENSE:
637       gtk_about_dialog_set_license (about, g_value_get_string (value));
638       break;
639     case PROP_COPYRIGHT:
640       gtk_about_dialog_set_copyright (about, g_value_get_string (value));
641       break;
642     case PROP_LOGO:
643       gtk_about_dialog_set_logo (about, g_value_get_object (value));
644       break; 
645     case PROP_AUTHORS:
646       gtk_about_dialog_set_authors (about, (const gchar**)g_value_get_boxed (value));
647       break;
648     case PROP_DOCUMENTERS:
649       gtk_about_dialog_set_documenters (about, (const gchar**)g_value_get_boxed (value));
650       break;    
651     case PROP_ARTISTS:
652       gtk_about_dialog_set_artists (about, (const gchar**)g_value_get_boxed (value));
653       break;    
654     case PROP_TRANSLATOR_CREDITS:
655       gtk_about_dialog_set_translator_credits (about, g_value_get_string (value));
656       break;
657     case PROP_LOGO_ICON_NAME:
658       gtk_about_dialog_set_logo_icon_name (about, g_value_get_string (value));
659       break;
660     case PROP_WRAP_LICENSE:
661       priv->wrap_license = g_value_get_boolean (value);
662       break;
663     default:
664       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
665       break;
666     }
667 }
668
669 static void
670 gtk_about_dialog_get_property (GObject    *object, 
671                                guint       prop_id, 
672                                GValue     *value, 
673                                GParamSpec *pspec)
674 {
675   GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
676   GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data;
677         
678   switch (prop_id) 
679     {
680     case PROP_NAME:
681       g_value_set_string (value, priv->name);
682       break;
683     case PROP_VERSION:
684       g_value_set_string (value, priv->version);
685       break;
686     case PROP_COPYRIGHT:
687       g_value_set_string (value, priv->copyright);
688       break;
689     case PROP_COMMENTS:
690       g_value_set_string (value, priv->comments);
691       break;
692     case PROP_WEBSITE:
693       g_value_set_string (value, priv->website_url);
694       break;
695     case PROP_WEBSITE_LABEL:
696       g_value_set_string (value, priv->website_text);
697       break;
698     case PROP_LICENSE:
699       g_value_set_string (value, priv->license);
700       break;
701     case PROP_TRANSLATOR_CREDITS:
702       g_value_set_string (value, priv->translator_credits);
703       break;
704     case PROP_AUTHORS:
705       g_value_set_boxed (value, priv->authors);
706       break;
707     case PROP_DOCUMENTERS:
708       g_value_set_boxed (value, priv->documenters);
709       break;
710     case PROP_ARTISTS:
711       g_value_set_boxed (value, priv->artists);
712       break;
713     case PROP_LOGO:
714       if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
715         g_value_set_object (value, gtk_image_get_pixbuf (GTK_IMAGE (priv->logo_image)));
716       else
717         g_value_set_object (value, NULL);
718       break;
719     case PROP_LOGO_ICON_NAME:
720       if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_ICON_NAME)
721         {
722           const gchar *icon_name;
723
724           gtk_image_get_icon_name (GTK_IMAGE (priv->logo_image), &icon_name, NULL);
725           g_value_set_string (value, icon_name);
726         }
727       else
728         g_value_set_string (value, NULL);
729       break;
730     case PROP_WRAP_LICENSE:
731       g_value_set_boolean (value, priv->wrap_license);
732       break;
733     default:
734       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
735       break;
736     }
737 }
738
739 static void
740 update_website (GtkAboutDialog *about)
741 {
742   GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data;
743
744   if (priv->website_url && (!activate_url_hook_set || activate_url_hook != NULL))
745     {
746       gtk_widget_show (priv->website_button);
747       gtk_widget_hide (priv->website_label);
748
749       gtk_link_button_set_uri (GTK_LINK_BUTTON (priv->website_button), priv->website_url);
750       if (priv->website_text)
751         gtk_button_set_label (GTK_BUTTON (priv->website_button), priv->website_text);
752       else 
753         gtk_button_set_label (GTK_BUTTON (priv->website_button), priv->website_url);
754     }
755   else
756     {
757       gtk_widget_show (priv->website_label);
758       gtk_widget_hide (priv->website_button);
759
760       if (priv->website_url)
761         gtk_label_set_text (GTK_LABEL (priv->website_label), priv->website_url);
762       else if (priv->website_text)
763         gtk_label_set_text (GTK_LABEL (priv->website_label), priv->website_text);
764       else
765         gtk_widget_hide (priv->website_label);
766     }
767 }
768
769 static void
770 gtk_about_dialog_show (GtkWidget *widget)
771 {
772   update_website (GTK_ABOUT_DIALOG (widget));
773   
774   GTK_WIDGET_CLASS (gtk_about_dialog_parent_class)->show (widget);
775 }
776
777 /**
778  * gtk_about_dialog_get_name:
779  * @about: a #GtkAboutDialog
780  * 
781  * Returns the program name displayed in the about dialog.
782  * 
783  * Return value: The program name. The string is owned by the about
784  *  dialog and must not be modified.
785  *
786  * Since: 2.6
787  *
788  * Deprecated: 2.12: Use gtk_about_dialog_get_program_name() instead.
789  **/
790 G_CONST_RETURN gchar *
791 gtk_about_dialog_get_name (GtkAboutDialog *about)
792 {
793   return gtk_about_dialog_get_program_name (about);
794 }
795
796 /**
797  * gtk_about_dialog_get_program_name:
798  * @about: a #GtkAboutDialog
799  * 
800  * Returns the program name displayed in the about dialog.
801  * 
802  * Return value: The program name. The string is owned by the about
803  *  dialog and must not be modified.
804  *
805  * Since: 2.12
806  **/
807 G_CONST_RETURN gchar *
808 gtk_about_dialog_get_program_name (GtkAboutDialog *about)
809 {
810   GtkAboutDialogPrivate *priv;
811   
812   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
813
814   priv = (GtkAboutDialogPrivate *)about->private_data;
815
816   return priv->name;
817 }
818
819 static void
820 update_name_version (GtkAboutDialog *about)
821 {
822   GtkAboutDialogPrivate *priv;
823   gchar *title_string, *name_string;
824
825   priv = (GtkAboutDialogPrivate *)about->private_data;
826
827   title_string = g_strdup_printf (_("About %s"), priv->name);
828   gtk_window_set_title (GTK_WINDOW (about), title_string);
829   g_free (title_string);
830
831   if (priv->version != NULL) 
832     name_string = g_markup_printf_escaped ("<span size=\"xx-large\" weight=\"bold\">%s %s</span>", 
833                                              priv->name, priv->version);
834   else
835     name_string = g_markup_printf_escaped ("<span size=\"xx-large\" weight=\"bold\">%s</span>", 
836                                            priv->name);
837
838   gtk_label_set_markup (GTK_LABEL (priv->name_label), name_string);
839
840   g_free (name_string);
841 }
842
843 /**
844  * gtk_about_dialog_set_name:
845  * @about: a #GtkAboutDialog
846  * @name: the program name
847  *
848  * Sets the name to display in the about dialog. 
849  * If this is not set, it defaults to g_get_application_name().
850  * 
851  * Since: 2.6
852  *
853  * Deprecated: 2.12: Use gtk_about_dialog_set_program_name() instead.
854  **/
855 void
856 gtk_about_dialog_set_name (GtkAboutDialog *about, 
857                            const gchar    *name)
858 {
859     gtk_about_dialog_set_program_name (about, name);
860 }
861
862 /**
863  * gtk_about_dialog_set_program_name:
864  * @about: a #GtkAboutDialog
865  * @name: the program name
866  *
867  * Sets the name to display in the about dialog. 
868  * If this is not set, it defaults to g_get_application_name().
869  * 
870  * Since: 2.12
871  **/
872 void
873 gtk_about_dialog_set_program_name (GtkAboutDialog *about, 
874                                    const gchar    *name)
875 {
876   GtkAboutDialogPrivate *priv;
877   gchar *tmp;
878
879   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
880         
881   priv = (GtkAboutDialogPrivate *)about->private_data;
882   tmp = priv->name;
883   priv->name = g_strdup (name ? name : g_get_application_name ());
884   g_free (tmp);
885
886   update_name_version (about);
887
888   g_object_notify (G_OBJECT (about), "program-name");
889 }
890
891
892 /**
893  * gtk_about_dialog_get_version:
894  * @about: a #GtkAboutDialog
895  * 
896  * Returns the version string.
897  * 
898  * Return value: The version string. The string is owned by the about
899  *  dialog and must not be modified.
900  *
901  * Since: 2.6
902  **/
903 G_CONST_RETURN gchar *
904 gtk_about_dialog_get_version (GtkAboutDialog *about)
905 {
906   GtkAboutDialogPrivate *priv;
907   
908   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
909
910   priv = (GtkAboutDialogPrivate *)about->private_data;
911
912   return priv->version;
913 }
914
915 /**
916  * gtk_about_dialog_set_version:
917  * @about: a #GtkAboutDialog
918  * @version: the version string 
919  *
920  * Sets the version string to display in the about dialog.
921  * 
922  * Since: 2.6
923  **/
924 void
925 gtk_about_dialog_set_version (GtkAboutDialog *about, 
926                               const gchar    *version)
927 {
928   GtkAboutDialogPrivate *priv;
929   gchar *tmp;
930
931   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
932
933   priv = (GtkAboutDialogPrivate *)about->private_data;
934   
935   tmp = priv->version;
936   priv->version = g_strdup (version);
937   g_free (tmp); 
938
939   update_name_version (about);
940
941   g_object_notify (G_OBJECT (about), "version");
942 }
943
944 /**
945  * gtk_about_dialog_get_copyright:
946  * @about: a #GtkAboutDialog
947  * 
948  * Returns the copyright string.
949  * 
950  * Return value: The copyright string. The string is owned by the about
951  *  dialog and must not be modified.
952  *
953  * Since: 2.6
954  **/
955 G_CONST_RETURN gchar *
956 gtk_about_dialog_get_copyright (GtkAboutDialog *about)
957 {
958   GtkAboutDialogPrivate *priv;
959   
960   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
961
962   priv = (GtkAboutDialogPrivate *)about->private_data;
963
964   return priv->copyright;
965 }
966
967 /**
968  * gtk_about_dialog_set_copyright:
969  * @about: a #GtkAboutDialog
970  * @copyright: the copyright string
971  * 
972  * Sets the copyright string to display in the about dialog.
973  * This should be a short string of one or two lines. 
974  *
975  * Since: 2.6
976  **/
977 void
978 gtk_about_dialog_set_copyright (GtkAboutDialog *about, 
979                                 const gchar    *copyright)
980 {
981   GtkAboutDialogPrivate *priv;
982   gchar *copyright_string, *tmp;
983
984   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
985
986   priv = (GtkAboutDialogPrivate *)about->private_data;
987         
988   tmp = priv->copyright;
989   priv->copyright = g_strdup (copyright);
990   g_free (tmp);
991   
992   if (priv->copyright != NULL) 
993     {
994       copyright_string = g_markup_printf_escaped ("<span size=\"small\">%s</span>", 
995                                                   priv->copyright);
996       gtk_label_set_markup (GTK_LABEL (priv->copyright_label), copyright_string);
997       g_free (copyright_string);
998   
999       gtk_widget_show (priv->copyright_label);
1000     }
1001   else 
1002     gtk_widget_hide (priv->copyright_label);
1003   
1004   g_object_notify (G_OBJECT (about), "copyright");
1005 }
1006
1007 /**
1008  * gtk_about_dialog_get_comments:
1009  * @about: a #GtkAboutDialog
1010  * 
1011  * Returns the comments string.
1012  * 
1013  * Return value: The comments. The string is owned by the about
1014  *  dialog and must not be modified.
1015  *
1016  * Since: 2.6
1017  **/
1018 G_CONST_RETURN gchar *
1019 gtk_about_dialog_get_comments (GtkAboutDialog *about)
1020 {
1021   GtkAboutDialogPrivate *priv;
1022   
1023   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1024
1025   priv = (GtkAboutDialogPrivate *)about->private_data;
1026
1027   return priv->comments;
1028 }
1029
1030 /**
1031  * gtk_about_dialog_set_comments:
1032  * @about: a #GtkAboutDialog
1033  * @comments: a comments string
1034  * 
1035  * Sets the comments string to display in the about 
1036  * dialog. This should be a short string of one or
1037  * two lines.
1038  *
1039  * Since: 2.6
1040  **/
1041 void
1042 gtk_about_dialog_set_comments (GtkAboutDialog *about, 
1043                                const gchar    *comments)
1044 {
1045   GtkAboutDialogPrivate *priv;
1046   gchar *tmp;
1047
1048   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1049
1050   priv = (GtkAboutDialogPrivate *)about->private_data;
1051   
1052   tmp = priv->comments;
1053   if (comments) 
1054     {
1055       priv->comments = g_strdup (comments);
1056       gtk_label_set_text (GTK_LABEL (priv->comments_label), priv->comments);
1057       gtk_widget_show (priv->comments_label);
1058     }
1059   else
1060     {
1061       priv->comments = NULL;
1062       gtk_widget_hide (priv->comments_label);
1063     }
1064   g_free (tmp);
1065
1066   g_object_notify (G_OBJECT (about), "comments");
1067 }
1068
1069 /**
1070  * gtk_about_dialog_get_license:
1071  * @about: a #GtkAboutDialog
1072  * 
1073  * Returns the license information.
1074  * 
1075  * Return value: The license information. The string is owned by the about
1076  *  dialog and must not be modified.
1077  *
1078  * Since: 2.6
1079  **/
1080 G_CONST_RETURN gchar *
1081 gtk_about_dialog_get_license (GtkAboutDialog *about)
1082 {
1083   GtkAboutDialogPrivate *priv;
1084   
1085   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1086
1087   priv = (GtkAboutDialogPrivate *)about->private_data;
1088
1089   return priv->license;
1090 }
1091
1092 /**
1093  * gtk_about_dialog_set_license:
1094  * @about: a #GtkAboutDialog
1095  * @license: the license information or %NULL
1096  *
1097  * Sets the license information to be displayed in the secondary
1098  * license dialog. If @license is %NULL, the license button is
1099  * hidden.
1100  * 
1101  * Since: 2.6
1102  **/
1103 void
1104 gtk_about_dialog_set_license (GtkAboutDialog *about, 
1105                               const gchar    *license)
1106 {
1107   GtkAboutDialogPrivate *priv;
1108   gchar *tmp;
1109
1110   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1111
1112   priv = (GtkAboutDialogPrivate *)about->private_data;
1113
1114   tmp = priv->license;
1115   if (license) 
1116     {
1117       priv->license = g_strdup (license);
1118       gtk_widget_show (priv->license_button);
1119     }
1120   else
1121     {
1122       priv->license = NULL;
1123       gtk_widget_hide (priv->license_button);
1124     }
1125   g_free (tmp);
1126
1127   g_object_notify (G_OBJECT (about), "license");
1128 }
1129
1130 /**
1131  * gtk_about_dialog_get_wrap_license:
1132  * @about: a #GtkAboutDialog
1133  *
1134  * Returns whether the license text in @about is 
1135  * automatically wrapped.
1136  *
1137  * Returns: %TRUE if the license text is wrapped 
1138  *
1139  * Since: 2.8
1140  */
1141 gboolean
1142 gtk_about_dialog_get_wrap_license (GtkAboutDialog *about)
1143 {
1144   GtkAboutDialogPrivate *priv;
1145
1146   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), FALSE);
1147
1148   priv = (GtkAboutDialogPrivate *)about->private_data;
1149
1150   return priv->wrap_license;
1151 }
1152
1153 /**
1154  * gtk_about_dialog_set_wrap_license:
1155  * @about: a #GtkAboutDialog
1156  * @wrap_license: whether to wrap the license
1157  *
1158  * Sets whether the license text in @about is 
1159  * automatically wrapped.
1160  * 
1161  * Since: 2.8
1162  */
1163 void
1164 gtk_about_dialog_set_wrap_license (GtkAboutDialog *about,
1165                                    gboolean        wrap_license)
1166 {
1167   GtkAboutDialogPrivate *priv;
1168
1169   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1170
1171   priv = (GtkAboutDialogPrivate *)about->private_data;
1172
1173   wrap_license = wrap_license != FALSE;
1174   
1175   if (priv->wrap_license != wrap_license)
1176     {
1177        priv->wrap_license = wrap_license;
1178
1179        g_object_notify (G_OBJECT (about), "wrap-license");
1180     }
1181 }
1182
1183 /**
1184  * gtk_about_dialog_get_website:
1185  * @about: a #GtkAboutDialog
1186  * 
1187  * Returns the website URL.
1188  * 
1189  * Return value: The website URL. The string is owned by the about
1190  *  dialog and must not be modified.
1191  *
1192  * Since: 2.6
1193  **/
1194 G_CONST_RETURN gchar *
1195 gtk_about_dialog_get_website (GtkAboutDialog *about)
1196 {
1197   GtkAboutDialogPrivate *priv;
1198   
1199   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1200
1201   priv = (GtkAboutDialogPrivate *)about->private_data;
1202
1203   return priv->website_url;
1204 }
1205
1206 /**
1207  * gtk_about_dialog_set_website:
1208  * @about: a #GtkAboutDialog
1209  * @website: a URL string starting with "http://"
1210  * 
1211  * Sets the URL to use for the website link.
1212  *
1213  * Note that that the hook functions need to be set up
1214  * before calling this function.
1215  *
1216  * Since: 2.6
1217  **/
1218 void
1219 gtk_about_dialog_set_website (GtkAboutDialog *about, 
1220                               const gchar    *website)
1221 {
1222   GtkAboutDialogPrivate *priv;
1223   gchar *tmp;
1224
1225   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1226
1227   priv = (GtkAboutDialogPrivate *)about->private_data;
1228   
1229   tmp = priv->website_url;
1230   priv->website_url = g_strdup (website);
1231   g_free (tmp); 
1232
1233   update_website (about);
1234
1235   g_object_notify (G_OBJECT (about), "website");
1236 }
1237
1238 /**
1239  * gtk_about_dialog_get_website_label:
1240  * @about: a #GtkAboutDialog
1241  * 
1242  * Returns the label used for the website link. 
1243  * 
1244  * Return value: The label used for the website link. The string is owned by the about
1245  *  dialog and must not be modified.
1246  *
1247  * Since: 2.6
1248  **/
1249 G_CONST_RETURN gchar *
1250 gtk_about_dialog_get_website_label (GtkAboutDialog *about)
1251 {
1252   GtkAboutDialogPrivate *priv;
1253   
1254   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1255
1256   priv = (GtkAboutDialogPrivate *)about->private_data;
1257
1258   return priv->website_text;
1259 }
1260
1261 /**
1262  * gtk_about_dialog_set_website_label:
1263  * @about: a #GtkAboutDialog
1264  * @website_label: the label used for the website link
1265  * 
1266  * Sets the label to be used for the website link.
1267  * It defaults to the website URL.
1268  *
1269  * Since: 2.6
1270  **/
1271 void
1272 gtk_about_dialog_set_website_label (GtkAboutDialog *about, 
1273                                     const gchar    *website_label)
1274 {
1275   GtkAboutDialogPrivate *priv;
1276   gchar *tmp;
1277
1278   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1279
1280   priv = (GtkAboutDialogPrivate *)about->private_data;
1281
1282   tmp = priv->website_text;
1283   priv->website_text = g_strdup (website_label);
1284   g_free (tmp);
1285
1286   update_website (about);
1287
1288   g_object_notify (G_OBJECT (about), "website-label");
1289 }
1290
1291 /**
1292  * gtk_about_dialog_get_authors:
1293  * @about: a #GtkAboutDialog
1294  * 
1295  * Returns the string which are displayed in the authors tab
1296  * of the secondary credits dialog.
1297  * 
1298  * Return value: A %NULL-terminated string array containing
1299  *  the authors. The array is owned by the about dialog 
1300  *  and must not be modified.
1301  *
1302  * Since: 2.6
1303  **/
1304 G_CONST_RETURN gchar * G_CONST_RETURN *
1305 gtk_about_dialog_get_authors (GtkAboutDialog *about)
1306 {
1307   GtkAboutDialogPrivate *priv;
1308   
1309   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1310
1311   priv = (GtkAboutDialogPrivate *)about->private_data;
1312
1313   return (const gchar * const *) priv->authors;
1314 }
1315
1316 static void
1317 update_credits_button_visibility (GtkAboutDialog *about)
1318 {
1319   GtkAboutDialogPrivate *priv = about->private_data;
1320   gboolean show;
1321
1322   show = priv->authors != NULL ||
1323          priv->documenters != NULL ||
1324          priv->artists != NULL ||
1325          (priv->translator_credits != NULL &&
1326           strcmp (priv->translator_credits, "translator_credits") &&
1327           strcmp (priv->translator_credits, "translator-credits"));
1328   if (show)
1329     gtk_widget_show (priv->credits_button);
1330   else
1331     gtk_widget_hide (priv->credits_button);
1332 }
1333
1334 /**
1335  * gtk_about_dialog_set_authors:
1336  * @about: a #GtkAboutDialog
1337  * @authors: a %NULL-terminated array of strings 
1338  *
1339  * Sets the strings which are displayed in the authors tab
1340  * of the secondary credits dialog. 
1341  * 
1342  * Since: 2.6
1343  **/
1344 void
1345 gtk_about_dialog_set_authors (GtkAboutDialog  *about, 
1346                               const gchar    **authors)
1347 {
1348   GtkAboutDialogPrivate *priv;
1349   gchar **tmp;
1350
1351   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1352
1353   priv = (GtkAboutDialogPrivate *)about->private_data;
1354
1355   tmp = priv->authors;
1356   priv->authors = g_strdupv ((gchar **)authors);
1357   g_strfreev (tmp);
1358
1359   update_credits_button_visibility (about);
1360
1361   g_object_notify (G_OBJECT (about), "authors");
1362 }
1363
1364 /**
1365  * gtk_about_dialog_get_documenters:
1366  * @about: a #GtkAboutDialog
1367  * 
1368  * Returns the string which are displayed in the documenters 
1369  * tab of the secondary credits dialog.
1370  * 
1371  * Return value: A %NULL-terminated string array containing
1372  *  the documenters. The array is owned by the about dialog 
1373  *  and must not be modified.
1374  *
1375  * Since: 2.6
1376  **/
1377 G_CONST_RETURN gchar * G_CONST_RETURN *
1378 gtk_about_dialog_get_documenters (GtkAboutDialog *about)
1379 {
1380   GtkAboutDialogPrivate *priv;
1381   
1382   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1383
1384   priv = (GtkAboutDialogPrivate *)about->private_data;
1385
1386   return (const gchar * const *)priv->documenters;
1387 }
1388
1389 /**
1390  * gtk_about_dialog_set_documenters:
1391  * @about: a #GtkAboutDialog
1392  * @documenters: a %NULL-terminated array of strings 
1393  *
1394  * Sets the strings which are displayed in the documenters tab
1395  * of the secondary credits dialog. 
1396  * 
1397  * Since: 2.6
1398  **/
1399 void
1400 gtk_about_dialog_set_documenters (GtkAboutDialog *about, 
1401                                   const gchar   **documenters)
1402 {
1403   GtkAboutDialogPrivate *priv;
1404   gchar **tmp;
1405
1406   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1407
1408   priv = (GtkAboutDialogPrivate *)about->private_data;
1409   
1410   tmp = priv->documenters;
1411   priv->documenters = g_strdupv ((gchar **)documenters);
1412   g_strfreev (tmp);
1413
1414   update_credits_button_visibility (about);
1415
1416   g_object_notify (G_OBJECT (about), "documenters");
1417 }
1418
1419 /**
1420  * gtk_about_dialog_get_artists:
1421  * @about: a #GtkAboutDialog
1422  * 
1423  * Returns the string which are displayed in the artists tab
1424  * of the secondary credits dialog.
1425  * 
1426  * Return value: A %NULL-terminated string array containing
1427  *  the artists. The array is owned by the about dialog 
1428  *  and must not be modified.
1429  *
1430  * Since: 2.6
1431  **/
1432 G_CONST_RETURN gchar * G_CONST_RETURN *
1433 gtk_about_dialog_get_artists (GtkAboutDialog *about)
1434 {
1435   GtkAboutDialogPrivate *priv;
1436   
1437   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1438
1439   priv = (GtkAboutDialogPrivate *)about->private_data;
1440
1441   return (const gchar * const *)priv->artists;
1442 }
1443
1444 /**
1445  * gtk_about_dialog_set_artists:
1446  * @about: a #GtkAboutDialog
1447  * @artists: a %NULL-terminated array of strings 
1448  *
1449  * Sets the strings which are displayed in the artists tab
1450  * of the secondary credits dialog. 
1451  * 
1452  * Since: 2.6
1453  **/
1454 void
1455 gtk_about_dialog_set_artists (GtkAboutDialog *about, 
1456                               const gchar   **artists)
1457 {
1458   GtkAboutDialogPrivate *priv;
1459   gchar **tmp;
1460
1461   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1462
1463   priv = (GtkAboutDialogPrivate *)about->private_data;
1464   
1465   tmp = priv->artists;
1466   priv->artists = g_strdupv ((gchar **)artists);
1467   g_strfreev (tmp);
1468
1469   update_credits_button_visibility (about);
1470
1471   g_object_notify (G_OBJECT (about), "artists");
1472 }
1473
1474 /**
1475  * gtk_about_dialog_get_translator_credits:
1476  * @about: a #GtkAboutDialog
1477  * 
1478  * Returns the translator credits string which is displayed
1479  * in the translators tab of the secondary credits dialog.
1480  * 
1481  * Return value: The translator credits string. The string is
1482  *   owned by the about dialog and must not be modified.
1483  *
1484  * Since: 2.6
1485  **/
1486 G_CONST_RETURN gchar *
1487 gtk_about_dialog_get_translator_credits (GtkAboutDialog *about)
1488 {
1489   GtkAboutDialogPrivate *priv;
1490   
1491   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1492
1493   priv = (GtkAboutDialogPrivate *)about->private_data;
1494
1495   return priv->translator_credits;
1496 }
1497
1498 /**
1499  * gtk_about_dialog_set_translator_credits:
1500  * @about: a #GtkAboutDialog
1501  * @translator_credits: the translator credits
1502  * 
1503  * Sets the translator credits string which is displayed in
1504  * the translators tab of the secondary credits dialog.
1505  * 
1506  * The intended use for this string is to display the translator
1507  * of the language which is currently used in the user interface.
1508  * Using gettext(), a simple way to achieve that is to mark the
1509  * string for translation:
1510  * |[
1511  *  gtk_about_dialog_set_translator_credits (about, _("translator-credits"));
1512  * ]|
1513  * It is a good idea to use the customary msgid "translator-credits" for this
1514  * purpose, since translators will already know the purpose of that msgid, and
1515  * since #GtkAboutDialog will detect if "translator-credits" is untranslated
1516  * and hide the tab.
1517  *
1518  * Since: 2.6
1519  **/
1520 void
1521 gtk_about_dialog_set_translator_credits (GtkAboutDialog *about, 
1522                                          const gchar    *translator_credits)
1523 {
1524   GtkAboutDialogPrivate *priv;
1525   gchar *tmp;
1526
1527   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1528
1529   priv = (GtkAboutDialogPrivate *)about->private_data;
1530
1531   tmp = priv->translator_credits;
1532   priv->translator_credits = g_strdup (translator_credits);
1533   g_free (tmp);
1534
1535   update_credits_button_visibility (about);
1536
1537   g_object_notify (G_OBJECT (about), "translator-credits");
1538 }
1539
1540 /**
1541  * gtk_about_dialog_get_logo:
1542  * @about: a #GtkAboutDialog
1543  * 
1544  * Returns the pixbuf displayed as logo in the about dialog.
1545  * 
1546  * Return value: the pixbuf displayed as logo. The pixbuf is
1547  *   owned by the about dialog. If you want to keep a reference
1548  *   to it, you have to call g_object_ref() on it.
1549  *
1550  * Since: 2.6
1551  **/
1552 GdkPixbuf *
1553 gtk_about_dialog_get_logo (GtkAboutDialog *about)
1554 {
1555   GtkAboutDialogPrivate *priv;
1556   
1557   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1558
1559   priv = (GtkAboutDialogPrivate *)about->private_data;
1560
1561   if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
1562     return gtk_image_get_pixbuf (GTK_IMAGE (priv->logo_image));
1563   else
1564     return NULL;
1565 }
1566
1567 static GtkIconSet *
1568 icon_set_new_from_pixbufs (GList *pixbufs)
1569 {
1570   GtkIconSet *icon_set = gtk_icon_set_new ();
1571   
1572   for (; pixbufs; pixbufs = pixbufs->next)
1573     {
1574       GdkPixbuf *pixbuf = GDK_PIXBUF (pixbufs->data);
1575
1576       GtkIconSource *icon_source = gtk_icon_source_new ();
1577       gtk_icon_source_set_pixbuf (icon_source, pixbuf);
1578       gtk_icon_set_add_source (icon_set, icon_source);
1579       gtk_icon_source_free (icon_source);
1580     }
1581   
1582   return icon_set;
1583 }
1584
1585 /**
1586  * gtk_about_dialog_set_logo:
1587  * @about: a #GtkAboutDialog
1588  * @logo: a #GdkPixbuf, or %NULL
1589  * 
1590  * Sets the pixbuf to be displayed as logo in 
1591  * the about dialog. If it is %NULL, the default
1592  * window icon set with gtk_window_set_default_icon ()
1593  * will be used.
1594  *
1595  * Since: 2.6
1596  **/
1597 void
1598 gtk_about_dialog_set_logo (GtkAboutDialog *about,
1599                            GdkPixbuf      *logo)
1600 {
1601   GtkAboutDialogPrivate *priv;
1602
1603   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1604
1605   priv = (GtkAboutDialogPrivate *)about->private_data;
1606
1607   g_object_freeze_notify (G_OBJECT (about));
1608
1609   if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_ICON_NAME)
1610     g_object_notify (G_OBJECT (about), "logo-icon-name");
1611
1612   if (logo != NULL) 
1613     gtk_image_set_from_pixbuf (GTK_IMAGE (priv->logo_image), logo);
1614   else 
1615     {
1616       GList *pixbufs = gtk_window_get_default_icon_list ();
1617
1618       if (pixbufs != NULL)
1619         {
1620           GtkIconSet *icon_set = icon_set_new_from_pixbufs (pixbufs); 
1621           
1622           gtk_image_set_from_icon_set (GTK_IMAGE (priv->logo_image),
1623                                        icon_set, GTK_ICON_SIZE_DIALOG);
1624           
1625           gtk_icon_set_unref (icon_set);
1626           g_list_free (pixbufs);
1627         }
1628     }
1629
1630   g_object_notify (G_OBJECT (about), "logo");
1631
1632   g_object_thaw_notify (G_OBJECT (about));
1633 }
1634
1635 /**
1636  * gtk_about_dialog_get_logo_icon_name:
1637  * @about: a #GtkAboutDialog
1638  * 
1639  * Returns the icon name displayed as logo in the about dialog.
1640  * 
1641  * Return value: the icon name displayed as logo. The string is
1642  *   owned by the dialog. If you want to keep a reference
1643  *   to it, you have to call g_strdup() on it.
1644  *
1645  * Since: 2.6
1646  **/
1647 G_CONST_RETURN gchar *
1648 gtk_about_dialog_get_logo_icon_name (GtkAboutDialog *about)
1649 {
1650   GtkAboutDialogPrivate *priv;
1651   const gchar *icon_name = NULL;
1652   
1653   g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1654
1655   priv = (GtkAboutDialogPrivate *)about->private_data;
1656
1657   if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_ICON_NAME)
1658     gtk_image_get_icon_name (GTK_IMAGE (priv->logo_image), &icon_name, NULL);
1659
1660   return icon_name;
1661 }
1662
1663 /**
1664  * gtk_about_dialog_set_logo_icon_name:
1665  * @about: a #GtkAboutDialog
1666  * @icon_name: an icon name, or %NULL
1667  * 
1668  * Sets the pixbuf to be displayed as logo in 
1669  * the about dialog. If it is %NULL, the default
1670  * window icon set with gtk_window_set_default_icon()
1671  * will be used.
1672  *
1673  * Since: 2.6
1674  **/
1675 void
1676 gtk_about_dialog_set_logo_icon_name (GtkAboutDialog *about,
1677                                      const gchar    *icon_name)
1678 {
1679   GtkAboutDialogPrivate *priv;
1680
1681   g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1682
1683   priv = (GtkAboutDialogPrivate *)about->private_data;
1684
1685   g_object_freeze_notify (G_OBJECT (about));
1686
1687   if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
1688     g_object_notify (G_OBJECT (about), "logo");
1689
1690   gtk_image_set_from_icon_name (GTK_IMAGE (priv->logo_image), icon_name,
1691                                 GTK_ICON_SIZE_DIALOG);
1692   g_object_notify (G_OBJECT (about), "logo-icon-name");
1693
1694   g_object_thaw_notify (G_OBJECT (about));
1695 }
1696
1697 static void
1698 activate_url (GtkWidget *widget, 
1699               gpointer   data)
1700 {
1701   GtkAboutDialog *about = GTK_ABOUT_DIALOG (data);
1702   const gchar *url = gtk_link_button_get_uri (GTK_LINK_BUTTON (widget));
1703   GtkAboutDialogActivateLinkFunc url_hook;
1704   gpointer url_hook_data;
1705
1706   if (activate_url_hook_set)
1707     {
1708       url_hook = activate_url_hook;
1709       url_hook_data = activate_url_hook_data;
1710     }
1711   else
1712     {
1713       url_hook = default_url_hook;
1714       url_hook_data = NULL;
1715     }
1716
1717   if (url_hook)
1718     url_hook (about, url, url_hook_data);
1719 }
1720
1721 static void
1722 follow_if_link (GtkAboutDialog *about,
1723                 GtkTextView    *text_view,
1724                 GtkTextIter    *iter)
1725 {
1726   GSList *tags = NULL, *tagp = NULL;
1727   GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data;
1728   gchar *url = NULL;
1729   GtkAboutDialogActivateLinkFunc email_hook, url_hook;
1730   gpointer email_hook_data, url_hook_data;
1731
1732   if (activate_email_hook_set)
1733     {
1734       email_hook = activate_email_hook;
1735       email_hook_data = activate_email_hook_data;
1736     }
1737   else
1738     {
1739       email_hook = default_email_hook;
1740       email_hook_data = NULL;
1741     }
1742
1743   if (activate_url_hook_set)
1744     {
1745       url_hook = activate_url_hook;
1746       url_hook_data = activate_url_hook_data;
1747     }
1748   else
1749     {
1750       url_hook = default_url_hook;
1751       url_hook_data = NULL;
1752     }
1753
1754   tags = gtk_text_iter_get_tags (iter);
1755   for (tagp = tags; tagp != NULL && !url; tagp = tagp->next)
1756     {
1757       GtkTextTag *tag = tagp->data;
1758
1759       if (email_hook != NULL)
1760         {
1761           url = g_object_get_data (G_OBJECT (tag), "email");
1762           if (url)
1763             email_hook (about, url, email_hook_data);
1764         }
1765
1766       if (!url && url_hook != NULL)
1767         {
1768           url = g_object_get_data (G_OBJECT (tag), "url");
1769           if (url) 
1770             url_hook (about, url, url_hook_data);
1771         }
1772
1773       if (url && !g_slist_find_custom (priv->visited_links, url, (GCompareFunc)strcmp))
1774         {
1775           GdkColor *style_visited_link_color;
1776           GdkColor color;
1777           
1778           gtk_widget_ensure_style (GTK_WIDGET (about));
1779           gtk_widget_style_get (GTK_WIDGET (about), 
1780                                 "visited-link-color", &style_visited_link_color, 
1781                                 NULL);
1782           if (style_visited_link_color)
1783             {
1784               color = *style_visited_link_color;
1785               gdk_color_free (style_visited_link_color);
1786             }
1787           else
1788             color = default_visited_link_color;
1789           
1790           g_object_set (G_OBJECT (tag), "foreground-gdk", &color, NULL);
1791
1792           priv->visited_links = g_slist_prepend (priv->visited_links, g_strdup (url));
1793         }
1794     }
1795
1796   if (tags) 
1797     g_slist_free (tags);
1798 }
1799
1800 static gboolean
1801 text_view_key_press_event (GtkWidget      *text_view,
1802                            GdkEventKey    *event,
1803                            GtkAboutDialog *about)
1804 {
1805   GtkTextIter iter;
1806   GtkTextBuffer *buffer;
1807
1808   switch (event->keyval)
1809     {
1810       case GDK_Return:
1811       case GDK_ISO_Enter:
1812       case GDK_KP_Enter:
1813         buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
1814         gtk_text_buffer_get_iter_at_mark (buffer, &iter, 
1815                                           gtk_text_buffer_get_insert (buffer));
1816         follow_if_link (about, GTK_TEXT_VIEW (text_view), &iter);
1817         break;
1818
1819       default:
1820         break;
1821     }
1822
1823   return FALSE;
1824 }
1825
1826 static gboolean
1827 text_view_event_after (GtkWidget      *text_view,
1828                        GdkEvent       *event,
1829                        GtkAboutDialog *about)
1830 {
1831   GtkTextIter start, end, iter;
1832   GtkTextBuffer *buffer;
1833   GdkEventButton *button_event;
1834   gint x, y;
1835
1836   if (event->type != GDK_BUTTON_RELEASE)
1837     return FALSE;
1838
1839   button_event = (GdkEventButton *)event;
1840
1841   if (button_event->button != 1)
1842     return FALSE;
1843
1844   buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
1845
1846   /* we shouldn't follow a link if the user has selected something */
1847   gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
1848   if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
1849     return FALSE;
1850
1851   gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), 
1852                                          GTK_TEXT_WINDOW_WIDGET,
1853                                          button_event->x, button_event->y, &x, &y);
1854
1855   gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y);
1856
1857   follow_if_link (about, GTK_TEXT_VIEW (text_view), &iter);
1858
1859   return FALSE;
1860 }
1861
1862 static void
1863 set_cursor_if_appropriate (GtkAboutDialog *about,
1864                            GtkTextView    *text_view,
1865                            gint            x,
1866                            gint            y)
1867 {
1868   GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data;
1869   GSList *tags = NULL, *tagp = NULL;
1870   GtkTextIter iter;
1871   gboolean hovering_over_link = FALSE;
1872
1873   gtk_text_view_get_iter_at_location (text_view, &iter, x, y);
1874   
1875   tags = gtk_text_iter_get_tags (&iter);
1876   for (tagp = tags;  tagp != NULL;  tagp = tagp->next)
1877     {
1878       GtkTextTag *tag = tagp->data;
1879       gchar *email = g_object_get_data (G_OBJECT (tag), "email");
1880       gchar *url = g_object_get_data (G_OBJECT (tag), "url");
1881
1882       if (email != NULL || url != NULL) 
1883         {
1884           hovering_over_link = TRUE;
1885           break;
1886         }
1887     }
1888
1889   if (hovering_over_link != priv->hovering_over_link)
1890     {
1891       priv->hovering_over_link = hovering_over_link;
1892
1893       if (hovering_over_link)
1894         gdk_window_set_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), priv->hand_cursor);
1895       else
1896         gdk_window_set_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), priv->regular_cursor);
1897     }
1898
1899   if (tags) 
1900     g_slist_free (tags);
1901 }
1902
1903 static gboolean
1904 text_view_motion_notify_event (GtkWidget *text_view,
1905                                GdkEventMotion *event,
1906                                GtkAboutDialog *about)
1907 {
1908   gint x, y;
1909
1910   gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), 
1911                                          GTK_TEXT_WINDOW_WIDGET,
1912                                          event->x, event->y, &x, &y);
1913
1914   set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), x, y);
1915
1916   gdk_event_request_motions (event);
1917
1918   return FALSE;
1919 }
1920
1921
1922 static gboolean
1923 text_view_visibility_notify_event (GtkWidget          *text_view,
1924                                    GdkEventVisibility *event,
1925                                    GtkAboutDialog     *about)
1926 {
1927   gint wx, wy, bx, by;
1928
1929   gdk_window_get_pointer (text_view->window, &wx, &wy, NULL);
1930
1931   gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), 
1932                                          GTK_TEXT_WINDOW_WIDGET,
1933                                          wx, wy, &bx, &by);
1934
1935   set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), bx, by);
1936
1937   return FALSE;
1938 }
1939
1940 static GtkWidget *
1941 text_view_new (GtkAboutDialog  *about,
1942                GtkWidget       *dialog,
1943                gchar          **strings,
1944                GtkWrapMode      wrap_mode)
1945 {
1946   gchar **p;
1947   gchar *q0, *q1, *q2, *r1, *r2;
1948   GtkWidget *view;
1949   GtkTextView *text_view;
1950   GtkTextBuffer *buffer;
1951   gboolean linkify_email, linkify_urls;
1952   GdkColor *style_link_color;
1953   GdkColor *style_visited_link_color;
1954   GdkColor color;
1955   GdkColor link_color;
1956   GdkColor visited_link_color;
1957   GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data;
1958   
1959   linkify_email = (!activate_email_hook_set || activate_email_hook != NULL);
1960   linkify_urls = (!activate_url_hook_set || activate_url_hook != NULL);
1961
1962   gtk_widget_ensure_style (GTK_WIDGET (about));
1963   gtk_widget_style_get (GTK_WIDGET (about),
1964                         "link-color", &style_link_color, 
1965                         "visited-link-color", &style_visited_link_color, 
1966                         NULL);
1967   if (style_link_color)
1968     {
1969       link_color = *style_link_color;
1970       gdk_color_free (style_link_color);
1971     }
1972   else
1973     link_color = default_link_color;
1974
1975   if (style_visited_link_color)
1976     {
1977       visited_link_color = *style_visited_link_color;
1978       gdk_color_free (style_visited_link_color);
1979     }
1980   else
1981     visited_link_color = default_visited_link_color;
1982
1983   view = gtk_text_view_new ();
1984   text_view = GTK_TEXT_VIEW (view);
1985   buffer = gtk_text_view_get_buffer (text_view);
1986   gtk_text_view_set_cursor_visible (text_view, FALSE);
1987   gtk_text_view_set_editable (text_view, FALSE);
1988   gtk_text_view_set_wrap_mode (text_view, wrap_mode);
1989
1990   gtk_text_view_set_left_margin (text_view, 8);
1991   gtk_text_view_set_right_margin (text_view, 8);
1992
1993   g_signal_connect (view, "key-press-event",
1994                     G_CALLBACK (text_view_key_press_event), about);
1995   g_signal_connect (view, "event-after",
1996                     G_CALLBACK (text_view_event_after), about);
1997   g_signal_connect (view, "motion-notify-event",
1998                     G_CALLBACK (text_view_motion_notify_event), about);
1999   g_signal_connect (view, "visibility-notify-event",
2000                     G_CALLBACK (text_view_visibility_notify_event), about);
2001
2002   if (strings == NULL)
2003     {
2004       gtk_widget_hide (view);
2005       return view;
2006     }
2007
2008   for (p = strings; *p; p++)
2009     {
2010       q0  = *p;
2011       while (*q0)
2012         {
2013           q1 = linkify_email ? strchr (q0, '<') : NULL;
2014           q2 = q1 ? strchr (q1, '>') : NULL;
2015           r1 = linkify_urls ? strstr (q0, "http://") : NULL;
2016           if (r1)
2017             {
2018               r2 = strpbrk (r1, " \n\t");
2019               if (!r2)
2020                 r2 = strchr (r1, '\0');
2021             }
2022           else  
2023             r2 = NULL;
2024
2025           if (r1 && r2 && (!q1 || !q2 || (r1 < q1))) 
2026             {
2027               q1 = r1;
2028               q2 = r2;
2029             }
2030
2031           if (q1 && q2) 
2032             {
2033               GtkTextIter end;
2034               gchar *link;
2035               const gchar *link_type;
2036               GtkTextTag *tag;
2037
2038               if (*q1 == '<')
2039                 {
2040                   gtk_text_buffer_insert_at_cursor (buffer, q0, (q1 - q0) + 1);
2041                   gtk_text_buffer_get_end_iter (buffer, &end);
2042                   q1++;
2043                   link_type = I_("email");
2044                 }
2045               else
2046                 {
2047                   gtk_text_buffer_insert_at_cursor (buffer, q0, q1 - q0);
2048                   gtk_text_buffer_get_end_iter (buffer, &end);
2049                   link_type = I_("url");
2050                 }
2051
2052               q0 = q2;
2053
2054               link = g_strndup (q1, q2 - q1);
2055
2056               if (g_slist_find_custom (priv->visited_links, link, (GCompareFunc)strcmp))
2057                 color = visited_link_color;
2058               else
2059                 color = link_color;
2060               
2061               tag = gtk_text_buffer_create_tag (buffer, NULL, 
2062                                                 "foreground-gdk", &color, 
2063                                                 "underline", PANGO_UNDERLINE_SINGLE, 
2064                                                 NULL);
2065               g_object_set_data_full (G_OBJECT (tag), link_type, g_strdup (link), g_free);
2066               gtk_text_buffer_insert_with_tags (buffer, &end, link, -1, tag, NULL);
2067               
2068               g_free (link);
2069             }
2070           else
2071             {
2072               gtk_text_buffer_insert_at_cursor (buffer, q0, -1);
2073               break;
2074             }
2075         }
2076       
2077       if (p[1])
2078         gtk_text_buffer_insert_at_cursor (buffer, "\n", 1);
2079     }
2080
2081   gtk_widget_show (view);
2082   return view;
2083 }
2084
2085 static void
2086 add_credits_page (GtkAboutDialog *about,
2087                   GtkWidget      *credits_dialog,
2088                   GtkWidget      *notebook,
2089                   gchar          *title,
2090                   gchar         **people)
2091 {
2092   GtkWidget *sw, *view;
2093
2094   view = text_view_new (about, credits_dialog, people, GTK_WRAP_NONE);
2095
2096   sw = gtk_scrolled_window_new (NULL, NULL);
2097   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
2098                                        GTK_SHADOW_IN);
2099   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2100                                   GTK_POLICY_AUTOMATIC,
2101                                   GTK_POLICY_AUTOMATIC);
2102   gtk_container_add (GTK_CONTAINER (sw), view);
2103   
2104   gtk_notebook_append_page (GTK_NOTEBOOK (notebook), 
2105                             sw, gtk_label_new (title));
2106 }
2107
2108 static void
2109 display_credits_dialog (GtkWidget *button, 
2110                         gpointer   data)
2111 {
2112   GtkAboutDialog *about = (GtkAboutDialog *)data;
2113   GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data;
2114   GtkWidget *dialog, *notebook;
2115   GtkDialog *credits_dialog;
2116
2117   if (priv->credits_dialog != NULL)
2118     {
2119       gtk_window_present (GTK_WINDOW (priv->credits_dialog));
2120       return;
2121     }
2122         
2123   dialog = gtk_dialog_new_with_buttons (_("Credits"),
2124                                         GTK_WINDOW (about),
2125                                         GTK_DIALOG_DESTROY_WITH_PARENT,
2126                                         GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
2127                                         NULL);
2128   credits_dialog = GTK_DIALOG (dialog);
2129   gtk_dialog_set_has_separator (credits_dialog, FALSE);
2130   gtk_container_set_border_width (GTK_CONTAINER (credits_dialog), 5);
2131   gtk_box_set_spacing (GTK_BOX (credits_dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
2132   gtk_container_set_border_width (GTK_CONTAINER (credits_dialog->action_area), 5);
2133
2134   priv->credits_dialog = dialog;
2135   gtk_window_set_default_size (GTK_WINDOW (dialog), 360, 260);
2136   gtk_dialog_set_default_response (credits_dialog, GTK_RESPONSE_CANCEL);
2137
2138   gtk_window_set_modal (GTK_WINDOW (dialog), 
2139                         gtk_window_get_modal (GTK_WINDOW (about)));
2140
2141   g_signal_connect (dialog, "response",
2142                     G_CALLBACK (gtk_widget_destroy), dialog);
2143   g_signal_connect (dialog, "destroy",
2144                     G_CALLBACK (gtk_widget_destroyed),
2145                     &(priv->credits_dialog));
2146
2147   notebook = gtk_notebook_new ();
2148   gtk_container_set_border_width (GTK_CONTAINER (notebook), 5);
2149   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), notebook, TRUE, TRUE, 0);
2150
2151   if (priv->authors != NULL) 
2152     add_credits_page (about, dialog, notebook, _("Written by"), priv->authors);
2153   
2154   if (priv->documenters != NULL)
2155     add_credits_page (about, dialog, notebook, _("Documented by"), priv->documenters);
2156     
2157   /* Don't show an untranslated gettext msgid */
2158   if (priv->translator_credits != NULL &&
2159       strcmp (priv->translator_credits, "translator_credits") &&
2160       strcmp (priv->translator_credits, "translator-credits")) 
2161     {
2162       gchar *translators[2];
2163       
2164       translators[0] = priv->translator_credits;
2165       translators[1] = NULL;
2166
2167       add_credits_page (about, dialog, notebook, _("Translated by"), translators);
2168     }
2169
2170   if (priv->artists != NULL) 
2171     add_credits_page (about, dialog, notebook, _("Artwork by"), priv->artists);
2172   
2173   gtk_widget_show_all (dialog);
2174 }
2175
2176 static void
2177 set_policy (GtkWidget *sw)
2178 {
2179   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2180                                   GTK_POLICY_AUTOMATIC,
2181                                   GTK_POLICY_AUTOMATIC);  
2182 }
2183
2184 static void
2185 display_license_dialog (GtkWidget *button, 
2186                         gpointer   data)
2187 {
2188   GtkAboutDialog *about = (GtkAboutDialog *)data;
2189   GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data;
2190   GtkWidget *dialog, *view, *sw;
2191   GtkDialog *licence_dialog;
2192   gchar *strings[2];
2193   
2194   if (priv->license_dialog != NULL)
2195     {
2196       gtk_window_present (GTK_WINDOW (priv->license_dialog));
2197       return;
2198     }
2199         
2200   dialog = gtk_dialog_new_with_buttons (_("License"),
2201                                         GTK_WINDOW (about),
2202                                         GTK_DIALOG_DESTROY_WITH_PARENT,
2203                                         GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
2204                                         NULL);
2205   licence_dialog = GTK_DIALOG (dialog);
2206   gtk_dialog_set_has_separator (licence_dialog, FALSE);
2207   gtk_container_set_border_width (GTK_CONTAINER (licence_dialog), 5);
2208   gtk_box_set_spacing (GTK_BOX (licence_dialog->vbox), 2); /* 2 * 5 + 2 = 12 */
2209   gtk_container_set_border_width (GTK_CONTAINER (licence_dialog->action_area), 5);
2210
2211   priv->license_dialog = dialog;
2212   gtk_window_set_default_size (GTK_WINDOW (dialog), 420, 320);
2213   gtk_dialog_set_default_response (licence_dialog, GTK_RESPONSE_CANCEL);
2214
2215   gtk_window_set_modal (GTK_WINDOW (dialog), 
2216                         gtk_window_get_modal (GTK_WINDOW (about)));
2217
2218   g_signal_connect (dialog, "response",
2219                     G_CALLBACK (gtk_widget_destroy), dialog);
2220   g_signal_connect (dialog, "destroy",
2221                     G_CALLBACK (gtk_widget_destroyed),
2222                     &(priv->license_dialog));
2223
2224   sw = gtk_scrolled_window_new (NULL, NULL);
2225   gtk_container_set_border_width (GTK_CONTAINER (sw), 5);
2226   gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
2227                                        GTK_SHADOW_IN);
2228   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2229                                   GTK_POLICY_NEVER,
2230                                   GTK_POLICY_AUTOMATIC);
2231   g_signal_connect (sw, "map", G_CALLBACK (set_policy), NULL);
2232   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), sw, TRUE, TRUE, 0);
2233
2234   strings[0] = priv->license;
2235   strings[1] = NULL;
2236   view = text_view_new (about, dialog, strings,
2237                         priv->wrap_license ? GTK_WRAP_WORD : GTK_WRAP_NONE);
2238
2239   gtk_container_add (GTK_CONTAINER (sw), view);
2240
2241   gtk_widget_show_all (dialog);
2242 }
2243
2244 /**
2245  * gtk_about_dialog_new:
2246  *
2247  * Creates a new #GtkAboutDialog.
2248  *
2249  * Returns: a newly created #GtkAboutDialog
2250  *
2251  * Since: 2.6
2252  */
2253 GtkWidget *
2254 gtk_about_dialog_new (void)
2255 {
2256   GtkAboutDialog *dialog = g_object_new (GTK_TYPE_ABOUT_DIALOG, NULL);
2257
2258   return GTK_WIDGET (dialog);
2259 }
2260
2261 /**
2262  * gtk_about_dialog_set_email_hook:
2263  * @func: a function to call when an email link is activated.
2264  * @data: data to pass to @func
2265  * @destroy: #GDestroyNotify for @data
2266  * 
2267  * Installs a global function to be called whenever the user activates an
2268  * email link in an about dialog. 
2269  *
2270  * Since 2.18 there exists a default function which uses gtk_show_uri(). To
2271  * deactivate it, you can pass %NULL for @func.
2272  * 
2273  * Return value: the previous email hook.
2274  *
2275  * Since: 2.6
2276  */
2277 GtkAboutDialogActivateLinkFunc      
2278 gtk_about_dialog_set_email_hook (GtkAboutDialogActivateLinkFunc func, 
2279                                  gpointer                       data, 
2280                                  GDestroyNotify                 destroy)
2281 {
2282   GtkAboutDialogActivateLinkFunc old;
2283
2284   if (activate_email_hook_destroy != NULL)
2285     (* activate_email_hook_destroy) (activate_email_hook_data);
2286
2287   old = activate_email_hook;
2288
2289   activate_email_hook_set = TRUE;
2290   activate_email_hook = func;
2291   activate_email_hook_data = data;
2292   activate_email_hook_destroy = destroy;
2293
2294   return old;
2295 }
2296
2297 /**
2298  * gtk_about_dialog_set_url_hook:
2299  * @func: a function to call when a URL link is activated.
2300  * @data: data to pass to @func
2301  * @destroy: #GDestroyNotify for @data
2302  * 
2303  * Installs a global function to be called whenever the user activates a
2304  * URL link in an about dialog.
2305  * 
2306  * Since 2.18 here exists a default function which uses gtk_show_uri(). To
2307  * deactivate it, you can pass %NULL for @func.
2308  * 
2309  * Return value: the previous URL hook.
2310  *
2311  * Since: 2.6
2312  */
2313 GtkAboutDialogActivateLinkFunc      
2314 gtk_about_dialog_set_url_hook (GtkAboutDialogActivateLinkFunc func, 
2315                                gpointer                       data, 
2316                                GDestroyNotify                 destroy)
2317 {
2318   GtkAboutDialogActivateLinkFunc old;
2319
2320   if (activate_url_hook_destroy != NULL)
2321     (* activate_url_hook_destroy) (activate_url_hook_data);
2322
2323   old = activate_url_hook;
2324
2325   activate_url_hook_set = TRUE;
2326   activate_url_hook = func;
2327   activate_url_hook_data = data;
2328   activate_url_hook_destroy = destroy;
2329
2330   return old;
2331 }
2332
2333 static void 
2334 close_cb (GtkAboutDialog *about)
2335 {
2336   GtkAboutDialogPrivate *priv = (GtkAboutDialogPrivate *)about->private_data;
2337
2338   if (priv->license_dialog != NULL)
2339     {
2340       gtk_widget_destroy (priv->license_dialog);
2341       priv->license_dialog = NULL;
2342     }
2343
2344   if (priv->credits_dialog != NULL)
2345     {
2346       gtk_widget_destroy (priv->credits_dialog);
2347       priv->credits_dialog = NULL;
2348     }
2349
2350   gtk_widget_hide (GTK_WIDGET (about));
2351   
2352 }
2353
2354 /**
2355  * gtk_show_about_dialog:
2356  * @parent: transient parent, or %NULL for none
2357  * @first_property_name: the name of the first property 
2358  * @Varargs: value of first property, followed by more properties, %NULL-terminated
2359  *
2360  * This is a convenience function for showing an application's about box.
2361  * The constructed dialog is associated with the parent window and 
2362  * reused for future invocations of this function.
2363  *
2364  * Since: 2.6
2365  */
2366 void
2367 gtk_show_about_dialog (GtkWindow   *parent,
2368                        const gchar *first_property_name,
2369                        ...)
2370 {
2371   static GtkWidget *global_about_dialog = NULL;
2372   GtkWidget *dialog = NULL;
2373   va_list var_args;
2374
2375   if (parent)
2376     dialog = g_object_get_data (G_OBJECT (parent), "gtk-about-dialog");
2377   else 
2378     dialog = global_about_dialog;
2379
2380   if (!dialog) 
2381     {
2382       dialog = gtk_about_dialog_new ();
2383
2384       g_object_ref_sink (dialog);
2385
2386       g_signal_connect (dialog, "delete-event",
2387                         G_CALLBACK (gtk_widget_hide_on_delete), NULL);
2388
2389       /* Close dialog on user response */
2390       g_signal_connect (dialog, "response",
2391                         G_CALLBACK (close_cb), NULL);
2392
2393       va_start (var_args, first_property_name);
2394       g_object_set_valist (G_OBJECT (dialog), first_property_name, var_args);
2395       va_end (var_args);
2396
2397       if (parent) 
2398         {
2399           gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
2400           gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
2401           g_object_set_data_full (G_OBJECT (parent), 
2402                                   I_("gtk-about-dialog"), 
2403                                   dialog, g_object_unref);
2404         }
2405       else 
2406         global_about_dialog = dialog;
2407       
2408     }
2409   
2410   gtk_window_present (GTK_WINDOW (dialog));
2411 }
2412
2413 #define __GTK_ABOUT_DIALOG_C__
2414 #include "gtkaliasdef.c"