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