gtkaboutdialog.c 75.2 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 76 77
 * displays these as clickable links. By default, it calls gtk_show_uri()
 * when a user clicks one. The behaviour can be overridden with the
 * #GtkAboutDialog::activate-link signal.
78
 *
79 80 81 82
 * To specify a person with an email address, use a string like
 * "Edgar Allan Poe <edgar@poe.com>". To specify a website with a title,
 * 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 94 95 96 97
 * gtk_show_about_dialog (NULL,
 *                        "program-name", "ExampleCode",
 *                        "logo", example_logo,
 *                        "title" _("About ExampleCode"),
 *                        NULL);
98
 * ]|
99 100 101
 *
 * 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
102
 * the “Close” button returns the #GTK_RESPONSE_CANCEL response id.
103 104
 */

105 106 107 108 109 110
typedef struct
{
  const gchar *name;
  const gchar *url;
} LicenseInfo;

111 112 113
/* Translators: this is the license preamble; the string at the end
 * contains the name of the license as link text.
 */
114
static const gchar *gtk_license_preamble = N_("This program comes with absolutely no warranty.\nSee the <a href=\"%s\">%s</a> for details.");
115

116 117 118 119 120
/* 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 },
  { N_("GNU General Public License, version 2 or later"), "http://www.gnu.org/licenses/old-licenses/gpl-2.0.html" },
121
  { N_("GNU General Public License, version 3 or later"), "http://www.gnu.org/licenses/gpl-3.0.html" },
122
  { N_("GNU Lesser General Public License, version 2.1 or later"), "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html" },
123
  { N_("GNU Lesser General Public License, version 3 or later"), "http://www.gnu.org/licenses/lgpl-3.0.html" },
124 125 126 127
  { N_("BSD 2-Clause License"), "http://opensource.org/licenses/bsd-license.php" },
  { N_("The MIT License (MIT)"), "http://opensource.org/licenses/mit-license.php" },
  { N_("Artistic License 2.0"), "http://opensource.org/licenses/artistic-license-2.0.php" },
  { N_("GNU General Public License, version 2 only"), "http://www.gnu.org/licenses/old-licenses/gpl-2.0.html" },
128
  { N_("GNU General Public License, version 3 only"), "http://www.gnu.org/licenses/gpl-3.0.html" },
129
  { N_("GNU Lesser General Public License, version 2.1 only"), "http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html" },
130
  { N_("GNU Lesser General Public License, version 3 only"), "http://www.gnu.org/licenses/lgpl-3.0.html" }
131 132
};

133 134 135 136 137 138
typedef struct
{
  gchar *heading;
  gchar **people;
} CreditSection;

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

150 151 152
  gchar **authors;
  gchar **documenters;
  gchar **artists;
Matthias Clasen's avatar
Matthias Clasen committed
153

154 155
  GSList *credit_sections;

156 157
  gboolean credits_page_initialized;
  gboolean license_page_initialized;
158

159
  GtkWidget *stack;
160
  GtkWidget *stack_switcher;
161 162 163
  GtkWidget *credits_button;
  GtkWidget *license_button;

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

172 173
  GtkWidget *credits_page;
  GtkWidget *license_page;
Matthias Clasen's avatar
Matthias Clasen committed
174

175 176 177
  GtkWidget *credits_grid;
  GtkWidget *license_view;

178 179
  GdkCursor *hand_cursor;
  GdkCursor *regular_cursor;
Matthias Clasen's avatar
Matthias Clasen committed
180

181 182
  GSList *visited_links;

183 184
  GtkLicense license_type;

185 186
  guint hovering_over_link : 1;
  guint wrap_license : 1;
187
  guint in_child_changed : 1;
188
  guint in_switch_page : 1;
189 190
};

Matthias Clasen's avatar
Matthias Clasen committed
191
enum
192 193 194 195 196 197 198 199 200 201 202 203 204
{
  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,
205
  PROP_LOGO,
206
  PROP_LOGO_ICON_NAME,
207
  PROP_WRAP_LICENSE,
208 209
  PROP_LICENSE_TYPE,
  LAST_PROP
210 211 212 213
};

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

254 255 256 257
enum {
  ACTIVATE_LINK,
  LAST_SIGNAL
};
258

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

262
G_DEFINE_TYPE_WITH_PRIVATE (GtkAboutDialog, gtk_about_dialog, GTK_TYPE_DIALOG)
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 290 291
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;
}
292

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

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

302 303 304 305 306
  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;

307
  widget_class->show = gtk_about_dialog_show;
308 309
  widget_class->realize = gtk_about_dialog_realize;
  widget_class->unrealize = gtk_about_dialog_unrealize;
310

311 312 313 314 315 316 317 318 319 320 321 322 323
  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,
   * which is to call gtk_show_uri().
   *
   * Returns: %TRUE if the link has been activated
   *
324
   * Since: 2.24
325 326 327 328 329 330 331 332 333 334
   */
  signals[ACTIVATE_LINK] =
    g_signal_new ("activate-link",
                  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
335
  /**
336
   * GtkAboutDialog:program-name:
Matthias Clasen's avatar
Matthias Clasen committed
337
   *
Matthias Clasen's avatar
Matthias Clasen committed
338
   * The name of the program.
Matthias Clasen's avatar
Matthias Clasen committed
339 340
   * If this is not set, it defaults to g_get_application_name().
   *
341
   * Since: 2.12
Matthias Clasen's avatar
Matthias Clasen committed
342
   */
343 344 345 346 347
  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,
348
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
349

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

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

  /**
   * GtkAboutDialog:comments:
   *
Matthias Clasen's avatar
Matthias Clasen committed
381
   * Comments about the program. This string is displayed in a label
Matthias Clasen's avatar
Matthias Clasen committed
382 383 384 385
   * 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
386
   */
387 388 389 390 391
  props[PROP_COMMENTS] =
    g_param_spec_string ("comments",
                         P_("Comments string"),
                         P_("Comments about the program"),
                         NULL,
392
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
Matthias Clasen's avatar
Matthias Clasen committed
393 394 395 396

  /**
   * GtkAboutDialog:license:
   *
Matthias Clasen's avatar
Matthias Clasen committed
397
   * The license of the program. This string is displayed in a
Matthias Clasen's avatar
Matthias Clasen committed
398
   * text view in a secondary dialog, therefore it is fine to use
399 400 401
   * 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.
402 403 404
   * 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
405 406
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
407
   */
408 409
  props[PROP_LICENSE] =
    g_param_spec_string ("license",
410 411
                         P_("License"),
                         P_("The license of the program"),
412
                         NULL,
413
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
414

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
  /**
   * 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
   */
436 437 438 439 440 441
  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,
442
                       GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
443

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

Matthias Clasen's avatar
Matthias Clasen committed
459 460 461
  /**
   * GtkAboutDialog:website-label:
   *
462
   * The label for the link to the website of the program.
Matthias Clasen's avatar
Matthias Clasen committed
463 464
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
465
   */
466 467 468 469 470
  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,
471
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
472

Matthias Clasen's avatar
Matthias Clasen committed
473 474 475 476 477 478 479 480
  /**
   * 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
481
   */
482 483 484 485 486
  props[PROP_AUTHORS] =
    g_param_spec_boxed ("authors",
                        P_("Authors"),
                        P_("List of authors of the program"),
                        G_TYPE_STRV,
487
                        GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
Matthias Clasen's avatar
Matthias Clasen committed
488 489 490 491 492 493 494 495 496

  /**
   * 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
497
   */
498 499 500 501 502
  props[PROP_DOCUMENTERS] =
    g_param_spec_boxed ("documenters",
                        P_("Documenters"),
                        P_("List of people documenting the program"),
                        G_TYPE_STRV,
503
                        GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
504

Matthias Clasen's avatar
Matthias Clasen committed
505 506 507
  /**
   * GtkAboutDialog:artists:
   *
Matthias Clasen's avatar
Matthias Clasen committed
508 509 510
   * 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
511 512
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
513
   */
514 515 516 517 518
  props[PROP_ARTISTS] =
    g_param_spec_boxed ("artists",
                        P_("Artists"),
                        P_("List of people who have contributed artwork to the program"),
                        G_TYPE_STRV,
519
                        GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
Matthias Clasen's avatar
Matthias Clasen committed
520 521 522 523 524 525 526 527 528

  /**
   * 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
529
   */
530 531 532 533 534
  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,
535
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
536

Matthias Clasen's avatar
Matthias Clasen committed
537 538 539
  /**
   * GtkAboutDialog:logo:
   *
540 541
   * 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
542 543
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
544
   */
545 546 547 548 549
  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,
550
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
551

Matthias Clasen's avatar
Matthias Clasen committed
552 553 554 555
  /**
   * 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
556
   * overrides the #GtkAboutDialog:logo property.
Matthias Clasen's avatar
Matthias Clasen committed
557 558
   *
   * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
559
   */
560 561 562 563 564
  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",
565
                         GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
566

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

  g_object_class_install_properties (object_class, LAST_PROP, props);
582

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

588
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, stack);
589
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, stack_switcher);
590 591 592 593 594 595 596
  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);
597 598
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, credits_page);
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, license_page);
599 600
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, credits_grid);
  gtk_widget_class_bind_template_child_private (widget_class, GtkAboutDialog, license_view);
