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