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