601 602 603 604 605

  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);
606
  gtk_widget_class_bind_template_callback (widget_class, stack_visible_child_notify);
607 608
}

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

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

  return TRUE;
}

620 621 622 623 624 625 626 627 628 629 630 631
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);
}

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

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

  update_stack_switcher_visibility (about);
643 644 645 646 647 648 649 650 651 652 653
}

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

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

  update_stack_switcher_visibility (about);
664 665 666 667
}

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

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

  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

699
      priv->credits_button = gtk_toggle_button_new_with_mnemonic (_("C_redits"));
700 701 702 703 704 705 706
      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);

707
      priv->license_button = gtk_toggle_button_new_with_mnemonic (_("_License"));
708 709 710 711 712 713 714 715
      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);


716
      gtk_dialog_add_button (GTK_DIALOG (about), _("_Close"), GTK_RESPONSE_DELETE_EVENT);
717
    }
718 719
}

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

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

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

  priv->hovering_over_link = FALSE;
742
  priv->wrap_license = FALSE;
743

744 745
  priv->license_type = GTK_LICENSE_UNKNOWN;

746
  gtk_dialog_set_default_response (GTK_DIALOG (about), GTK_RESPONSE_CANCEL);
747

748
  gtk_widget_init_template (GTK_WIDGET (about));
