gtkaboutdialog.c 75.6 KB
Newer Older
Cody Russell's avatar
Cody Russell committed
1
/* GTK - The GIMP Toolkit
2 3 4 5 6
 * Copyright (C) 2001 CodeFactory AB
 * Copyright (C) 2001, 2002 Anders Carlsson
 * Copyright (C) 2003, 2004 Matthias Clasen <mclasen@redhat.com>
 *
 * This library is free software; you can redistribute it and/or
Matthias Clasen's avatar
Matthias Clasen committed
7 8
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
9 10 11 12 13 14 15 16
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
Javier Jardón's avatar
Javier Jardón committed
17
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 19 20
 */

/*
21
 * Author: Anders Carlsson <andersca@gnome.org>
22 23 24 25
 *
 * Modified by the GTK+ Team and others 1997-2004.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
Matthias Clasen's avatar
Matthias Clasen committed
26
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
27 28
 */

29
#include "config.h"
30

31 32
#include <string.h>

33
#include "gtkaboutdialog.h"
34 35 36
#include "gtkbutton.h"
#include "gtkbbox.h"
#include "gtkdialog.h"
37
#include "gtkgrid.h"
Matthias Clasen's avatar
Matthias Clasen committed
38
#include "gtkbox.h"
39
#include "gtkicontheme.h"
40 41
#include "gtkimage.h"
#include "gtklabel.h"
42
#include "gtklinkbutton.h"
43
#include "gtkmarshalers.h"
44
#include "gtkstack.h"
45
#include "gtkorientable.h"
46 47
#include "gtkscrolledwindow.h"
#include "gtktextview.h"
48
#include "gtkshow.h"
49
#include "gtkmain.h"
50
#include "gtkmessagedialog.h"
51
#include "gtktogglebutton.h"
52
#include "gtktypebuiltins.h"
53 54 55 56
#include "gtkstack.h"
#include "gtkstackswitcher.h"
#include "gtksettings.h"
#include "gtkheaderbar.h"
57
#include "gtkprivate.h"
58
#include "gtkintl.h"
59
#include "gtkdialogprivate.h"
60

61 62 63 64 65 66

/**
 * SECTION:gtkaboutdialog
 * @Short_description: Display information about an application
 * @Title: GtkAboutDialog
 *
67
 * The GtkAboutDialog offers a simple way to display information about
68 69 70
 * a program like its logo, name, copyright, website and license. It is
 * also possible to give credits to the authors, documenters, translators
 * and artists who have worked on the program. An about dialog is typically
71 72
 * opened when the user selects the `About` option from the `Help` menu.
 * All parts of the dialog are optional.
73
 *
Matthias Clasen's avatar
Matthias Clasen committed
74
 * About dialogs often contain links and email addresses. GtkAboutDialog
75
 * displays these as clickable links. By default, it calls gtk_show_uri_on_window()
76 77
 * when a user clicks one. The behaviour can be overridden with the
 * #GtkAboutDialog::activate-link signal.
78
 *
79
 * To specify a person with an email address, use a string like
80
 * "Edgar Allan Poe <edgar\@poe.com>". To specify a website with a title,
81 82
 * use a string like "GTK+ team http://www.gtk.org".
 *
83
 * To make constructing a GtkAboutDialog as convenient as possible, you can
84 85 86
 * use the function gtk_show_about_dialog() which constructs and shows a dialog
 * and keeps it around so that it can be shown again.
 *
87
 * Note that GTK+ sets a default title of `_("About %s")` on the dialog
88 89 90 91
 * window (where \%s is replaced by the name of the application, but in
 * order to ensure proper translation of the title, applications should
 * set the title property explicitly when constructing a GtkAboutDialog,
 * as shown in the following example:
92
 * |[<!-- language="C" -->
93
 * GdkPixbuf *example_logo = gdk_pixbuf_new_from_file ("./logo.png", NULL);
94 95 96
 * gtk_show_about_dialog (NULL,
 *                        "program-name", "ExampleCode",
 *                        "logo", example_logo,
97
 *                        "title", _("About ExampleCode"),
98
 *                        NULL);
99
 * ]|
100 101 102
 *
 * It is also possible to show a #GtkAboutDialog like any other #GtkDialog,
 * e.g. using gtk_dialog_run(). In this case, you might need to know that
103
 * the “Close” button returns the #GTK_RESPONSE_CANCEL response id.
104 105
 */

106 107 108 109 110 111 112 113 114 115
typedef struct
{
  const gchar *name;
  const gchar *url;
} LicenseInfo;

/* LicenseInfo for each GtkLicense type; keep in the same order as the enumeration */
static const LicenseInfo gtk_license_info [] = {
  { N_("License"), NULL },
  { N_("Custom License") , NULL },
116 117 118 119 120 121 122 123 124 125 126
  { N_("GNU General Public License, version 2 or later"), "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html" },
  { N_("GNU General Public License, version 3 or later"), "https://www.gnu.org/licenses/gpl-3.0.html" },
  { N_("GNU Lesser General Public License, version 2.1 or later"), "https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html" },
  { N_("GNU Lesser General Public License, version 3 or later"), "https://www.gnu.org/licenses/lgpl-3.0.html" },
  { N_("BSD 2-Clause License"), "https://opensource.org/licenses/bsd-license.php" },
  { N_("The MIT License (MIT)"), "https://opensource.org/licenses/mit-license.php" },
  { N_("Artistic License 2.0"), "https://opensource.org/licenses/artistic-license-2.0.php" },
  { N_("GNU General Public License, version 2 only"), "https://www.gnu.org/licenses/old-licenses/gpl-2.0.html" },
  { N_("GNU General Public License, version 3 only"), "https://www.gnu.org/licenses/gpl-3.0.html" },
  { N_("GNU Lesser General Public License, version 2.1 only"), "https://www.gnu.org/licenses/old-licenses/lgpl-2.1.html" },
  { N_("GNU Lesser General Public License, version 3 only"), "https://www.gnu.org/licenses/lgpl-3.0.html" },
127 128
  { N_("GNU Affero General Public License, version 3 or later"), "https://www.gnu.org/licenses/agpl-3.0.html" },
  { N_("GNU Affero General Public License, version 3 only"), "https://www.gnu.org/licenses/agpl-3.0.html" }
129 130
};

131 132 133 134 135 136
typedef struct
{
  gchar *heading;
  gchar **people;
} CreditSection;

