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