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