137
struct _GtkAboutDialogPrivate
138 139 140 141 142
{
  gchar *name;
  gchar *version;
  gchar *copyright;
  gchar *comments;
143 144
  gchar *website_url;
  gchar *website_text;
145 146
  gchar *translator_credits;
  gchar *license;
Matthias Clasen's avatar
Matthias Clasen committed
147

148 149 150
  gchar **authors;
  gchar **documenters;
  gchar **artists;
Matthias Clasen's avatar
Matthias Clasen committed
151

152 153
  GSList *credit_sections;

154 155
  gboolean credits_page_initialized;
  gboolean license_page_initialized;
156

157
  GtkWidget *stack;
158
  GtkWidget *stack_switcher;
159 160 161
  GtkWidget *credits_button;
  GtkWidget *license_button;

162 163
  GtkWidget *logo_image;
  GtkWidget *name_label;
164
  GtkWidget *version_label;
165 166
  GtkWidget *comments_label;
  GtkWidget *copyright_label;
167
  GtkWidget *license_label;
168
  GtkWidget *website_label;
169

170 171
  GtkWidget *credits_page;
  GtkWidget *license_page;
Matthias Clasen's avatar
Matthias Clasen committed
172

173 174 175
  GtkWidget *credits_grid;
  GtkWidget *license_view;

176 177
  GdkCursor *hand_cursor;
  GdkCursor *regular_cursor;
Matthias Clasen's avatar
Matthias Clasen committed
178

179 180
  GSList *visited_links;

181 182
  GtkLicense license_type;

183 184
  guint hovering_over_link : 1;
  guint wrap_license : 1;
185
  guint in_child_changed : 1;
186
  guint in_switch_page : 1;
187 188
};

Matthias Clasen's avatar
Matthias Clasen committed
189
enum
190 191 192 193 194 195 196 197 198 199 200 201 202
{
  PROP_0,
  PROP_NAME,
  PROP_VERSION,
  PROP_COPYRIGHT,
  PROP_COMMENTS,
  PROP_WEBSITE,
  PROP_WEBSITE_LABEL,
  PROP_LICENSE,
  PROP_AUTHORS,
  PROP_DOCUMENTERS,
  PROP_TRANSLATOR_CREDITS,
  PROP_ARTISTS,
203
  PROP_LOGO,
204
  PROP_LOGO_ICON_NAME,
205
  PROP_WRAP_LICENSE,
206 207
  PROP_LICENSE_TYPE,
  LAST_PROP
208 209 210 211
};

static void                 gtk_about_dialog_finalize       (GObject            *object);
static void                 gtk_about_dialog_get_property   (GObject            *object,
Matthias Clasen's avatar
Matthias Clasen committed
212 213 214
                                                             guint               prop_id,
                                                             GValue             *value,
                                                             GParamSpec         *pspec);
215
static void                 gtk_about_dialog_set_property   (GObject            *object,
Matthias Clasen's avatar
Matthias Clasen committed
216 217 218
                                                             guint               prop_id,
                                                             const GValue       *value,
                                                             GParamSpec         *pspec);
219 220 221
static void                 gtk_about_dialog_realize        (GtkWidget          *widget);
static void                 gtk_about_dialog_unrealize      (GtkWidget          *widget);
static void                 gtk_about_dialog_show           (GtkWidget          *widget);
222 223
static void                 update_name_version             (GtkAboutDialog     *about);
static void                 follow_if_link                  (GtkAboutDialog     *about,
Matthias Clasen's avatar
Matthias Clasen committed
224 225
                                                             GtkTextView        *text_view,
                                                             GtkTextIter        *iter);
226
static void                 set_cursor_if_appropriate       (GtkAboutDialog     *about,
227
                                                             GtkTextView        *text_view,
228
                                                             GdkDevice          *device,
229 230
                                                             gint                x,
                                                             gint                y);
231 232
static void                 populate_credits_page           (GtkAboutDialog     *about);
static void                 populate_license_page           (GtkAboutDialog     *about);
233
static void                 close_cb                        (GtkAboutDialog     *about);
234 235
static gboolean             gtk_about_dialog_activate_link  (GtkAboutDialog     *about,
                                                             const gchar        *uri);
236 237 238 239 240 241 242 243 244 245 246
static gboolean             emit_activate_link              (GtkAboutDialog     *about,
							     const gchar        *uri);
static gboolean             text_view_key_press_event       (GtkWidget          *text_view,
							     GdkEventKey        *event,
							     GtkAboutDialog     *about);
static gboolean             text_view_event_after           (GtkWidget          *text_view,
							     GdkEvent           *event,
							     GtkAboutDialog     *about);
static gboolean             text_view_motion_notify_event   (GtkWidget          *text_view,
							     GdkEventMotion     *event,
							     GtkAboutDialog     *about);
247 248 249 250
static void                 toggle_credits                  (GtkToggleButton    *button,
                                                             gpointer            user_data);
static void                 toggle_license                  (GtkToggleButton    *button,
                                                             gpointer            user_data);
251

252 253 254 255
enum {
  ACTIVATE_LINK,
  LAST_SIGNAL
};
256

257
static guint signals[LAST_SIGNAL] = { 0 };
258
static GParamSpec *props[LAST_PROP] = { NULL, };
259

260
G_DEFINE_TYPE_WITH_PRIVATE (GtkAboutDialog, gtk_about_dialog, GTK_TYPE_DIALOG)
261

262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
static gboolean
stack_visible_child_notify (GtkStack       *stack,
                            GParamSpec     *pspec,
                            GtkAboutDialog *about)
{
  GtkAboutDialogPrivate *priv = about->priv;
  GtkWidget *child;

  child = gtk_stack_get_visible_child (stack);
  if (child == priv->credits_page)
    {
      if (!priv->credits_page_initialized)
        {
          populate_credits_page (about);
          priv->credits_page_initialized = TRUE;
        }
    }
  else if (child == priv->license_page)
    {
      if (!priv->license_page_initialized)
        {
          populate_license_page (about);
          priv->license_page_initialized = TRUE;
        }
    }

  return FALSE;
}
290

