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