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