291 292 293 294 295
static void
gtk_about_dialog_class_init (GtkAboutDialogClass *klass)
{
  GObjectClass *object_class;
  GtkWidgetClass *widget_class;
Matthias Clasen's avatar
Matthias Clasen committed
296

297 298
  object_class = (GObjectClass *)klass;
  widget_class = (GtkWidgetClass *)klass;
Matthias Clasen's avatar
Matthias Clasen committed
299

300 301 302 303 304
  object_class->set_property = gtk_about_dialog_set_property;
  object_class->get_property = gtk_about_dialog_get_property;

  object_class->finalize = gtk_about_dialog_finalize;

305
  widget_class->show = gtk_about_dialog_show;
306 307
  widget_class->realize = gtk_about_dialog_realize;
  widget_class->unrealize = gtk_about_dialog_unrealize;
308

309 310 311 312 313 314 315 316 317
  klass->activate_link = gtk_about_dialog_activate_link;

  /**
   * GtkAboutDialog::activate-link:
   * @label: The object on which the signal was emitted
   * @uri: the URI that is activated
   *
   * The signal which gets emitted to activate a URI.
   * Applications may connect to it to override the default behaviour,
318
   * which is to call gtk_show_uri_on_window().
319 320 321
   *
   * Returns: %TRUE if the link has been activated
   *
322
   * Since: 2.24
323 324
   */
  signals[ACTIVATE_LINK] =
325
    g_signal_new (I_("activate-link"),
326 327 328 329 330 331 332
                  G_TYPE_FROM_CLASS (object_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (GtkAboutDialogClass, activate_link),
                  _gtk_boolean_handled_accumulator, NULL,
                  _gtk_marshal_BOOLEAN__STRING,
                  G_TYPE_BOOLEAN, 1, G_TYPE_STRING);

Matthias Clasen's avatar
Matthias Clasen committed
333
  /**
334
   * GtkAboutDialog:program-name:
Matthias Clasen's avatar
Matthias Clasen committed
335
   *
Matthias Clasen's avatar
Matthias Clasen committed
336
   * The name of the program.
Matthias Clasen's avatar
Matthias Clasen committed
337 338
   * If this is not set, it defaults to g_get_application_name().
   *
339
   * Since: 2.12
Matthias Clasen's avatar
Matthias Clasen committed
340
   */
341 342 343 344 345
  props[PROP_NAME] =
    g_param_spec_string ("program-name",
                         P_("Program name"),
                         P_("The name of the program. If this is not set, it defaults to g_get_application_name()"),
                         NULL,
346
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
347

Matthias Clasen's avatar
Matthias Clasen committed
348 349 350
  /**
   * GtkAboutDialog:version:
   *
Matthias Clasen's avatar
Matthias Clasen committed
351
   * The version of the program.
Matthias Clasen's avatar
Matthias Clasen committed
352 353
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
354
   */
355 356 357 358 359
  props[PROP_VERSION] =
    g_param_spec_string ("version",
                         P_("Program version"),
                         P_("The version of the program"),
                         NULL,
360
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
Matthias Clasen's avatar
Matthias Clasen committed
361 362 363 364

  /**
   * GtkAboutDialog:copyright:
   *
Matthias Clasen's avatar
Matthias Clasen committed
365
   * Copyright information for the program.
Matthias Clasen's avatar
Matthias Clasen committed
366 367
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
368
   */
369 370 371 372
  props[PROP_COPYRIGHT] =
    g_param_spec_string ("copyright",
                         P_("Copyright string"),
                         P_("Copyright information for the program"),
Matthias Clasen's avatar
Matthias Clasen committed
373
                        NULL,
374
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
Matthias Clasen's avatar
Matthias Clasen committed
375 376 377 378

  /**
   * GtkAboutDialog:comments:
   *
Matthias Clasen's avatar
Matthias Clasen committed
379
   * Comments about the program. This string is displayed in a label
Matthias Clasen's avatar
Matthias Clasen committed
380 381 382 383
   * in the main dialog, thus it should be a short explanation of
   * the main purpose of the program, not a detailed list of features.
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
384
   */
385 386 387 388 389
  props[PROP_COMMENTS] =
    g_param_spec_string ("comments",
                         P_("Comments string"),
                         P_("Comments about the program"),
                         NULL,
390
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
Matthias Clasen's avatar
Matthias Clasen committed
391 392 393 394

  /**
   * GtkAboutDialog:license:
   *
Matthias Clasen's avatar
Matthias Clasen committed
395
   * The license of the program. This string is displayed in a
Matthias Clasen's avatar
Matthias Clasen committed
396
   * text view in a secondary dialog, therefore it is fine to use
397 398 399
   * a long multi-paragraph text. Note that the text is only wrapped
   * in the text view if the "wrap-license" property is set to %TRUE;
   * otherwise the text itself must contain the intended linebreaks.
400 401 402
   * When setting this property to a non-%NULL value, the
   * #GtkAboutDialog:license-type property is set to %GTK_LICENSE_CUSTOM
   * as a side effect.
Matthias Clasen's avatar
Matthias Clasen committed
403 404
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
405
   */
406 407
  props[PROP_LICENSE] =
    g_param_spec_string ("license",
408 409
                         P_("License"),
                         P_("The license of the program"),
410
                         NULL,
411
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
412

413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
  /**
   * GtkAboutDialog:license-type:
   *
   * The license of the program, as a value of the %GtkLicense enumeration.
   *
   * The #GtkAboutDialog will automatically fill out a standard disclaimer
   * and link the user to the appropriate online resource for the license
   * text.
   *
   * If %GTK_LICENSE_UNKNOWN is used, the link used will be the same
   * specified in the #GtkAboutDialog:website property.
   *
   * If %GTK_LICENSE_CUSTOM is used, the current contents of the
   * #GtkAboutDialog:license property are used.
   *
   * For any other #GtkLicense value, the contents of the
   * #GtkAboutDialog:license property are also set by this property as
   * a side effect.
   *
   * Since: 3.0
   */
434 435 436 437 438 439
  props[PROP_LICENSE_TYPE] =
    g_param_spec_enum ("license-type",
                       P_("License Type"),
                       P_("The license type of the program"),
                       GTK_TYPE_LICENSE,
                       GTK_LICENSE_UNKNOWN,
440
                       GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
441

Matthias Clasen's avatar
Matthias Clasen committed
442 443 444
  /**
   * GtkAboutDialog:website:
   *
Matthias Clasen's avatar
Matthias Clasen committed
445
   * The URL for the link to the website of the program.
Matthias Clasen's avatar
Matthias Clasen committed
446 447 448
   * This should be a string starting with "http://.
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
449
   */
450 451 452 453 454
  props[PROP_WEBSITE] =
    g_param_spec_string ("website",
                         P_("Website URL"),
                         P_("The URL for the link to the website of the program"),
                         NULL,
455
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
456

Matthias Clasen's avatar
Matthias Clasen committed
457 458 459
  /**
   * GtkAboutDialog:website-label:
   *
460
   * The label for the link to the website of the program.
Matthias Clasen's avatar
Matthias Clasen committed
461 462
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
463
   */
464 465 466 467 468
  props[PROP_WEBSITE_LABEL] =
    g_param_spec_string ("website-label",
                         P_("Website label"),
                         P_("The label for the link to the website of the program"),
                         NULL,
469
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
470

Matthias Clasen's avatar
Matthias Clasen committed
471 472 473 474 475 476 477 478
  /**
   * GtkAboutDialog:authors:
   *
   * The authors of the program, as a %NULL-terminated array of strings.
   * Each string may contain email addresses and URLs, which will be displayed
   * as links, see the introduction for more details.
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
479
   */
480 481 482 483 484
  props[PROP_AUTHORS] =
    g_param_spec_boxed ("authors",
                        P_("Authors"),
                        P_("List of authors of the program"),
                        G_TYPE_STRV,
485
                        GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
Matthias Clasen's avatar
Matthias Clasen committed
486 487 488 489 490 491 492 493 494

  /**
   * GtkAboutDialog:documenters:
   *
   * The people documenting the program, as a %NULL-terminated array of strings.
   * Each string may contain email addresses and URLs, which will be displayed
   * as links, see the introduction for more details.
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
495
   */
496 497 498 499 500
  props[PROP_DOCUMENTERS] =
    g_param_spec_boxed ("documenters",
                        P_("Documenters"),
                        P_("List of people documenting the program"),
                        G_TYPE_STRV,
501
                        GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
502

Matthias Clasen's avatar
Matthias Clasen committed
503 504 505
  /**
   * GtkAboutDialog:artists:
   *
Matthias Clasen's avatar
Matthias Clasen committed
506 507 508
   * The people who contributed artwork to the program, as a %NULL-terminated
   * array of strings. Each string may contain email addresses and URLs, which
   * will be displayed as links, see the introduction for more details.
Matthias Clasen's avatar
Matthias Clasen committed
509 510
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
511
   */
512 513 514 515 516
  props[PROP_ARTISTS] =
    g_param_spec_boxed ("artists",
                        P_("Artists"),
                        P_("List of people who have contributed artwork to the program"),
                        G_TYPE_STRV,
517
                        GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
Matthias Clasen's avatar
Matthias Clasen committed
518 519 520 521 522 523 524 525 526

  /**
   * GtkAboutDialog:translator-credits:
   *
   * Credits to the translators. This string should be marked as translatable.
   * The string may contain email addresses and URLs, which will be displayed
   * as links, see the introduction for more details.
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
527
   */
528 529 530 531 532
  props[PROP_TRANSLATOR_CREDITS] =
    g_param_spec_string ("translator-credits",
                         P_("Translator credits"),
                         P_("Credits to the translators. This string should be marked as translatable"),
                         NULL,
533
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
534

Matthias Clasen's avatar
Matthias Clasen committed
535 536 537
  /**
   * GtkAboutDialog:logo:
   *
538 539
   * A logo for the about box. If it is %NULL, the default window icon
   * set with gtk_window_set_default_icon() will be used.
Matthias Clasen's avatar
Matthias Clasen committed
540 541
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
542
   */
543 544 545 546 547
  props[PROP_LOGO] =
    g_param_spec_object ("logo",
                         P_("Logo"),
                         P_("A logo for the about box. If this is not set, it defaults to gtk_window_get_default_icon_list()"),
                         GDK_TYPE_PIXBUF,
548
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
549

Matthias Clasen's avatar
Matthias Clasen committed
550 551 552 553
  /**
   * GtkAboutDialog:logo-icon-name:
   *
   * A named icon to use as the logo for the about box. This property
Matthias Clasen's avatar
Matthias Clasen committed
554
   * overrides the #GtkAboutDialog:logo property.
Matthias Clasen's avatar
Matthias Clasen committed
555 556
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
557
   */
558 559 560 561 562
  props[PROP_LOGO_ICON_NAME] =
    g_param_spec_string ("logo-icon-name",
                         P_("Logo Icon Name"),
                         P_("A named icon to use as the logo for the about box."),
                         "image-missing",
563
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
564

565 566 567 568 569
  /**
   * GtkAboutDialog:wrap-license:
   *
   * Whether to wrap the text in the license dialog.
   *
Matthias Clasen's avatar
Matthias Clasen committed
570
   * Since: 2.8
Matthias Clasen's avatar
Matthias Clasen committed
571
   */
572 573 574 575 576
  props[PROP_WRAP_LICENSE] =
    g_param_spec_boolean ("wrap-license",
                          P_("Wrap license"),
                          P_("Whether to wrap the license text."),
                          FALSE,
577
                          GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
578 579

  g_object_class_install_properties (object_class, LAST_PROP, props);
580

581 582 583
  /* Bind class to template
   */
  gtk_widget_class_set_template_from_resource (widget_class,
584
					       "/org/gtk/libgtk/ui/gtkaboutdialog.ui");
585

586
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, stack);
587
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, stack_switcher);
588 589 590 591 592 593 594
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, logo_image);
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, name_label);
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, version_label);
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, comments_label);
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, copyright_label);
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, license_label);
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, website_label);
595 596
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, credits_page);
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, license_page);
597 598
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, credits_grid);
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, license_view);
599 600 601 602 603

  gtk_widget_class_bind_template_callback (widget_class, emit_activate_link);
  gtk_widget_class_bind_template_callback (widget_class, text_view_event_after);
  gtk_widget_class_bind_template_callback (widget_class, text_view_key_press_event);
  gtk_widget_class_bind_template_callback (widget_class, text_view_motion_notify_event);
604
  gtk_widget_class_bind_template_callback (widget_class, stack_visible_child_notify);
605 606
}

607
static gboolean
608 609
emit_activate_link (GtkAboutDialog *about,
                    const gchar    *uri)
610
{
611
  gboolean handled = FALSE;
612

613
  g_signal_emit (about, signals[ACTIVATE_LINK], 0, uri, &handled);
614 615 616 617

  return TRUE;
}

618 619 620 621 622 623 624 625 626 627 628 629
static void
update_stack_switcher_visibility (GtkAboutDialog *about)
{
  GtkAboutDialogPrivate *priv = about->priv;

  if (gtk_widget_get_visible (priv->credits_page) ||
      gtk_widget_get_visible (priv->license_page))
    gtk_widget_show (priv->stack_switcher);
  else
    gtk_widget_hide (priv->stack_switcher);
}

630 631 632 633 634
static void
update_license_button_visibility (GtkAboutDialog *about)
{
  GtkAboutDialogPrivate *priv = about->priv;

635
  if (priv->license_type == GTK_LICENSE_CUSTOM && priv->license != NULL && priv->license[0] != '\0')
636
    gtk_widget_show (priv->license_page);
637
  else
638 639 640
    gtk_widget_hide (priv->license_page);

  update_stack_switcher_visibility (about);
641 642 643 644 645 646 647 648 649 650 651
}

static void
update_credits_button_visibility (GtkAboutDialog *about)
{
  GtkAboutDialogPrivate *priv = about->priv;
  gboolean show;

  show = (priv->authors != NULL ||
          priv->documenters != NULL ||
          priv->artists != NULL ||
652
          priv->credit_sections != NULL ||
Matthias Clasen's avatar
Matthias Clasen committed
653 654 655
          (priv->translator_credits != NULL &&
           strcmp (priv->translator_credits, "translator_credits") &&
           strcmp (priv->translator_credits, "translator-credits")));
656
  if (show)
657
    gtk_widget_show (priv->credits_page);
658
  else
659 660 661
    gtk_widget_hide (priv->credits_page);

  update_stack_switcher_visibility (about);
662 663 664 665
}

static void
switch_page (GtkAboutDialog *about,
666
             const gchar    *name)
667 668 669
{
  GtkAboutDialogPrivate *priv = about->priv;

670
  gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), name);
671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696

  priv->in_switch_page = TRUE;
  if (priv->credits_button)
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->credits_button),
                                  g_str_equal (name, "credits"));
  if (priv->license_button)
    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->license_button),
                                  g_str_equal (name, "license"));
  priv->in_switch_page = FALSE;
}

