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