749 750 751
  gtk_dialog_set_use_header_bar_from_setting (GTK_DIALOG (about));

  apply_use_header_bar (about);
752

753
  switch_page (about, "main");
754
  update_stack_switcher_visibility (about);
755

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

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

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

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

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

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

792 793 794
  G_OBJECT_CLASS (gtk_about_dialog_parent_class)->finalize (object);
}

795 796 797 798 799 800 801 802 803 804
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);
805 806
  priv->hand_cursor = gdk_cursor_new_from_name (display, "pointer");
  priv->regular_cursor = gdk_cursor_new_from_name (display, "text");
807 808 809 810 811 812 813 814 815 816 817 818 819 820
}

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);
}

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

Matthias Clasen's avatar
Matthias Clasen committed
829
  switch (prop_id)
830 831
    {
    case PROP_NAME:
832
      gtk_about_dialog_set_program_name (about, g_value_get_string (value));
833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848
      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;
849 850 851
    case PROP_LICENSE_TYPE:
      gtk_about_dialog_set_license_type (about, g_value_get_enum (value));
      break;
852 853 854 855 856
    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
857
      break;
858
    case PROP_AUTHORS:
859
      gtk_about_dialog_set_authors (about, (const gchar**)g_value_get_boxed (value));
860 861
      break;
    case PROP_DOCUMENTERS:
862
      gtk_about_dialog_set_documenters (about, (const gchar**)g_value_get_boxed (value));
Matthias Clasen's avatar
Matthias Clasen committed
863
      break;
864
    case PROP_ARTISTS:
865
      gtk_about_dialog_set_artists (about, (const gchar**)g_value_get_boxed (value));
Matthias Clasen's avatar
Matthias Clasen committed
866
      break;
867 868 869
    case PROP_TRANSLATOR_CREDITS:
      gtk_about_dialog_set_translator_credits (about, g_value_get_string (value));
      break;
870 871 872
    case PROP_LOGO_ICON_NAME:
      gtk_about_dialog_set_logo_icon_name (about, g_value_get_string (value));
      break;
873
    case PROP_WRAP_LICENSE:
874
      gtk_about_dialog_set_wrap_license (about, g_value_get_boolean (value));
875
      break;
876 877 878 879 880 881 882
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

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

  switch (prop_id)
892 893 894 895 896 897 898 899 900 901 902 903 904 905
    {
    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:
906
      g_value_set_string (value, priv->website_url);
907 908
      break;
    case PROP_WEBSITE_LABEL:
909
      g_value_set_string (value, priv->website_text);
910 911 912 913
      break;
    case PROP_LICENSE:
      g_value_set_string (value, priv->license);
      break;
914 915 916
    case PROP_LICENSE_TYPE:
      g_value_set_enum (value, priv->license_type);
      break;
917 918 919 920 921 922 923 924 925 926 927 928 929
    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:
930
      if (gtk_image_get_storage_type (GTK_IMAGE (priv->logo_image)) == GTK_IMAGE_PIXBUF)
Matthias Clasen's avatar
Matthias Clasen committed
931
        g_value_set_object (value, gtk_image_get_pixbuf (GTK_IMAGE (priv->logo_image)));
932
      else
Matthias Clasen's avatar
Matthias Clasen committed
933
        g_value_set_object (value, NULL);
934 935 936
      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
937 938
        {
          const gchar *icon_name;
939

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

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 983 984
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");
}

985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
static gboolean
gtk_about_dialog_activate_link (GtkAboutDialog *about,
                                const gchar    *uri)
{
  GdkScreen *screen;
  GError *error = NULL;

  screen = gtk_widget_get_screen (GTK_WIDGET (about));

  if (!gtk_show_uri (screen, uri, gtk_get_current_event_time (), &error))
    {
      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;
}

1017 1018 1019
static void
update_website (GtkAboutDialog *about)
{
1020
  GtkAboutDialogPrivate *priv = about->priv;
1021

1022 1023
  gtk_widget_show (priv->website_label);

1024
  if (priv->website_url)
1025
    {
1026
      gchar *markup;
1027 1028

      if (priv->website_text)
1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039
        {
          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>",
1040
                                    priv->website_url, _("Website"));
1041 1042
        }

1043
      gtk_label_set_markup (GTK_LABEL (priv->website_label), markup);
1044
      g_free (markup);
1045 1046 1047
    }
  else
    {
1048
      if (priv->website_text)
1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
        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
1059

1060 1061 1062
  GTK_WIDGET_CLASS (gtk_about_dialog_parent_class)->show (widget);
}

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

Matthias Clasen's avatar
Matthias Clasen committed
1079
  return about->priv->name;
1080 1081 1082 1083 1084 1085 1086 1087
}

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

1088
  priv = about->priv;
1089 1090 1091 1092 1093

  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
1094
  if (priv->version != NULL)
1095 1096 1097 1098
    {
      gtk_label_set_markup (GTK_LABEL (priv->version_label), priv->version);
      gtk_widget_show (priv->version_label);
    }
1099
  else
1100
    gtk_widget_hide (priv->version_label);
1101

1102 1103
  name_string = g_markup_printf_escaped ("<span weight=\"bold\">%s</span>",
                                         priv->name);
1104 1105 1106 1107
  gtk_label_set_markup (GTK_LABEL (priv->name_label), name_string);
  g_free (name_string);
}

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

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

1127 1128
  priv = about->priv;

1129 1130 1131 1132 1133 1134
  tmp = priv->name;
  priv->name = g_strdup (name ? name : g_get_application_name ());
  g_free (tmp);

  update_name_version (about);

1135
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_NAME]);
1136 1137
}