static void
apply_use_header_bar (GtkAboutDialog *about)
{
  GtkAboutDialogPrivate *priv = about->priv;
  gboolean use_header_bar;

  g_object_get (about, "use-header-bar", &use_header_bar, NULL);
  if (!use_header_bar)
    {
      GtkWidget *action_area;

      G_GNUC_BEGIN_IGNORE_DEPRECATIONS
      action_area = gtk_dialog_get_action_area (GTK_DIALOG (about));
      G_GNUC_END_IGNORE_DEPRECATIONS

697
      priv->credits_button = gtk_toggle_button_new_with_mnemonic (_("C_redits"));
698 699 700 701 702 703 704
      g_object_bind_property (priv->credits_page, "visible",
                              priv->credits_button, "visible", G_BINDING_SYNC_CREATE);
      g_signal_connect (priv->credits_button, "toggled", G_CALLBACK (toggle_credits), about);
      gtk_container_add_with_properties (GTK_CONTAINER (action_area), priv->credits_button,
                                         "secondary", TRUE,
                                         NULL);

705
      priv->license_button = gtk_toggle_button_new_with_mnemonic (_("_License"));
706 707 708 709 710 711 712 713
      g_object_bind_property (priv->license_page, "visible",
                              priv->license_button, "visible", G_BINDING_SYNC_CREATE);
      g_signal_connect (priv->license_button, "toggled", G_CALLBACK (toggle_license), about);
      gtk_container_add_with_properties (GTK_CONTAINER (action_area), priv->license_button,
                                         "secondary", TRUE,
                                         NULL);


714
      gtk_dialog_add_button (GTK_DIALOG (about), _("_Close"), GTK_RESPONSE_DELETE_EVENT);
715
    }
716 717
}

