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