1138

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

1155
  return about->priv->version;
1156 1157 1158 1159 1160
}

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

  g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));

1176 1177
  priv = about->priv;

1178
  tmp = priv->version;
1179
  priv->version = g_strdup (version);
Matthias Clasen's avatar
Matthias Clasen committed
1180
  g_free (tmp);
1181 1182 1183

  update_name_version (about);

1184
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_VERSION]);
1185 1186 1187 1188 1189
}

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

1203
  return about->priv->copyright;
1204 1205 1206 1207 1208
}

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

  g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));

1225
  priv = about->priv;
Matthias Clasen's avatar
Matthias Clasen committed
1226

1227
  tmp = priv->copyright;
1228
  priv->copyright = g_strdup (copyright);
1229
  g_free (tmp);
Matthias Clasen's avatar
Matthias Clasen committed
1230 1231

  if (priv->copyright != NULL)
1232
    {
Matthias Clasen's avatar
Matthias Clasen committed
1233 1234
      copyright_string = g_markup_printf_escaped ("<span size=\"small\">%s</span>",
                                                  priv->copyright);
1235 1236
      gtk_label_set_markup (GTK_LABEL (priv->copyright_label), copyright_string);
      g_free (copyright_string);
Matthias Clasen's avatar
Matthias Clasen committed
1237

1238 1239
      gtk_widget_show (priv->copyright_label);
    }