718 719 720 721 722 723
static void
gtk_about_dialog_init (GtkAboutDialog *about)
{
  GtkAboutDialogPrivate *priv;

  /* Data */
724
  priv = gtk_about_dialog_get_instance_private (about);
725
  about->priv = priv;
726 727 728 729 730

  priv->name = NULL;
  priv->version = NULL;
  priv->copyright = NULL;
  priv->comments = NULL;
731 732
  priv->website_url = NULL;
  priv->website_text = NULL;
733
  priv->translator_credits = NULL;
734
  priv->license = NULL;
735 736 737 738 739
  priv->authors = NULL;
  priv->documenters = NULL;
  priv->artists = NULL;

  priv->hovering_over_link = FALSE;
740
  priv->wrap_license = FALSE;
741

742 743
  priv->license_type = GTK_LICENSE_UNKNOWN;

744
  gtk_dialog_set_default_response (GTK_DIALOG (about), GTK_RESPONSE_CANCEL);
745

746
  gtk_widget_init_template (GTK_WIDGET (about));
747 748 749
  gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (about));

  apply_use_header_bar (about);
750

751
  switch_page (about, "main");
752
  update_stack_switcher_visibility (about);
753

754
  /* force defaults */
755
  gtk_about_dialog_set_program_name (about, NULL);
756
  gtk_about_dialog_set_logo (about, NULL);
757 758
}

Matthias Clasen's avatar
Matthias Clasen committed
759 760
static void
destroy_credit_section (gpointer data)
761 762 763 764 765 766 767
{
  CreditSection *cs = data;
  g_free (cs->heading);
  g_strfreev (cs->people);
  g_slice_free (CreditSection, data);
}

768 769 770 771
static void
gtk_about_dialog_finalize (GObject *object)
{
  GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
772
  GtkAboutDialogPrivate *priv = about->priv;
773 774 775 776 777 778

  g_free (priv->name);
  g_free (priv->version);
  g_free (priv->copyright);
  g_free (priv->comments);
  g_free (priv->license);
779 780
  g_free (priv->website_url);
  g_free (priv->website_text);
781 782 783 784 785 786
  g_free (priv->translator_credits);

  g_strfreev (priv->authors);
  g_strfreev (priv->documenters);
  g_strfreev (priv->artists);

787
  g_slist_free_full (priv->credit_sections, destroy_credit_section);
Matthias Clasen's avatar
Matthias Clasen committed
788
  g_slist_free_full (priv->visited_links, g_free);
789

790 791 792
  G_OBJECT_CLASS (gtk_about_dialog_parent_class)->finalize (object);
}

793 794 795 796 797 798 799 800 801 802
static void
gtk_about_dialog_realize (GtkWidget *widget)
{
  GtkAboutDialog *about = GTK_ABOUT_DIALOG (widget);
  GtkAboutDialogPrivate *priv = about->priv;
  GdkDisplay *display;

  GTK_WIDGET_CLASS (gtk_about_dialog_parent_class)->realize (widget);

  display = gtk_widget_get_display (widget);
803 804
  priv->hand_cursor = gdk_cursor_new_from_name (display, "pointer");
  priv->regular_cursor = gdk_cursor_new_from_name (display, "text");
805 806 807 808 809 810 811 812 813 814 815 816 817 818
}

static void
gtk_about_dialog_unrealize (GtkWidget *widget)
{
  GtkAboutDialog *about = GTK_ABOUT_DIALOG (widget);
  GtkAboutDialogPrivate *priv = about->priv;

  g_clear_object (&priv->hand_cursor);
  g_clear_object (&priv->regular_cursor);

  GTK_WIDGET_CLASS (gtk_about_dialog_parent_class)->unrealize (widget);
}

819
static void
Matthias Clasen's avatar
Matthias Clasen committed
820 821 822 823
gtk_about_dialog_set_property (GObject      *object,
                               guint         prop_id,
                               const GValue *value,
                               GParamSpec   *pspec)
824 825 826
{
  GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);

Matthias Clasen's avatar
Matthias Clasen committed
827
  switch (prop_id)
