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