Matthias Clasen's avatar
Matthias Clasen committed
1240
  else
1241
    gtk_widget_hide (priv->copyright_label);
Matthias Clasen's avatar
Matthias Clasen committed
1242

1243
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_COPYRIGHT]);
1244 1245 1246 1247 1248
}

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

1262
  return about->priv->comments;
1263 1264 1265 1266 1267
}

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

  g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));

1284
  priv = about->priv;
Matthias Clasen's avatar
Matthias Clasen committed
1285

1286
  tmp = priv->comments;
Matthias Clasen's avatar
Matthias Clasen committed
1287
  if (comments)
1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
    {
      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);

1300
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_COMMENTS]);
1301 1302 1303 1304 1305
}

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

1319
  return about->priv->license;
1320 1321 1322 1323 1324
}

/**
 * gtk_about_dialog_set_license:
 * @about: a #GtkAboutDialog
1325
 * @license: (allow-none): the license information or %NULL
1326 1327 1328 1329
 *
 * 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
1330
 *
1331
 * Since: 2.6
Matthias Clasen's avatar
Matthias Clasen committed
1332
 */
1333
void
Matthias Clasen's avatar
Matthias Clasen committed
1334 1335
gtk_about_dialog_set_license (GtkAboutDialog *about,
                              const gchar    *license)
1336 1337 1338 1339 1340 1341
{
  GtkAboutDialogPrivate *priv;
  gchar *tmp;

  g_return_if_fail (GTK_IS_ABOUT_DIALOG (about));

1342
  priv = about->priv;
1343 1344

  tmp = priv->license;
Matthias Clasen's avatar
Matthias Clasen committed
1345
  if (license)
1346 1347
    {
      priv->license = g_strdup (license);
1348
      priv->license_type = GTK_LICENSE_CUSTOM;
1349 1350 1351 1352
    }
  else
    {
      priv->license = NULL;
1353
      priv->license_type = GTK_LICENSE_UNKNOWN;
1354 1355 1356
    }
  g_free (tmp);

1357 1358 1359 1360
  gtk_widget_hide (priv->license_label);

  update_license_button_visibility (about);

1361 1362
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_LICENSE]);
  g_object_notify_by_pspec (G_OBJECT (about), props[PROP_LICENSE_TYPE]);
1363 1364
}

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

1381
  return about->priv->wrap_license;
1382 1383 1384 1385 1386 1387 1388
}