828 829
    {
    case PROP_NAME:
830
      gtk_about_dialog_set_program_name (about, g_value_get_string (value));
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846
      break;
    case PROP_VERSION:
      gtk_about_dialog_set_version (about, g_value_get_string (value));
      break;
    case PROP_COMMENTS:
      gtk_about_dialog_set_comments (about, g_value_get_string (value));
      break;
    case PROP_WEBSITE:
      gtk_about_dialog_set_website (about, g_value_get_string (value));
      break;
    case PROP_WEBSITE_LABEL:
      gtk_about_dialog_set_website_label (about, g_value_get_string (value));
      break;
    case PROP_LICENSE:
      gtk_about_dialog_set_license (about, g_value_get_string (value));
      break;
847 848 849
    case PROP_LICENSE_TYPE:
      gtk_about_dialog_set_license_type (about, g_value_get_enum (value));
      break;
850 851 852 853 854
    case PROP_COPYRIGHT:
      gtk_about_dialog_set_copyright (about, g_value_get_string (value));
      break;
    case PROP_LOGO:
      gtk_about_dialog_set_logo (about, g_value_get_object (value));
Matthias Clasen's avatar
Matthias Clasen committed
855
      break;
856
    case PROP_AUTHORS:
857
      gtk_about_dialog_set_authors (about, (const gchar**)g_value_get_boxed (value));
858 859
      break;
    case PROP_DOCUMENTERS:
860
      gtk_about_dialog_set_documenters (about, (const gchar**)g_value_get_boxed (value));
Matthias Clasen's avatar
Matthias Clasen committed
861
      break;
862
    case PROP_ARTISTS:
863
      gtk_about_dialog_set_artists (about, (const gchar**)g_value_get_boxed (value));
Matthias Clasen's avatar
Matthias Clasen committed
864
      break;
865 866 867
    case PROP_TRANSLATOR_CREDITS:
      gtk_about_dialog_set_translator_credits (about, g_value_get_string (value));
      break;
868 869 870
    case PROP_LOGO_ICON_NAME:
      gtk_about_dialog_set_logo_icon_name (about, g_value_get_string (value));
      break;
871
    case PROP_WRAP_LICENSE:
872
      gtk_about_dialog_set_wrap_license (about, g_value_get_boolean (value));
873
      break;
874 875 876 877 878 879 880
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
Matthias Clasen's avatar
Matthias Clasen committed
881 882 883 884
gtk_about_dialog_get_property (GObject    *object,
                               guint       prop_id,
                               GValue     *value,
                               GParamSpec *pspec)
885 886
{
  GtkAboutDialog *about = GTK_ABOUT_DIALOG (object);
887
  GtkAboutDialogPrivate *priv = about->priv;
Matthias Clasen's avatar
Matthias Clasen committed
888 889

  switch (prop_id)
890 891 892 893 894 895 896 897 898 899 900 901 902 903
    {
    case PROP_NAME:
      g_value_set_string (value, priv->name);
      break;
    case PROP_VERSION:
      g_value_set_string (value, priv->version);
      break;
    case PROP_COPYRIGHT:
      g_value_set_string (value, priv->copyright);
      break;
    case PROP_COMMENTS:
      g_value_set_string (value, priv->comments);
      break;
    case PROP_WEBSITE:
904
      g_value_set_string (value, priv->website_url);
905 906
      break;
    case PROP_WEBSITE_LABEL:
907
      g_value_set_string (value, priv->website_text);
908 909 910 911
      break;
    case PROP_LICENSE:
      g_value_set_string (value, priv->license);
      break;
912 913 914
    case PROP_LICENSE_TYPE:
      g_value_set_enum (value, priv->license_type);
      break;
915 916 917 918 919 920 921 922 923 924 925 926 927
    case PROP_TRANSLATOR_CREDITS:
      g_value_set_string (value, priv->translator_credits);
      break;
    case PROP_AUTHORS:
      g_value_set_boxed (value, priv->authors);
      break;
    case PROP_DOCUMENTERS:
      g_value_set_boxed (value, priv->documenters);
      break;
    case PROP_ARTISTS:
      g_value_set_boxed (value, priv->artists);
      break;
    case PROP_LOGO:
928
      if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
Matthias Clasen's avatar
Matthias Clasen committed
929
        g_value_set_object (value, gtk_image_get_pixbuf (GTK_IMAGE (priv->logo_image)));
930
      else
Matthias Clasen's avatar
Matthias Clasen committed
931
        g_value_set_object (value, NULL);
932 933 934
      break;
    case PROP_LOGO_ICON_NAME:
      if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_ICON_NAME)
Matthias Clasen's avatar
Matthias Clasen committed
935 936
        {
          const gchar *icon_name;
937

Matthias Clasen's avatar
Matthias Clasen committed
938 939 940
          gtk_image_get_icon_name (GTK_IMAGE (priv->logo_image), &icon_name, NULL);
          g_value_set_string (value, icon_name);
        }
941
      else
Matthias Clasen's avatar
Matthias Clasen committed
942
        g_value_set_string (value, NULL);
943
      break;
944 945 946
    case PROP_WRAP_LICENSE:
      g_value_set_boolean (value, priv->wrap_license);
      break;
947 948 949 950 951 952
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
static void
toggle_credits (GtkToggleButton *button,
                gpointer         user_data)
{
  GtkAboutDialog *about = user_data;
  GtkAboutDialogPrivate *priv = about->priv;
  gboolean show_credits;

  if (priv->in_switch_page)
    return;

  show_credits = gtk_toggle_button_get_active (button);
  switch_page (about, show_credits ? "credits" : "main");
}

static void
toggle_license (GtkToggleButton *button,
                gpointer         user_data)
{
  GtkAboutDialog *about = user_data;
  GtkAboutDialogPrivate *priv = about->priv;
  gboolean show_license;

  if (priv->in_switch_page)
    return;

  show_license = gtk_toggle_button_get_active (button);
  switch_page (about, show_license ? "license" : "main");
}

983 984 985 986 987 988
static gboolean
gtk_about_dialog_activate_link (GtkAboutDialog *about,
                                const gchar    *uri)
{
  GError *error = NULL;

989
  if (!gtk_show_uri_on_window (GTK_WINDOW (about), uri, gtk_get_current_event_time (), &error))
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
    {
      GtkWidget *dialog;

      dialog = gtk_message_dialog_new (GTK_WINDOW (about),
                                       GTK_DIALOG_DESTROY_WITH_PARENT |
                                       GTK_DIALOG_MODAL,
                                       GTK_MESSAGE_ERROR,
                                       GTK_BUTTONS_CLOSE,
                                       "%s", _("Could not show link"));
      gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
                                                "%s", error->message);
      g_error_free (error);

      g_signal_connect (dialog, "response",
                        G_CALLBACK (gtk_widget_destroy), NULL);

      gtk_window_present (GTK_WINDOW (dialog));
    }

  return TRUE;
}

1012 1013 1014
static void
update_website (GtkAboutDialog *about)
{
1015
  GtkAboutDialogPrivate *priv = about->priv;
1016

1017 1018
  gtk_widget_show (priv->website_label);

1019
  if (priv->website_url)
1020
    {
1021
      gchar *markup;
1022 1023

      if (priv->website_text)
1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034
        {
          gchar *escaped;

          escaped = g_markup_escape_text (priv->website_text, -1);
          markup = g_strdup_printf ("<a href=\"%s\">%s</a>",
                                    priv->website_url, escaped);
          g_free (escaped);
        }
      else
        {
          markup = g_strdup_printf ("<a href=\"%s\">%s</a>",
1035
                                    priv->website_url, _("Website"));
1036 1037
        }

1038
      gtk_label_set_markup (GTK_LABEL (priv->website_label), markup);
1039
      g_free (markup);
1040 1041 1042
    }
  else
    {
1043
      if (priv->website_text)
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
        gtk_label_set_text (GTK_LABEL (priv->website_label), priv->website_text);
      else
        gtk_widget_hide (priv->website_label);
    }
}

static void
gtk_about_dialog_show (GtkWidget *widget)
{
  update_website (GTK_ABOUT_DIALOG (widget));
Matthias Clasen's avatar
Matthias Clasen committed
1054

1055 1056 1057
  GTK_WIDGET_CLASS (gtk_about_dialog_parent_class)->show (widget);
}

1058 1059 1060
/**
 * gtk_about_dialog_get_program_name:
 * @about: a #GtkAboutDialog
Matthias Clasen's avatar
Matthias Clasen committed
1061
 *
1062
 * Returns the program name displayed in the about dialog.
Matthias Clasen's avatar
Matthias Clasen committed
1063
 *
1064
 * Returns: The program name. The string is owned by the about
1065 1066 1067
 *  dialog and must not be modified.
 *
 * Since: 2.12
Matthias Clasen's avatar
Matthias Clasen committed
1068
 */
1069
const gchar *
1070
gtk_about_dialog_get_program_name (GtkAboutDialog *about)
1071 1072 1073
{
  g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);

Matthias Clasen's avatar
Matthias Clasen committed
1074
  return about->priv->name;
1075 1076 1077 1078 1079 1080 1081 1082
}

