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