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