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