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>
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.
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.
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.
23 * Author: Anders Carlsson <andersca@gnome.org>
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/.
35 #include <gdk/gdkkeysyms.h>
37 #include "gtkaboutdialog.h"
38 #include "gtkbutton.h"
40 #include "gtkdialog.h"
44 #include "gtklinkbutton.h"
45 #include "gtkmarshalers.h"
46 #include "gtknotebook.h"
47 #include "gtkscrolledwindow.h"
49 #include "gtktextview.h"
51 #include "gtkiconfactory.h"
54 #include "gtkmessagedialog.h"
55 #include "gtkprivate.h"
60 * SECTION:gtkaboutdialog
61 * @Short_description: Display information about an application
62 * @Title: GtkAboutDialog
63 * @See_also: #GTK_STOCK_ABOUT
65 * The GtkAboutDialog offers a simple way to display information about
66 * a program like its logo, name, copyright, website and license. It is
67 * also possible to give credits to the authors, documenters, translators
68 * and artists who have worked on the program. An about dialog is typically
69 * opened when the user selects the <literal>About</literal> option from
70 * the <literal>Help</literal> menu. All parts of the dialog are optional.
72 * About dialog often contain links and email addresses. GtkAboutDialog
73 * displays these as clickable links. By default, it calls gtk_show_uri()
74 * when a user clicks one. The behaviour can be overridden with the
75 * #GtkAboutDialog::activate-link signal.
77 * To make constructing a GtkAboutDialog as convenient as possible, you can
78 * use the function gtk_show_about_dialog() which constructs and shows a dialog
79 * and keeps it around so that it can be shown again.
81 * Note that GTK+ sets a default title of <literal>_("About %s")</literal>
82 * on the dialog window (where %s is replaced by the name of the
83 * application, but in order to ensure proper translation of the title,
84 * applications should set the title property explicitly when constructing
85 * a GtkAboutDialog, as shown in the following example:
86 * <informalexample><programlisting>
87 * gtk_show_about_dialog (NULL,
88 * "program-name", "ExampleCode",
89 * "logo", example_logo,
90 * "title" _("About ExampleCode"),
92 * </programlisting></informalexample>
95 static GdkColor default_link_color = { 0, 0, 0, 0xeeee };
96 static GdkColor default_visited_link_color = { 0, 0x5555, 0x1a1a, 0x8b8b };
98 /* Translators: this is the license preamble; the string at the end
99 * contains the URL of the license.
101 static const gchar *gtk_license_preamble = N_("This program comes with ABSOLUTELY NO WARRANTY; for details, visit %s");
103 /* URLs for each GtkLicense type; keep in the same order as the enumeration */
104 static const gchar *gtk_license_urls[] = {
108 "http://www.gnu.org/licenses/old-licenses/gpl-2.0.html",
109 "http://www.gnu.org/licenses/gpl.html",
111 "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html",
112 "http://www.gnu.org/licenses/lgpl.html",
114 "http://opensource.org/licenses/bsd-license.php",
115 "http://opensource.org/licenses/mit-license.php",
117 "http://opensource.org/licenses/artistic-license-2.0.php"
120 struct _GtkAboutDialogPrivate
128 gchar *translator_credits;
135 GtkWidget *logo_image;
136 GtkWidget *name_label;
137 GtkWidget *comments_label;
138 GtkWidget *copyright_label;
139 GtkWidget *website_label;
141 GtkWidget *credits_button;
142 GtkWidget *credits_dialog;
143 GtkWidget *license_button;
144 GtkWidget *license_dialog;
146 GdkCursor *hand_cursor;
147 GdkCursor *regular_cursor;
149 GSList *visited_links;
151 GtkLicense license_type;
153 guint hovering_over_link : 1;
154 guint wrap_license : 1;
157 #define GTK_ABOUT_DIALOG_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GTK_TYPE_ABOUT_DIALOG, GtkAboutDialogPrivate))
172 PROP_TRANSLATOR_CREDITS,
180 static void gtk_about_dialog_finalize (GObject *object);
181 static void gtk_about_dialog_get_property (GObject *object,
185 static void gtk_about_dialog_set_property (GObject *object,
189 static void gtk_about_dialog_show (GtkWidget *widge);
190 static void update_name_version (GtkAboutDialog *about);
191 static GtkIconSet * icon_set_new_from_pixbufs (GList *pixbufs);
192 static void follow_if_link (GtkAboutDialog *about,
193 GtkTextView *text_view,
195 static void set_cursor_if_appropriate (GtkAboutDialog *about,
196 GtkTextView *text_view,
200 static void display_credits_dialog (GtkWidget *button,
202 static void display_license_dialog (GtkWidget *button,
204 static void close_cb (GtkAboutDialog *about);
205 static gboolean gtk_about_dialog_activate_link (GtkAboutDialog *about,
213 static guint signals[LAST_SIGNAL] = { 0 };
215 G_DEFINE_TYPE (GtkAboutDialog, gtk_about_dialog, GTK_TYPE_DIALOG)
219 gtk_about_dialog_class_init (GtkAboutDialogClass *klass)
221 GObjectClass *object_class;
222 GtkWidgetClass *widget_class;
224 object_class = (GObjectClass *)klass;
225 widget_class = (GtkWidgetClass *)klass;
227 object_class->set_property = gtk_about_dialog_set_property;
228 object_class->get_property = gtk_about_dialog_get_property;
230 object_class->finalize = gtk_about_dialog_finalize;
232 widget_class->show = gtk_about_dialog_show;
234 klass->activate_link = gtk_about_dialog_activate_link;
237 * GtkAboutDialog::activate-link:
238 * @label: The object on which the signal was emitted
239 * @uri: the URI that is activated
241 * The signal which gets emitted to activate a URI.
242 * Applications may connect to it to override the default behaviour,
243 * which is to call gtk_show_uri().
245 * Returns: %TRUE if the link has been activated
249 signals[ACTIVATE_LINK] =
250 g_signal_new ("activate-link",
251 G_TYPE_FROM_CLASS (object_class),
253 G_STRUCT_OFFSET (GtkAboutDialogClass, activate_link),
254 _gtk_boolean_handled_accumulator, NULL,
255 _gtk_marshal_BOOLEAN__STRING,
256 G_TYPE_BOOLEAN, 1, G_TYPE_STRING);
259 * GtkAboutDialog:program-name:
261 * The name of the program.
262 * If this is not set, it defaults to g_get_application_name().
266 g_object_class_install_property (object_class,
268 g_param_spec_string ("program-name",
270 P_("The name of the program. If this is not set, it defaults to g_get_application_name()"),
272 GTK_PARAM_READWRITE));
275 * GtkAboutDialog:version:
277 * The version of the program.
281 g_object_class_install_property (object_class,
283 g_param_spec_string ("version",
284 P_("Program version"),
285 P_("The version of the program"),
287 GTK_PARAM_READWRITE));
290 * GtkAboutDialog:copyright:
292 * Copyright information for the program.
296 g_object_class_install_property (object_class,
298 g_param_spec_string ("copyright",
299 P_("Copyright string"),
300 P_("Copyright information for the program"),
302 GTK_PARAM_READWRITE));
306 * GtkAboutDialog:comments:
308 * Comments about the program. This string is displayed in a label
309 * in the main dialog, thus it should be a short explanation of
310 * the main purpose of the program, not a detailed list of features.
314 g_object_class_install_property (object_class,
316 g_param_spec_string ("comments",
317 P_("Comments string"),
318 P_("Comments about the program"),
320 GTK_PARAM_READWRITE));
323 * GtkAboutDialog:license:
325 * The license of the program. This string is displayed in a
326 * text view in a secondary dialog, therefore it is fine to use
327 * a long multi-paragraph text. Note that the text is only wrapped
328 * in the text view if the "wrap-license" property is set to %TRUE;
329 * otherwise the text itself must contain the intended linebreaks.
330 * When setting this property to a non-%NULL value, the
331 * #GtkAboutDialog:license-type property is set to %GTK_LICENSE_CUSTOM
336 g_object_class_install_property (object_class,
338 g_param_spec_string ("license",
340 _("The license of the program"),
342 GTK_PARAM_READWRITE));
345 * GtkAboutDialog:license-type:
347 * The license of the program, as a value of the %GtkLicense enumeration.
349 * The #GtkAboutDialog will automatically fill out a standard disclaimer
350 * and link the user to the appropriate online resource for the license
353 * If %GTK_LICENSE_UNKNOWN is used, the link used will be the same
354 * specified in the #GtkAboutDialog:website property.
356 * If %GTK_LICENSE_CUSTOM is used, the current contents of the
357 * #GtkAboutDialog:license property are used.
359 * For any other #GtkLicense value, the contents of the
360 * #GtkAboutDialog:license property are also set by this property as
365 g_object_class_install_property (object_class,
367 g_param_spec_enum ("license-type",
369 P_("The license type of the program"),
372 GTK_PARAM_READWRITE));
375 * GtkAboutDialog:website:
377 * The URL for the link to the website of the program.
378 * This should be a string starting with "http://.
382 g_object_class_install_property (object_class,
384 g_param_spec_string ("website",
386 P_("The URL for the link to the website of the program"),
388 GTK_PARAM_READWRITE));
391 * GtkAboutDialog:website-label:
393 * The label for the link to the website of the program. If this is not set,
394 * it defaults to the URL specified in the #GtkAboutDialog:website property.
398 g_object_class_install_property (object_class,
400 g_param_spec_string ("website-label",
402 P_("The label for the link to the website of the program. If this is not set, it defaults to the URL"),
404 GTK_PARAM_READWRITE));
407 * GtkAboutDialog:authors:
409 * The authors of the program, as a %NULL-terminated array of strings.
410 * Each string may contain email addresses and URLs, which will be displayed
411 * as links, see the introduction for more details.
415 g_object_class_install_property (object_class,
417 g_param_spec_boxed ("authors",
419 P_("List of authors of the program"),
421 GTK_PARAM_READWRITE));
424 * GtkAboutDialog:documenters:
426 * The people documenting the program, as a %NULL-terminated array of strings.
427 * Each string may contain email addresses and URLs, which will be displayed
428 * as links, see the introduction for more details.
432 g_object_class_install_property (object_class,
434 g_param_spec_boxed ("documenters",
436 P_("List of people documenting the program"),
438 GTK_PARAM_READWRITE));
441 * GtkAboutDialog:artists:
443 * The people who contributed artwork to the program, as a %NULL-terminated
444 * array of strings. Each string may contain email addresses and URLs, which
445 * will be displayed as links, see the introduction for more details.
449 g_object_class_install_property (object_class,
451 g_param_spec_boxed ("artists",
453 P_("List of people who have contributed artwork to the program"),
455 GTK_PARAM_READWRITE));
459 * GtkAboutDialog:translator-credits:
461 * Credits to the translators. This string should be marked as translatable.
462 * The string may contain email addresses and URLs, which will be displayed
463 * as links, see the introduction for more details.
467 g_object_class_install_property (object_class,
468 PROP_TRANSLATOR_CREDITS,
469 g_param_spec_string ("translator-credits",
470 P_("Translator credits"),
471 P_("Credits to the translators. This string should be marked as translatable"),
473 GTK_PARAM_READWRITE));
476 * GtkAboutDialog:logo:
478 * A logo for the about box. If this is not set, it defaults to
479 * gtk_window_get_default_icon_list().
483 g_object_class_install_property (object_class,
485 g_param_spec_object ("logo",
487 P_("A logo for the about box. If this is not set, it defaults to gtk_window_get_default_icon_list()"),
489 GTK_PARAM_READWRITE));
492 * GtkAboutDialog:logo-icon-name:
494 * A named icon to use as the logo for the about box. This property
495 * overrides the #GtkAboutDialog:logo property.
499 g_object_class_install_property (object_class,
501 g_param_spec_string ("logo-icon-name",
502 P_("Logo Icon Name"),
503 P_("A named icon to use as the logo for the about box."),
505 GTK_PARAM_READWRITE));
507 * GtkAboutDialog:wrap-license:
509 * Whether to wrap the text in the license dialog.
513 g_object_class_install_property (object_class,
515 g_param_spec_boolean ("wrap-license",
517 P_("Whether to wrap the license text."),
519 GTK_PARAM_READWRITE));
522 g_type_class_add_private (object_class, sizeof (GtkAboutDialogPrivate));
526 emit_activate_link (GtkAboutDialog *about,
529 gboolean handled = FALSE;
531 g_signal_emit (about, signals[ACTIVATE_LINK], 0, uri, &handled);
537 gtk_about_dialog_init (GtkAboutDialog *about)
539 GtkDialog *dialog = GTK_DIALOG (about);
540 GtkAboutDialogPrivate *priv;
541 GtkWidget *vbox, *hbox, *button, *close_button, *image;
542 GtkWidget *content_area, *action_area;
545 priv = GTK_ABOUT_DIALOG_GET_PRIVATE (about);
549 priv->version = NULL;
550 priv->copyright = NULL;
551 priv->comments = NULL;
552 priv->website_url = NULL;
553 priv->website_text = NULL;
554 priv->translator_credits = NULL;
555 priv->license = NULL;
556 priv->authors = NULL;
557 priv->documenters = NULL;
558 priv->artists = NULL;
560 priv->hand_cursor = gdk_cursor_new (GDK_HAND2);
561 priv->regular_cursor = gdk_cursor_new (GDK_XTERM);
562 priv->hovering_over_link = FALSE;
563 priv->wrap_license = FALSE;
565 priv->license_type = GTK_LICENSE_UNKNOWN;
567 content_area = gtk_dialog_get_content_area (dialog);
568 action_area = gtk_dialog_get_action_area (dialog);
570 gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
571 gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
572 gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
575 gtk_widget_push_composite_child ();
577 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 8);
578 gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
579 gtk_box_pack_start (GTK_BOX (content_area), vbox, TRUE, TRUE, 0);
581 priv->logo_image = gtk_image_new ();
582 gtk_box_pack_start (GTK_BOX (vbox), priv->logo_image, FALSE, FALSE, 0);
584 priv->name_label = gtk_label_new (NULL);
585 gtk_label_set_selectable (GTK_LABEL (priv->name_label), TRUE);
586 gtk_label_set_justify (GTK_LABEL (priv->name_label), GTK_JUSTIFY_CENTER);
587 gtk_box_pack_start (GTK_BOX (vbox), priv->name_label, FALSE, FALSE, 0);
589 priv->comments_label = gtk_label_new (NULL);
590 gtk_label_set_selectable (GTK_LABEL (priv->comments_label), TRUE);
591 gtk_label_set_justify (GTK_LABEL (priv->comments_label), GTK_JUSTIFY_CENTER);
592 gtk_label_set_line_wrap (GTK_LABEL (priv->comments_label), TRUE);
593 gtk_box_pack_start (GTK_BOX (vbox), priv->comments_label, FALSE, FALSE, 0);
595 priv->copyright_label = gtk_label_new (NULL);
596 gtk_label_set_selectable (GTK_LABEL (priv->copyright_label), TRUE);
597 gtk_label_set_justify (GTK_LABEL (priv->copyright_label), GTK_JUSTIFY_CENTER);
598 gtk_box_pack_start (GTK_BOX (vbox), priv->copyright_label, FALSE, FALSE, 0);
600 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
601 gtk_box_set_homogeneous (GTK_BOX (hbox), TRUE);
602 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, FALSE, 0);
604 priv->website_label = button = gtk_label_new ("");
605 gtk_widget_set_no_show_all (button, TRUE);
606 gtk_label_set_selectable (GTK_LABEL (button), TRUE);
607 gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
608 g_signal_connect_swapped (button, "activate-link",
609 G_CALLBACK (emit_activate_link), about);
611 gtk_widget_show (vbox);
612 gtk_widget_show (priv->logo_image);
613 gtk_widget_show (priv->name_label);
614 gtk_widget_show (hbox);
616 /* Add the close button */
617 close_button = gtk_dialog_add_button (GTK_DIALOG (about), GTK_STOCK_CLOSE,
618 GTK_RESPONSE_CANCEL);
619 gtk_dialog_set_default_response (GTK_DIALOG (about), GTK_RESPONSE_CANCEL);
621 /* Add the credits button */
622 button = gtk_button_new_with_mnemonic (_("C_redits"));
623 gtk_widget_set_can_default (button, TRUE);
624 image = gtk_image_new_from_stock (GTK_STOCK_ABOUT, GTK_ICON_SIZE_BUTTON);
625 gtk_button_set_image (GTK_BUTTON (button), image);
626 gtk_widget_set_no_show_all (button, TRUE);
627 gtk_box_pack_end (GTK_BOX (action_area),
628 button, FALSE, TRUE, 0);
629 gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (action_area), button, TRUE);
630 g_signal_connect (button, "clicked",
631 G_CALLBACK (display_credits_dialog), about);
632 priv->credits_button = button;
633 priv->credits_dialog = NULL;
635 /* Add the license button */
636 button = gtk_button_new_from_stock (_("_License"));
637 gtk_widget_set_can_default (button, TRUE);
638 gtk_widget_set_no_show_all (button, TRUE);
639 gtk_box_pack_end (GTK_BOX (action_area),
640 button, FALSE, TRUE, 0);
641 gtk_button_box_set_child_secondary (GTK_BUTTON_BOX (action_area), button, TRUE);
642 g_signal_connect (button, "clicked",
643 G_CALLBACK (display_license_dialog), about);
644 priv->license_button = button;
645 priv->license_dialog = NULL;
647 gtk_window_set_resizable (GTK_WINDOW (about), FALSE);
649 gtk_widget_pop_composite_child ();
651 gtk_widget_grab_default (close_button);
652 gtk_widget_grab_focus (close_button);
655 gtk_about_dialog_set_program_name (about, NULL);
656 gtk_about_dialog_set_logo (about, NULL);
660 gtk_about_dialog_finalize (GObject *object)
662 GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
663 GtkAboutDialogPrivate *priv = about->priv;
666 g_free (priv->version);
667 g_free (priv->copyright);
668 g_free (priv->comments);
669 g_free (priv->license);
670 g_free (priv->website_url);
671 g_free (priv->website_text);
672 g_free (priv->translator_credits);
674 g_strfreev (priv->authors);
675 g_strfreev (priv->documenters);
676 g_strfreev (priv->artists);
678 g_slist_foreach (priv->visited_links, (GFunc)g_free, NULL);
679 g_slist_free (priv->visited_links);
681 gdk_cursor_unref (priv->hand_cursor);
682 gdk_cursor_unref (priv->regular_cursor);
684 G_OBJECT_CLASS (gtk_about_dialog_parent_class)->finalize (object);
688 gtk_about_dialog_set_property (GObject *object,
693 GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
694 GtkAboutDialogPrivate *priv = about->priv;
699 gtk_about_dialog_set_program_name (about, g_value_get_string (value));
702 gtk_about_dialog_set_version (about, g_value_get_string (value));
705 gtk_about_dialog_set_comments (about, g_value_get_string (value));
708 gtk_about_dialog_set_website (about, g_value_get_string (value));
710 case PROP_WEBSITE_LABEL:
711 gtk_about_dialog_set_website_label (about, g_value_get_string (value));
714 gtk_about_dialog_set_license (about, g_value_get_string (value));
716 case PROP_LICENSE_TYPE:
717 gtk_about_dialog_set_license_type (about, g_value_get_enum (value));
720 gtk_about_dialog_set_copyright (about, g_value_get_string (value));
723 gtk_about_dialog_set_logo (about, g_value_get_object (value));
726 gtk_about_dialog_set_authors (about, (const gchar**)g_value_get_boxed (value));
728 case PROP_DOCUMENTERS:
729 gtk_about_dialog_set_documenters (about, (const gchar**)g_value_get_boxed (value));
732 gtk_about_dialog_set_artists (about, (const gchar**)g_value_get_boxed (value));
734 case PROP_TRANSLATOR_CREDITS:
735 gtk_about_dialog_set_translator_credits (about, g_value_get_string (value));
737 case PROP_LOGO_ICON_NAME:
738 gtk_about_dialog_set_logo_icon_name (about, g_value_get_string (value));
740 case PROP_WRAP_LICENSE:
741 priv->wrap_license = g_value_get_boolean (value);
744 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
750 gtk_about_dialog_get_property (GObject *object,
755 GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
756 GtkAboutDialogPrivate *priv = about->priv;
761 g_value_set_string (value, priv->name);
764 g_value_set_string (value, priv->version);
767 g_value_set_string (value, priv->copyright);
770 g_value_set_string (value, priv->comments);
773 g_value_set_string (value, priv->website_url);
775 case PROP_WEBSITE_LABEL:
776 g_value_set_string (value, priv->website_text);
779 g_value_set_string (value, priv->license);
781 case PROP_LICENSE_TYPE:
782 g_value_set_enum (value, priv->license_type);
784 case PROP_TRANSLATOR_CREDITS:
785 g_value_set_string (value, priv->translator_credits);
788 g_value_set_boxed (value, priv->authors);
790 case PROP_DOCUMENTERS:
791 g_value_set_boxed (value, priv->documenters);
794 g_value_set_boxed (value, priv->artists);
797 if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
798 g_value_set_object (value, gtk_image_get_pixbuf (GTK_IMAGE (priv->logo_image)));
800 g_value_set_object (value, NULL);
802 case PROP_LOGO_ICON_NAME:
803 if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_ICON_NAME)
805 const gchar *icon_name;
807 gtk_image_get_icon_name (GTK_IMAGE (priv->logo_image), &icon_name, NULL);
808 g_value_set_string (value, icon_name);
811 g_value_set_string (value, NULL);
813 case PROP_WRAP_LICENSE:
814 g_value_set_boolean (value, priv->wrap_license);
817 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
823 gtk_about_dialog_activate_link (GtkAboutDialog *about,
827 GError *error = NULL;
829 screen = gtk_widget_get_screen (GTK_WIDGET (about));
831 if (!gtk_show_uri (screen, uri, gtk_get_current_event_time (), &error))
835 dialog = gtk_message_dialog_new (GTK_WINDOW (about),
836 GTK_DIALOG_DESTROY_WITH_PARENT |
840 "%s", _("Could not show link"));
841 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
842 "%s", error->message);
843 g_error_free (error);
845 g_signal_connect (dialog, "response",
846 G_CALLBACK (gtk_widget_destroy), NULL);
848 gtk_window_present (GTK_WINDOW (dialog));
855 update_website (GtkAboutDialog *about)
857 GtkAboutDialogPrivate *priv = about->priv;
859 gtk_widget_show (priv->website_label);
861 if (priv->website_url)
865 if (priv->website_text)
869 escaped = g_markup_escape_text (priv->website_text, -1);
870 markup = g_strdup_printf ("<a href=\"%s\">%s</a>",
871 priv->website_url, escaped);
876 markup = g_strdup_printf ("<a href=\"%s\">%s</a>",
877 priv->website_url, priv->website_url);
880 gtk_label_set_markup (GTK_LABEL (priv->website_label), markup);
885 if (priv->website_url)
886 gtk_label_set_text (GTK_LABEL (priv->website_label), priv->website_url);
887 else if (priv->website_text)
888 gtk_label_set_text (GTK_LABEL (priv->website_label), priv->website_text);
890 gtk_widget_hide (priv->website_label);
895 gtk_about_dialog_show (GtkWidget *widget)
897 update_website (GTK_ABOUT_DIALOG (widget));
899 GTK_WIDGET_CLASS (gtk_about_dialog_parent_class)->show (widget);
903 * gtk_about_dialog_get_program_name:
904 * @about: a #GtkAboutDialog
906 * Returns the program name displayed in the about dialog.
908 * Return value: The program name. The string is owned by the about
909 * dialog and must not be modified.
913 G_CONST_RETURN gchar *
914 gtk_about_dialog_get_program_name (GtkAboutDialog *about)
916 GtkAboutDialogPrivate *priv;
918 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
926 update_name_version (GtkAboutDialog *about)
928 GtkAboutDialogPrivate *priv;
929 gchar *title_string, *name_string;
933 title_string = g_strdup_printf (_("About %s"), priv->name);
934 gtk_window_set_title (GTK_WINDOW (about), title_string);
935 g_free (title_string);
937 if (priv->version != NULL)
938 name_string = g_markup_printf_escaped ("<span size=\"xx-large\" weight=\"bold\">%s %s</span>",
939 priv->name, priv->version);
941 name_string = g_markup_printf_escaped ("<span size=\"xx-large\" weight=\"bold\">%s</span>",
944 gtk_label_set_markup (GTK_LABEL (priv->name_label), name_string);
946 g_free (name_string);
950 * gtk_about_dialog_set_program_name:
951 * @about: a #GtkAboutDialog
952 * @name: the program name
954 * Sets the name to display in the about dialog.
955 * If this is not set, it defaults to g_get_application_name().
960 gtk_about_dialog_set_program_name (GtkAboutDialog *about,
963 GtkAboutDialogPrivate *priv;
966 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
971 priv->name = g_strdup (name ? name : g_get_application_name ());
974 update_name_version (about);
976 g_object_notify (G_OBJECT (about), "program-name");
981 * gtk_about_dialog_get_version:
982 * @about: a #GtkAboutDialog
984 * Returns the version string.
986 * Return value: The version string. The string is owned by the about
987 * dialog and must not be modified.
991 G_CONST_RETURN gchar *
992 gtk_about_dialog_get_version (GtkAboutDialog *about)
994 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
996 return about->priv->version;
1000 * gtk_about_dialog_set_version:
1001 * @about: a #GtkAboutDialog
1002 * @version: (allow-none): the version string
1004 * Sets the version string to display in the about dialog.
1009 gtk_about_dialog_set_version (GtkAboutDialog *about,
1010 const gchar *version)
1012 GtkAboutDialogPrivate *priv;
1015 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1019 tmp = priv->version;
1020 priv->version = g_strdup (version);
1023 update_name_version (about);
1025 g_object_notify (G_OBJECT (about), "version");
1029 * gtk_about_dialog_get_copyright:
1030 * @about: a #GtkAboutDialog
1032 * Returns the copyright string.
1034 * Return value: The copyright string. The string is owned by the about
1035 * dialog and must not be modified.
1039 G_CONST_RETURN gchar *
1040 gtk_about_dialog_get_copyright (GtkAboutDialog *about)
1042 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1044 return about->priv->copyright;
1048 * gtk_about_dialog_set_copyright:
1049 * @about: a #GtkAboutDialog
1050 * @copyright: (allow-none) the copyright string
1052 * Sets the copyright string to display in the about dialog.
1053 * This should be a short string of one or two lines.
1058 gtk_about_dialog_set_copyright (GtkAboutDialog *about,
1059 const gchar *copyright)
1061 GtkAboutDialogPrivate *priv;
1062 gchar *copyright_string, *tmp;
1064 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1068 tmp = priv->copyright;
1069 priv->copyright = g_strdup (copyright);
1072 if (priv->copyright != NULL)
1074 copyright_string = g_markup_printf_escaped ("<span size=\"small\">%s</span>",
1076 gtk_label_set_markup (GTK_LABEL (priv->copyright_label), copyright_string);
1077 g_free (copyright_string);
1079 gtk_widget_show (priv->copyright_label);
1082 gtk_widget_hide (priv->copyright_label);
1084 g_object_notify (G_OBJECT (about), "copyright");
1088 * gtk_about_dialog_get_comments:
1089 * @about: a #GtkAboutDialog
1091 * Returns the comments string.
1093 * Return value: The comments. The string is owned by the about
1094 * dialog and must not be modified.
1098 G_CONST_RETURN gchar *
1099 gtk_about_dialog_get_comments (GtkAboutDialog *about)
1101 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1103 return about->priv->comments;
1107 * gtk_about_dialog_set_comments:
1108 * @about: a #GtkAboutDialog
1109 * @comments: (allow-none): a comments string
1111 * Sets the comments string to display in the about dialog.
1112 * This should be a short string of one or two lines.
1117 gtk_about_dialog_set_comments (GtkAboutDialog *about,
1118 const gchar *comments)
1120 GtkAboutDialogPrivate *priv;
1123 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1127 tmp = priv->comments;
1130 priv->comments = g_strdup (comments);
1131 gtk_label_set_text (GTK_LABEL (priv->comments_label), priv->comments);
1132 gtk_widget_show (priv->comments_label);
1136 priv->comments = NULL;
1137 gtk_widget_hide (priv->comments_label);
1141 g_object_notify (G_OBJECT (about), "comments");
1145 * gtk_about_dialog_get_license:
1146 * @about: a #GtkAboutDialog
1148 * Returns the license information.
1150 * Return value: The license information. The string is owned by the about
1151 * dialog and must not be modified.
1155 G_CONST_RETURN gchar *
1156 gtk_about_dialog_get_license (GtkAboutDialog *about)
1158 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1160 return about->priv->license;
1164 * gtk_about_dialog_set_license:
1165 * @about: a #GtkAboutDialog
1166 * @license: (allow-none): the license information or %NULL
1168 * Sets the license information to be displayed in the secondary
1169 * license dialog. If @license is %NULL, the license button is
1175 gtk_about_dialog_set_license (GtkAboutDialog *about,
1176 const gchar *license)
1178 GtkAboutDialogPrivate *priv;
1181 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1185 tmp = priv->license;
1188 priv->license = g_strdup (license);
1189 priv->license_type = GTK_LICENSE_CUSTOM;
1190 gtk_widget_show (priv->license_button);
1194 priv->license = NULL;
1195 priv->license_type = GTK_LICENSE_UNKNOWN;
1196 gtk_widget_hide (priv->license_button);
1200 g_object_notify (G_OBJECT (about), "license");
1201 g_object_notify (G_OBJECT (about), "license-type");
1205 * gtk_about_dialog_get_wrap_license:
1206 * @about: a #GtkAboutDialog
1208 * Returns whether the license text in @about is
1209 * automatically wrapped.
1211 * Returns: %TRUE if the license text is wrapped
1216 gtk_about_dialog_get_wrap_license (GtkAboutDialog *about)
1218 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), FALSE);
1220 return about->priv->wrap_license;
1224 * gtk_about_dialog_set_wrap_license:
1225 * @about: a #GtkAboutDialog
1226 * @wrap_license: whether to wrap the license
1228 * Sets whether the license text in @about is
1229 * automatically wrapped.
1234 gtk_about_dialog_set_wrap_license (GtkAboutDialog *about,
1235 gboolean wrap_license)
1237 GtkAboutDialogPrivate *priv;
1239 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1243 wrap_license = wrap_license != FALSE;
1245 if (priv->wrap_license != wrap_license)
1247 priv->wrap_license = wrap_license;
1249 g_object_notify (G_OBJECT (about), "wrap-license");
1254 * gtk_about_dialog_get_website:
1255 * @about: a #GtkAboutDialog
1257 * Returns the website URL.
1259 * Return value: The website URL. The string is owned by the about
1260 * dialog and must not be modified.
1264 G_CONST_RETURN gchar *
1265 gtk_about_dialog_get_website (GtkAboutDialog *about)
1267 GtkAboutDialogPrivate *priv;
1269 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1273 return priv->website_url;
1277 * gtk_about_dialog_set_website:
1278 * @about: a #GtkAboutDialog
1279 * @website: (allow-none): a URL string starting with "http://"
1281 * Sets the URL to use for the website link.
1286 gtk_about_dialog_set_website (GtkAboutDialog *about,
1287 const gchar *website)
1289 GtkAboutDialogPrivate *priv;
1292 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1296 tmp = priv->website_url;
1297 priv->website_url = g_strdup (website);
1300 update_website (about);
1302 g_object_notify (G_OBJECT (about), "website");
1306 * gtk_about_dialog_get_website_label:
1307 * @about: a #GtkAboutDialog
1309 * Returns the label used for the website link.
1311 * Return value: The label used for the website link. The string is
1312 * owned by the about dialog and must not be modified.
1316 G_CONST_RETURN gchar *
1317 gtk_about_dialog_get_website_label (GtkAboutDialog *about)
1319 GtkAboutDialogPrivate *priv;
1321 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1325 return priv->website_text;
1329 * gtk_about_dialog_set_website_label:
1330 * @about: a #GtkAboutDialog
1331 * @website_label: the label used for the website link
1333 * Sets the label to be used for the website link.
1334 * It defaults to the website URL.
1339 gtk_about_dialog_set_website_label (GtkAboutDialog *about,
1340 const gchar *website_label)
1342 GtkAboutDialogPrivate *priv;
1345 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1349 tmp = priv->website_text;
1350 priv->website_text = g_strdup (website_label);
1353 update_website (about);
1355 g_object_notify (G_OBJECT (about), "website-label");
1359 * gtk_about_dialog_get_authors:
1360 * @about: a #GtkAboutDialog
1362 * Returns the string which are displayed in the authors tab
1363 * of the secondary credits dialog.
1365 * Return value: A %NULL-terminated string array containing
1366 * the authors. The array is owned by the about dialog
1367 * and must not be modified.
1371 G_CONST_RETURN gchar * G_CONST_RETURN *
1372 gtk_about_dialog_get_authors (GtkAboutDialog *about)
1374 GtkAboutDialogPrivate *priv;
1376 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1380 return (const gchar * const *) priv->authors;
1384 update_credits_button_visibility (GtkAboutDialog *about)
1386 GtkAboutDialogPrivate *priv = about->priv;
1389 show = priv->authors != NULL ||
1390 priv->documenters != NULL ||
1391 priv->artists != NULL ||
1392 (priv->translator_credits != NULL &&
1393 strcmp (priv->translator_credits, "translator_credits") &&
1394 strcmp (priv->translator_credits, "translator-credits"));
1396 gtk_widget_show (priv->credits_button);
1398 gtk_widget_hide (priv->credits_button);
1402 * gtk_about_dialog_set_authors:
1403 * @about: a #GtkAboutDialog
1404 * @authors: a %NULL-terminated array of strings
1406 * Sets the strings which are displayed in the authors tab
1407 * of the secondary credits dialog.
1412 gtk_about_dialog_set_authors (GtkAboutDialog *about,
1413 const gchar **authors)
1415 GtkAboutDialogPrivate *priv;
1418 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1422 tmp = priv->authors;
1423 priv->authors = g_strdupv ((gchar **)authors);
1426 update_credits_button_visibility (about);
1428 g_object_notify (G_OBJECT (about), "authors");
1432 * gtk_about_dialog_get_documenters:
1433 * @about: a #GtkAboutDialog
1435 * Returns the string which are displayed in the documenters
1436 * tab of the secondary credits dialog.
1438 * Return value: A %NULL-terminated string array containing
1439 * the documenters. The array is owned by the about dialog
1440 * and must not be modified.
1444 G_CONST_RETURN gchar * G_CONST_RETURN *
1445 gtk_about_dialog_get_documenters (GtkAboutDialog *about)
1447 GtkAboutDialogPrivate *priv;
1449 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1453 return (const gchar * const *)priv->documenters;
1457 * gtk_about_dialog_set_documenters:
1458 * @about: a #GtkAboutDialog
1459 * @documenters: a %NULL-terminated array of strings
1461 * Sets the strings which are displayed in the documenters tab
1462 * of the secondary credits dialog.
1467 gtk_about_dialog_set_documenters (GtkAboutDialog *about,
1468 const gchar **documenters)
1470 GtkAboutDialogPrivate *priv;
1473 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1477 tmp = priv->documenters;
1478 priv->documenters = g_strdupv ((gchar **)documenters);
1481 update_credits_button_visibility (about);
1483 g_object_notify (G_OBJECT (about), "documenters");
1487 * gtk_about_dialog_get_artists:
1488 * @about: a #GtkAboutDialog
1490 * Returns the string which are displayed in the artists tab
1491 * of the secondary credits dialog.
1493 * Return value: A %NULL-terminated string array containing
1494 * the artists. The array is owned by the about dialog
1495 * and must not be modified.
1499 G_CONST_RETURN gchar * G_CONST_RETURN *
1500 gtk_about_dialog_get_artists (GtkAboutDialog *about)
1502 GtkAboutDialogPrivate *priv;
1504 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1508 return (const gchar * const *)priv->artists;
1512 * gtk_about_dialog_set_artists:
1513 * @about: a #GtkAboutDialog
1514 * @artists: a %NULL-terminated array of strings
1516 * Sets the strings which are displayed in the artists tab
1517 * of the secondary credits dialog.
1522 gtk_about_dialog_set_artists (GtkAboutDialog *about,
1523 const gchar **artists)
1525 GtkAboutDialogPrivate *priv;
1528 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1532 tmp = priv->artists;
1533 priv->artists = g_strdupv ((gchar **)artists);
1536 update_credits_button_visibility (about);
1538 g_object_notify (G_OBJECT (about), "artists");
1542 * gtk_about_dialog_get_translator_credits:
1543 * @about: a #GtkAboutDialog
1545 * Returns the translator credits string which is displayed
1546 * in the translators tab of the secondary credits dialog.
1548 * Return value: The translator credits string. The string is
1549 * owned by the about dialog and must not be modified.
1553 G_CONST_RETURN gchar *
1554 gtk_about_dialog_get_translator_credits (GtkAboutDialog *about)
1556 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1558 return about->priv->translator_credits;
1562 * gtk_about_dialog_set_translator_credits:
1563 * @about: a #GtkAboutDialog
1564 * @translator_credits: (allow-none): the translator credits
1566 * Sets the translator credits string which is displayed in
1567 * the translators tab of the secondary credits dialog.
1569 * The intended use for this string is to display the translator
1570 * of the language which is currently used in the user interface.
1571 * Using gettext(), a simple way to achieve that is to mark the
1572 * string for translation:
1574 * gtk_about_dialog_set_translator_credits (about, _("translator-credits"));
1576 * It is a good idea to use the customary msgid "translator-credits" for this
1577 * purpose, since translators will already know the purpose of that msgid, and
1578 * since #GtkAboutDialog will detect if "translator-credits" is untranslated
1584 gtk_about_dialog_set_translator_credits (GtkAboutDialog *about,
1585 const gchar *translator_credits)
1587 GtkAboutDialogPrivate *priv;
1590 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1594 tmp = priv->translator_credits;
1595 priv->translator_credits = g_strdup (translator_credits);
1598 update_credits_button_visibility (about);
1600 g_object_notify (G_OBJECT (about), "translator-credits");
1604 * gtk_about_dialog_get_logo:
1605 * @about: a #GtkAboutDialog
1607 * Returns the pixbuf displayed as logo in the about dialog.
1609 * Return value: the pixbuf displayed as logo. The pixbuf is
1610 * owned by the about dialog. If you want to keep a reference
1611 * to it, you have to call g_object_ref() on it.
1616 gtk_about_dialog_get_logo (GtkAboutDialog *about)
1618 GtkAboutDialogPrivate *priv;
1620 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1624 if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
1625 return gtk_image_get_pixbuf (GTK_IMAGE (priv->logo_image));
1631 icon_set_new_from_pixbufs (GList *pixbufs)
1633 GtkIconSet *icon_set = gtk_icon_set_new ();
1635 for (; pixbufs; pixbufs = pixbufs->next)
1637 GdkPixbuf *pixbuf = GDK_PIXBUF (pixbufs->data);
1639 GtkIconSource *icon_source = gtk_icon_source_new ();
1640 gtk_icon_source_set_pixbuf (icon_source, pixbuf);
1641 gtk_icon_set_add_source (icon_set, icon_source);
1642 gtk_icon_source_free (icon_source);
1649 * gtk_about_dialog_set_logo:
1650 * @about: a #GtkAboutDialog
1651 * @logo: (allow-none): a #GdkPixbuf, or %NULL
1653 * Sets the pixbuf to be displayed as logo in the about dialog.
1654 * If it is %NULL, the default window icon set with
1655 * gtk_window_set_default_icon() will be used.
1660 gtk_about_dialog_set_logo (GtkAboutDialog *about,
1663 GtkAboutDialogPrivate *priv;
1665 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1669 g_object_freeze_notify (G_OBJECT (about));
1671 if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_ICON_NAME)
1672 g_object_notify (G_OBJECT (about), "logo-icon-name");
1675 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->logo_image), logo);
1678 GList *pixbufs = gtk_window_get_default_icon_list ();
1680 if (pixbufs != NULL)
1682 GtkIconSet *icon_set = icon_set_new_from_pixbufs (pixbufs);
1684 gtk_image_set_from_icon_set (GTK_IMAGE (priv->logo_image),
1685 icon_set, GTK_ICON_SIZE_DIALOG);
1687 gtk_icon_set_unref (icon_set);
1688 g_list_free (pixbufs);
1692 g_object_notify (G_OBJECT (about), "logo");
1694 g_object_thaw_notify (G_OBJECT (about));
1698 * gtk_about_dialog_get_logo_icon_name:
1699 * @about: a #GtkAboutDialog
1701 * Returns the icon name displayed as logo in the about dialog.
1703 * Return value: the icon name displayed as logo. The string is
1704 * owned by the dialog. If you want to keep a reference
1705 * to it, you have to call g_strdup() on it.
1709 G_CONST_RETURN gchar *
1710 gtk_about_dialog_get_logo_icon_name (GtkAboutDialog *about)
1712 GtkAboutDialogPrivate *priv;
1713 const gchar *icon_name = NULL;
1715 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);
1719 if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_ICON_NAME)
1720 gtk_image_get_icon_name (GTK_IMAGE (priv->logo_image), &icon_name, NULL);
1726 * gtk_about_dialog_set_logo_icon_name:
1727 * @about: a #GtkAboutDialog
1728 * @icon_name: (allow-none): an icon name, or %NULL
1730 * Sets the pixbuf to be displayed as logo in the about dialog.
1731 * If it is %NULL, the default window icon set with
1732 * gtk_window_set_default_icon() will be used.
1737 gtk_about_dialog_set_logo_icon_name (GtkAboutDialog *about,
1738 const gchar *icon_name)
1740 GtkAboutDialogPrivate *priv;
1742 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
1746 g_object_freeze_notify (G_OBJECT (about));
1748 if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
1749 g_object_notify (G_OBJECT (about), "logo");
1751 gtk_image_set_from_icon_name (GTK_IMAGE (priv->logo_image), icon_name,
1752 GTK_ICON_SIZE_DIALOG);
1753 g_object_notify (G_OBJECT (about), "logo-icon-name");
1755 g_object_thaw_notify (G_OBJECT (about));
1759 follow_if_link (GtkAboutDialog *about,
1760 GtkTextView *text_view,
1763 GSList *tags = NULL, *tagp = NULL;
1764 GtkAboutDialogPrivate *priv = about->priv;
1767 tags = gtk_text_iter_get_tags (iter);
1768 for (tagp = tags; tagp != NULL && !uri; tagp = tagp->next)
1770 GtkTextTag *tag = tagp->data;
1772 uri = g_object_get_data (G_OBJECT (tag), "uri");
1774 emit_activate_link (about, uri);
1776 if (uri && !g_slist_find_custom (priv->visited_links, uri, (GCompareFunc)strcmp))
1778 GdkColor *style_visited_link_color;
1781 gtk_widget_ensure_style (GTK_WIDGET (about));
1782 gtk_widget_style_get (GTK_WIDGET (about),
1783 "visited-link-color", &style_visited_link_color,
1785 if (style_visited_link_color)
1787 color = *style_visited_link_color;
1788 gdk_color_free (style_visited_link_color);
1791 color = default_visited_link_color;
1793 g_object_set (G_OBJECT (tag), "foreground-gdk", &color, NULL);
1795 priv->visited_links = g_slist_prepend (priv->visited_links, g_strdup (uri));
1800 g_slist_free (tags);
1804 text_view_key_press_event (GtkWidget *text_view,
1806 GtkAboutDialog *about)
1809 GtkTextBuffer *buffer;
1811 switch (event->keyval)
1813 case GDK_KEY_Return:
1814 case GDK_KEY_ISO_Enter:
1815 case GDK_KEY_KP_Enter:
1816 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
1817 gtk_text_buffer_get_iter_at_mark (buffer, &iter,
1818 gtk_text_buffer_get_insert (buffer));
1819 follow_if_link (about, GTK_TEXT_VIEW (text_view), &iter);
1830 text_view_event_after (GtkWidget *text_view,
1832 GtkAboutDialog *about)
1834 GtkTextIter start, end, iter;
1835 GtkTextBuffer *buffer;
1836 GdkEventButton *button_event;
1839 if (event->type != GDK_BUTTON_RELEASE)
1842 button_event = (GdkEventButton *)event;
1844 if (button_event->button != 1)
1847 buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
1849 /* we shouldn't follow a link if the user has selected something */
1850 gtk_text_buffer_get_selection_bounds (buffer, &start, &end);
1851 if (gtk_text_iter_get_offset (&start) != gtk_text_iter_get_offset (&end))
1854 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
1855 GTK_TEXT_WINDOW_WIDGET,
1856 button_event->x, button_event->y, &x, &y);
1858 gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, x, y);
1860 follow_if_link (about, GTK_TEXT_VIEW (text_view), &iter);
1866 set_cursor_if_appropriate (GtkAboutDialog *about,
1867 GtkTextView *text_view,
1872 GtkAboutDialogPrivate *priv = about->priv;
1873 GSList *tags = NULL, *tagp = NULL;
1875 gboolean hovering_over_link = FALSE;
1877 gtk_text_view_get_iter_at_location (text_view, &iter, x, y);
1879 tags = gtk_text_iter_get_tags (&iter);
1880 for (tagp = tags; tagp != NULL; tagp = tagp->next)
1882 GtkTextTag *tag = tagp->data;
1883 gchar *uri = g_object_get_data (G_OBJECT (tag), "uri");
1887 hovering_over_link = TRUE;
1892 if (hovering_over_link != priv->hovering_over_link)
1894 priv->hovering_over_link = hovering_over_link;
1896 if (hovering_over_link)
1897 gdk_window_set_device_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), device, priv->hand_cursor);
1899 gdk_window_set_device_cursor (gtk_text_view_get_window (text_view, GTK_TEXT_WINDOW_TEXT), device, priv->regular_cursor);
1903 g_slist_free (tags);
1907 text_view_motion_notify_event (GtkWidget *text_view,
1908 GdkEventMotion *event,
1909 GtkAboutDialog *about)
1913 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
1914 GTK_TEXT_WINDOW_WIDGET,
1915 event->x, event->y, &x, &y);
1917 set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), event->device, x, y);
1919 gdk_event_request_motions (event);
1926 text_view_visibility_notify_event (GtkWidget *text_view,
1927 GdkEventVisibility *event,
1928 GtkAboutDialog *about)
1930 GdkDeviceManager *device_manager;
1931 GdkDisplay *display;
1933 gint wx, wy, bx, by;
1935 display = gdk_window_get_display (event->window);
1936 device_manager = gdk_display_get_device_manager (display);
1937 devices = gdk_device_manager_list_devices (device_manager, GDK_DEVICE_TYPE_MASTER);
1939 for (d = devices; d; d = d->next)
1941 GdkDevice *dev = d->data;
1943 gdk_window_get_device_position (gtk_widget_get_window (text_view), dev,
1946 gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view),
1947 GTK_TEXT_WINDOW_WIDGET,
1950 set_cursor_if_appropriate (about, GTK_TEXT_VIEW (text_view), dev, bx, by);
1957 text_view_new (GtkAboutDialog *about,
1960 GtkWrapMode wrap_mode)
1963 gchar *q0, *q1, *q2, *r1, *r2;
1965 GtkTextView *text_view;
1966 GtkTextBuffer *buffer;
1967 GdkColor *style_link_color;
1968 GdkColor *style_visited_link_color;
1970 GdkColor link_color;
1971 GdkColor visited_link_color;
1973 GtkAboutDialogPrivate *priv = about->priv;
1975 gtk_widget_ensure_style (GTK_WIDGET (about));
1976 gtk_widget_style_get (GTK_WIDGET (about),
1977 "link-color", &style_link_color,
1978 "visited-link-color", &style_visited_link_color,
1980 if (style_link_color)
1982 link_color = *style_link_color;
1983 gdk_color_free (style_link_color);
1986 link_color = default_link_color;
1988 if (style_visited_link_color)
1990 visited_link_color = *style_visited_link_color;
1991 gdk_color_free (style_visited_link_color);
1994 visited_link_color = default_visited_link_color;
1996 view = gtk_text_view_new ();
1997 text_view = GTK_TEXT_VIEW (view);
1998 buffer = gtk_text_view_get_buffer (text_view);
1999 gtk_text_view_set_cursor_visible (text_view, FALSE);
2000 gtk_text_view_set_editable (text_view, FALSE);
2001 gtk_text_view_set_wrap_mode (text_view, wrap_mode);
2003 gtk_text_view_set_left_margin (text_view, 8);
2004 gtk_text_view_set_right_margin (text_view, 8);
2006 g_signal_connect (view, "key-press-event",
2007 G_CALLBACK (text_view_key_press_event), about);
2008 g_signal_connect (view, "event-after",
2009 G_CALLBACK (text_view_event_after), about);
2010 g_signal_connect (view, "motion-notify-event",
2011 G_CALLBACK (text_view_motion_notify_event), about);
2012 g_signal_connect (view, "visibility-notify-event",
2013 G_CALLBACK (text_view_visibility_notify_event), about);
2015 if (strings == NULL)
2017 gtk_widget_hide (view);
2021 for (p = strings; *p; p++)
2026 q1 = strchr (q0, '<');
2027 q2 = q1 ? strchr (q1, '>') : NULL;
2028 r1 = strstr (q0, "http://");
2031 r2 = strpbrk (r1, " \n\t");
2033 r2 = strchr (r1, '\0');
2038 if (r1 && r2 && (!q1 || !q2 || (r1 < q1)))
2049 const gchar *link_type;
2054 gtk_text_buffer_insert_at_cursor (buffer, q0, (q1 - q0) + 1);
2055 gtk_text_buffer_get_end_iter (buffer, &end);
2057 link_type = "email";
2061 gtk_text_buffer_insert_at_cursor (buffer, q0, q1 - q0);
2062 gtk_text_buffer_get_end_iter (buffer, &end);
2068 link = g_strndup (q1, q2 - q1);
2070 if (g_slist_find_custom (priv->visited_links, link, (GCompareFunc)strcmp))
2071 color = visited_link_color;
2075 tag = gtk_text_buffer_create_tag (buffer, NULL,
2076 "foreground-gdk", &color,
2077 "underline", PANGO_UNDERLINE_SINGLE,
2079 if (strcmp (link_type, "email") == 0)
2083 escaped = g_uri_escape_string (link, NULL, FALSE);
2084 uri = g_strconcat ("mailto:", escaped, NULL);
2089 uri = g_strdup (link);
2091 g_object_set_data_full (G_OBJECT (tag), I_("uri"), uri, g_free);
2092 gtk_text_buffer_insert_with_tags (buffer, &end, link, -1, tag, NULL);
2098 gtk_text_buffer_insert_at_cursor (buffer, q0, -1);
2104 gtk_text_buffer_insert_at_cursor (buffer, "\n", 1);
2107 gtk_widget_show (view);
2112 add_credits_page (GtkAboutDialog *about,
2113 GtkWidget *credits_dialog,
2114 GtkWidget *notebook,
2118 GtkWidget *sw, *view;
2120 view = text_view_new (about, credits_dialog, people, GTK_WRAP_NONE);
2122 sw = gtk_scrolled_window_new (NULL, NULL);
2123 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
2125 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2126 GTK_POLICY_AUTOMATIC,
2127 GTK_POLICY_AUTOMATIC);
2128 gtk_container_add (GTK_CONTAINER (sw), view);
2130 gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
2131 sw, gtk_label_new (title));
2135 display_credits_dialog (GtkWidget *button,
2138 GtkAboutDialog *about = (GtkAboutDialog *)data;
2139 GtkAboutDialogPrivate *priv = about->priv;
2140 GtkWidget *dialog, *notebook;
2141 GtkDialog *credits_dialog;
2142 GtkWidget *content_area;
2143 GtkWidget *action_area;
2145 if (priv->credits_dialog != NULL)
2147 gtk_window_present (GTK_WINDOW (priv->credits_dialog));
2151 dialog = gtk_dialog_new_with_buttons (_("Credits"),
2153 GTK_DIALOG_DESTROY_WITH_PARENT,
2154 GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
2156 credits_dialog = GTK_DIALOG (dialog);
2158 content_area = gtk_dialog_get_content_area (credits_dialog);
2159 action_area = gtk_dialog_get_action_area (credits_dialog);
2161 gtk_container_set_border_width (GTK_CONTAINER (credits_dialog), 5);
2162 gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
2163 gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
2165 priv->credits_dialog = dialog;
2166 gtk_window_set_default_size (GTK_WINDOW (dialog), 360, 260);
2167 gtk_dialog_set_default_response (credits_dialog, GTK_RESPONSE_CANCEL);
2169 gtk_window_set_modal (GTK_WINDOW (dialog),
2170 gtk_window_get_modal (GTK_WINDOW (about)));
2172 g_signal_connect (dialog, "response",
2173 G_CALLBACK (gtk_widget_destroy), dialog);
2174 g_signal_connect (dialog, "destroy",
2175 G_CALLBACK (gtk_widget_destroyed),
2176 &(priv->credits_dialog));
2178 notebook = gtk_notebook_new ();
2179 gtk_container_set_border_width (GTK_CONTAINER (notebook), 5);
2180 gtk_box_pack_start (GTK_BOX (content_area), notebook, TRUE, TRUE, 0);
2182 if (priv->authors != NULL)
2183 add_credits_page (about, dialog, notebook, _("Written by"), priv->authors);
2185 if (priv->documenters != NULL)
2186 add_credits_page (about, dialog, notebook, _("Documented by"), priv->documenters);
2188 /* Don't show an untranslated gettext msgid */
2189 if (priv->translator_credits != NULL &&
2190 strcmp (priv->translator_credits, "translator_credits") != 0 &&
2191 strcmp (priv->translator_credits, "translator-credits") != 0)
2193 gchar *translators[2];
2195 translators[0] = priv->translator_credits;
2196 translators[1] = NULL;
2198 add_credits_page (about, dialog, notebook, _("Translated by"), translators);
2201 if (priv->artists != NULL)
2202 add_credits_page (about, dialog, notebook, _("Artwork by"), priv->artists);
2204 gtk_widget_show_all (dialog);
2208 set_policy (GtkWidget *sw)
2210 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2211 GTK_POLICY_AUTOMATIC,
2212 GTK_POLICY_AUTOMATIC);
2216 display_license_dialog (GtkWidget *button,
2219 GtkAboutDialog *about = (GtkAboutDialog *)data;
2220 GtkAboutDialogPrivate *priv = about->priv;
2221 GtkWidget *dialog, *view, *sw;
2222 GtkDialog *license_dialog;
2223 GtkWidget *content_area;
2224 GtkWidget *action_area;
2227 if (priv->license_dialog != NULL)
2229 gtk_window_present (GTK_WINDOW (priv->license_dialog));
2233 dialog = gtk_dialog_new_with_buttons (_("License"),
2235 GTK_DIALOG_DESTROY_WITH_PARENT,
2236 GTK_STOCK_CLOSE, GTK_RESPONSE_CANCEL,
2238 license_dialog = GTK_DIALOG (dialog);
2240 content_area = gtk_dialog_get_content_area (license_dialog);
2241 action_area = gtk_dialog_get_action_area (license_dialog);
2243 gtk_container_set_border_width (GTK_CONTAINER (license_dialog), 5);
2244 gtk_box_set_spacing (GTK_BOX (content_area), 2); /* 2 * 5 + 2 = 12 */
2245 gtk_container_set_border_width (GTK_CONTAINER (action_area), 5);
2247 priv->license_dialog = dialog;
2248 gtk_window_set_default_size (GTK_WINDOW (dialog), 420, 320);
2249 gtk_dialog_set_default_response (license_dialog, GTK_RESPONSE_CANCEL);
2251 gtk_window_set_modal (GTK_WINDOW (dialog),
2252 gtk_window_get_modal (GTK_WINDOW (about)));
2254 g_signal_connect (dialog, "response",
2255 G_CALLBACK (gtk_widget_destroy), dialog);
2256 g_signal_connect (dialog, "destroy",
2257 G_CALLBACK (gtk_widget_destroyed),
2258 &(priv->license_dialog));
2260 sw = gtk_scrolled_window_new (NULL, NULL);
2261 gtk_container_set_border_width (GTK_CONTAINER (sw), 5);
2262 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw),
2264 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
2266 GTK_POLICY_AUTOMATIC);
2267 g_signal_connect (sw, "map", G_CALLBACK (set_policy), NULL);
2268 gtk_box_pack_start (GTK_BOX (content_area), sw, TRUE, TRUE, 0);
2270 strings[0] = priv->license;
2272 view = text_view_new (about, dialog, strings,
2273 priv->wrap_license ? GTK_WRAP_WORD : GTK_WRAP_NONE);
2275 gtk_container_add (GTK_CONTAINER (sw), view);
2277 gtk_widget_show_all (dialog);
2281 * gtk_about_dialog_new:
2283 * Creates a new #GtkAboutDialog.
2285 * Returns: a newly created #GtkAboutDialog
2290 gtk_about_dialog_new (void)
2292 GtkAboutDialog *dialog = g_object_new (GTK_TYPE_ABOUT_DIALOG, NULL);
2294 return GTK_WIDGET (dialog);
2298 close_cb (GtkAboutDialog *about)
2300 GtkAboutDialogPrivate *priv = about->priv;
2302 if (priv->license_dialog != NULL)
2304 gtk_widget_destroy (priv->license_dialog);
2305 priv->license_dialog = NULL;
2308 if (priv->credits_dialog != NULL)
2310 gtk_widget_destroy (priv->credits_dialog);
2311 priv->credits_dialog = NULL;
2314 gtk_widget_hide (GTK_WIDGET (about));
2319 * gtk_show_about_dialog:
2320 * @parent: (allow-none): transient parent, or %NULL for none
2321 * @first_property_name: the name of the first property
2322 * @Varargs: value of first property, followed by more properties, %NULL-terminated
2324 * This is a convenience function for showing an application's about box.
2325 * The constructed dialog is associated with the parent window and
2326 * reused for future invocations of this function.
2331 gtk_show_about_dialog (GtkWindow *parent,
2332 const gchar *first_property_name,
2335 static GtkWidget *global_about_dialog = NULL;
2336 GtkWidget *dialog = NULL;
2340 dialog = g_object_get_data (G_OBJECT (parent), "gtk-about-dialog");
2342 dialog = global_about_dialog;
2346 dialog = gtk_about_dialog_new ();
2348 g_object_ref_sink (dialog);
2350 g_signal_connect (dialog, "delete-event",
2351 G_CALLBACK (gtk_widget_hide_on_delete), NULL);
2353 /* Close dialog on user response */
2354 g_signal_connect (dialog, "response",
2355 G_CALLBACK (close_cb), NULL);
2357 va_start (var_args, first_property_name);
2358 g_object_set_valist (G_OBJECT (dialog), first_property_name, var_args);
2363 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
2364 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
2365 g_object_set_data_full (G_OBJECT (parent),
2366 I_("gtk-about-dialog"),
2367 dialog, g_object_unref);
2370 global_about_dialog = dialog;
2374 gtk_window_present (GTK_WINDOW (dialog));
2378 * gtk_about_dialog_set_license_type:
2379 * @about: a #GtkAboutDialog
2380 * @license_type: the type of license
2382 * Sets the license of the application showing the @about dialog from a
2383 * list of known licenses.
2385 * This function overrides the license set using
2386 * gtk_about_dialog_set_license().
2391 gtk_about_dialog_set_license_type (GtkAboutDialog *about,
2392 GtkLicense license_type)
2394 GtkAboutDialogPrivate *priv;
2396 g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
2397 g_return_if_fail (license_type >= GTK_LICENSE_UNKNOWN &&
2398 license_type <= GTK_LICENSE_ARTISTIC);
2402 if (priv->license_type != license_type)
2404 g_object_freeze_notify (G_OBJECT (about));
2406 priv->license_type = license_type;
2408 /* custom licenses use the contents of the :license property */
2409 if (priv->license_type != GTK_LICENSE_CUSTOM)
2414 url = gtk_license_urls[priv->license_type];
2416 url = priv->website_url;
2418 /* compose the new license string as:
2421 * <copyright line 1>\n
2423 * <copyright line n>\n
2425 * license preamble + URL
2428 str = g_string_sized_new (256);
2429 g_string_append (str, priv->name);
2430 g_string_append (str, "\n");
2431 g_string_append (str, priv->copyright);
2432 g_string_append (str, "\n\n");
2433 g_string_append_printf (str, _(gtk_license_preamble), url);
2435 g_free (priv->license);
2436 priv->license = g_string_free (str, FALSE);
2437 priv->wrap_license = TRUE;
2438 gtk_widget_show (priv->license_button);
2440 g_object_notify (G_OBJECT (about), "wrap-license");
2441 g_object_notify (G_OBJECT (about), "license");
2444 g_object_notify (G_OBJECT (about), "license-type");
2446 g_object_thaw_notify (G_OBJECT (about));
2451 * gtk_about_dialog_get_license_type:
2452 * @about: a #GtkAboutDialog
2454 * Retrieves the license set using gtk_about_dialog_set_license_type()
2456 * Return value: a #GtkLicense value
2461 gtk_about_dialog_get_license_type (GtkAboutDialog *about)
2463 g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), GTK_LICENSE_UNKNOWN);
2465 return about->priv->license_type;