static void
update_name_version (GtkAboutDialog *about)
{
  GtkAboutDialogPrivate *priv;
  gchar *title_string, *name_string;

1083
  priv = about->priv;
1084 1085 1086 1087 1088

  title_string = g_strdup_printf (_("About %s"), priv->name);
  gtk_window_set_title (GTK_WINDOW (about), title_string);
  g_free (title_string);

Matthias Clasen's avatar
Matthias Clasen committed
1089
  if (priv->version != NULL)
1090 1091 1092 1093
    {
      gtk_label_set_markup (GTK_LABEL (priv->version_label), priv->version);
      gtk_widget_show (priv->version_label);
    }
1094
  else
1095
    gtk_widget_hide (priv->version_label);
1096

1097 1098
  name_string = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>",
                                         priv->name);
1099 1100 1101 1102
  gtk_label_set_markup (GTK_LABEL (priv->name_label), name_string);
  g_free (name_string);
}

1103 1104 1105 1106 1107
/**
 * gtk_about_dialog_set_program_name:
 * @about: a #GtkAboutDialog
 * @name: the program name
 *
Matthias Clasen's avatar
Matthias Clasen committed
1108
 * Sets the name to display in the about dialog.
1109
 * If this is not set, it defaults to g_get_application_name().
Matthias Clasen's avatar
Matthias Clasen committed
1110
 *
1111
 * Since: 2.12
Matthias Clasen's avatar
Matthias Clasen committed
1112
 */
1113
void
Matthias Clasen's avatar
Matthias Clasen committed
1114
gtk_about_dialog_set_program_name (GtkAboutDialog *about,
1115
                                   const gchar    *name)
1116 1117 1118 1119 1120
{
  GtkAboutDialogPrivate *priv;
  gchar *tmp;

  g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));
Matthias Clasen's avatar
Matthias Clasen committed
1121

1122 1123
  priv = about->priv;

1124 1125 1126 1127 1128 1129
  tmp = priv->name;
  priv->name = g_strdup (name ? name : g_get_application_name ());
  g_free (tmp);

  update_name_version (about);

1130
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_NAME]);
1131 1132
}

1133

1134 1135 1136
/**
 * gtk_about_dialog_get_version:
 * @about: a #GtkAboutDialog
Matthias Clasen's avatar
Matthias Clasen committed
1137
 *
1138
 * Returns the version string.
Matthias Clasen's avatar
Matthias Clasen committed
1139
 *
1140
 * Returns: The version string. The string is owned by the about
1141 1142 1143
 *  dialog and must not be modified.
 *
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
1144
 */
1145
const gchar *
1146 1147 1148 1149
gtk_about_dialog_get_version (GtkAboutDialog *about)
{
  g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);

1150
  return about->priv->version;
1151 1152 1153 1154 1155
}

/**
 * gtk_about_dialog_set_version:
 * @about: a #GtkAboutDialog
1156
 * @version: (allow-none): the version string
1157 1158
 *
 * Sets the version string to display in the about dialog.
Matthias Clasen's avatar
Matthias Clasen committed
1159
 *
1160
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
1161
 */
1162
void
Matthias Clasen's avatar
Matthias Clasen committed
1163 1164
gtk_about_dialog_set_version (GtkAboutDialog *about,
                              const gchar    *version)
1165 1166 1167 1168 1169 1170
{
  GtkAboutDialogPrivate *priv;
  gchar *tmp;

  g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));

1171 1172
  priv = about->priv;

1173
  tmp = priv->version;
1174
  priv->version = g_strdup (version);
Matthias Clasen's avatar
Matthias Clasen committed
1175
  g_free (tmp);
1176 1177 1178

  update_name_version (about);

1179
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_VERSION]);
1180 1181 1182 1183 1184
}

/**
 * gtk_about_dialog_get_copyright:
 * @about: a #GtkAboutDialog
Matthias Clasen's avatar
Matthias Clasen committed
1185
 *
1186
 * Returns the copyright string.
Matthias Clasen's avatar
Matthias Clasen committed
1187
 *
1188
 * Returns: The copyright string. The string is owned by the about
1189 1190 1191
 *  dialog and must not be modified.
 *
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
1192
 */
1193
const gchar *
1194 1195 1196 1197
gtk_about_dialog_get_copyright (GtkAboutDialog *about)
{
  g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);

1198
  return about->priv->copyright;
1199 1200 1201 1202 1203
}

/**
 * gtk_about_dialog_set_copyright:
 * @about: a #GtkAboutDialog
Jasper St. Pierre's avatar
Jasper St. Pierre committed
1204
 * @copyright: (allow-none): the copyright string
Matthias Clasen's avatar
Matthias Clasen committed
1205
 *
1206
 * Sets the copyright string to display in the about dialog.
Matthias Clasen's avatar
Matthias Clasen committed
1207
 * This should be a short string of one or two lines.
1208 1209
 *
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
1210
 */
1211
void
Matthias Clasen's avatar
Matthias Clasen committed
1212 1213
gtk_about_dialog_set_copyright (GtkAboutDialog *about,
                                const gchar    *copyright)
1214 1215 1216 1217 1218 1219
{
  GtkAboutDialogPrivate *priv;
  gchar *copyright_string, *tmp;

  g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));

1220
  priv = about->priv;
Matthias Clasen's avatar
Matthias Clasen committed
1221

1222
  tmp = priv->copyright;
1223
  priv->copyright = g_strdup (copyright);
1224
  g_free (tmp);
Matthias Clasen's avatar
Matthias Clasen committed
1225 1226

  if (priv->copyright != NULL)
1227
    {
Matthias Clasen's avatar
Matthias Clasen committed
1228 1229
      copyright_string = g_markup_printf_escaped ("<span size=\"small\">%s</span>",
                                                  priv->copyright);
1230 1231
      gtk_label_set_markup (GTK_LABEL (priv->copyright_label), copyright_string);
      g_free (copyright_string);
Matthias Clasen's avatar
Matthias Clasen committed
1232

1233 1234
      gtk_widget_show (priv->copyright_label);
    }
Matthias Clasen's avatar
Matthias Clasen committed
1235
  else
1236
    gtk_widget_hide (priv->copyright_label);
Matthias Clasen's avatar
Matthias Clasen committed
1237

1238
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_COPYRIGHT]);
1239 1240 1241 1242 1243
}

/**
 * gtk_about_dialog_get_comments:
 * @about: a #GtkAboutDialog
Matthias Clasen's avatar
Matthias Clasen committed
1244
 *
1245
 * Returns the comments string.
Matthias Clasen's avatar
Matthias Clasen committed
1246
 *
1247
 * Returns: The comments. The string is owned by the about
1248 1249 1250
 *  dialog and must not be modified.
 *
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
1251
 */
1252
const gchar *
1253 1254 1255 1256
gtk_about_dialog_get_comments (GtkAboutDialog *about)
{
  g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);

1257
  return about->priv->comments;
1258 1259 1260 1261 1262
}

/**
 * gtk_about_dialog_set_comments:
 * @about: a #GtkAboutDialog
1263
 * @comments: (allow-none): a comments string
Matthias Clasen's avatar
Matthias Clasen committed
1264 1265 1266
 *
 * Sets the comments string to display in the about dialog.
 * This should be a short string of one or two lines.
1267 1268
 *
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
1269
 */
1270
void
Matthias Clasen's avatar
Matthias Clasen committed
1271 1272
gtk_about_dialog_set_comments (GtkAboutDialog *about,
                               const gchar    *comments)
1273 1274 1275 1276 1277 1278
{
  GtkAboutDialogPrivate *priv;
  gchar *tmp;

  g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));

1279
  priv = about->priv;
Matthias Clasen's avatar
Matthias Clasen committed
1280

1281
  tmp = priv->comments;
Matthias Clasen's avatar
Matthias Clasen committed
1282
  if (comments)
1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294
    {
      priv->comments = g_strdup (comments);
      gtk_label_set_text (GTK_LABEL (priv->comments_label), priv->comments);
      gtk_widget_show (priv->comments_label);
    }
  else
    {
      priv->comments = NULL;
      gtk_widget_hide (priv->comments_label);
    }
  g_free (tmp);

1295
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_COMMENTS]);
1296 1297 1298 1299 1300
}

/**
 * gtk_about_dialog_get_license:
 * @about: a #GtkAboutDialog
Matthias Clasen's avatar
Matthias Clasen committed
1301
 *
1302
 * Returns the license information.
Matthias Clasen's avatar
Matthias Clasen committed
1303
 *
1304
 * Returns: The license information. The string is owned by the about
1305 1306 1307
 *  dialog and must not be modified.
 *
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
1308
 */
1309
const gchar *
1310 1311 1312 1313
gtk_about_dialog_get_license (GtkAboutDialog *about)
{
  g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), NULL);

1314
  return about->priv->license;
1315 1316 1317 1318 1319
}

/**
 * gtk_about_dialog_set_license:
 * @about: a #GtkAboutDialog
1320
 * @license: (allow-none): the license information or %NULL
1321 1322 1323 1324
 *
 * Sets the license information to be displayed in the secondary
 * license dialog. If @license is %NULL, the license button is
 * hidden.
Matthias Clasen's avatar
Matthias Clasen committed
1325
 *
1326
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
1327
 */
1328
void
Matthias Clasen's avatar
Matthias Clasen committed
1329 1330
gtk_about_dialog_set_license (GtkAboutDialog *about,
                              const gchar    *license)
1331 1332 1333 1334 1335 1336
{
  GtkAboutDialogPrivate *priv;
  gchar *tmp;

  g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));

1337
  priv = about->priv;
1338 1339

  tmp = priv->license;
Matthias Clasen's avatar
Matthias Clasen committed
1340
  if (license)
1341 1342
    {
      priv->license = g_strdup (license);
1343
      priv->license_type = GTK_LICENSE_CUSTOM;
1344 1345 1346 1347
    }
  else
    {
      priv->license = NULL;
1348
      priv->license_type = GTK_LICENSE_UNKNOWN;
1349 1350 1351
    }
  g_free (tmp);

1352 1353 1354 1355
  gtk_widget_hide (priv->license_label);

  update_license_button_visibility (about);

1356 1357
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_LICENSE]);
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_LICENSE_TYPE]);
1358 1359
}

1360 1361 1362 1363
/**
 * gtk_about_dialog_get_wrap_license:
 * @about: a #GtkAboutDialog
 *
Matthias Clasen's avatar
Matthias Clasen committed
1364
 * Returns whether the license text in @about is
1365 1366
 * automatically wrapped.
 *
Matthias Clasen's avatar
Matthias Clasen committed
1367
 * Returns: %TRUE if the license text is wrapped
1368 1369 1370 1371 1372 1373 1374 1375
 *
 * Since: 2.8
 */
gboolean
gtk_about_dialog_get_wrap_license (GtkAboutDialog *about)
{
  g_return_val_if_fail (GTK_IS_ABOUT_DIALOG (about), FALSE);

1376
  return about->priv->wrap_license;
1377 1378 1379 1380 1381 1382 1383
}

/**
 * gtk_about_dialog_set_wrap_license:
 * @about: a #GtkAboutDialog
 * @wrap_license: whether to wrap the license
 *