1/* GTK - The GIMP Toolkit
2 * gtklinkbutton.c - a hyperlink-enabled button
3 *
4 * Copyright (C) 2006 Emmanuele Bassi <ebassi@gmail.com>
5 * All rights reserved.
6 *
7 * Based on gnome-href code by:
8 * James Henstridge <james@daa.com.au>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
19 *
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/**
25 * GtkLinkButton:
26 *
27 * A `GtkLinkButton` is a button with a hyperlink.
28 *
29 * ![An example GtkLinkButton](link-button.png)
30 *
31 * It is useful to show quick links to resources.
32 *
33 * A link button is created by calling either [ctor@Gtk.LinkButton.new] or
34 * [ctor@Gtk.LinkButton.new_with_label]. If using the former, the URI you
35 * pass to the constructor is used as a label for the widget.
36 *
37 * The URI bound to a `GtkLinkButton` can be set specifically using
38 * [method@Gtk.LinkButton.set_uri].
39 *
40 * By default, `GtkLinkButton` calls [func@Gtk.show_uri] when the button
41 * is clicked. This behaviour can be overridden by connecting to the
42 * [signal@Gtk.LinkButton::activate-link] signal and returning %TRUE from
43 * the signal handler.
44 *
45 * # CSS nodes
46 *
47 * `GtkLinkButton` has a single CSS node with name button. To differentiate
48 * it from a plain `GtkButton`, it gets the .link style class.
49 *
50 * # Accessibility
51 *
52 * `GtkLinkButton` uses the %GTK_ACCESSIBLE_ROLE_LINK role.
53 */
54
55#include "config.h"
56
57#include "gtklinkbutton.h"
58
59#include "gtkdragsource.h"
60#include "gtkgestureclick.h"
61#include "gtkgesturesingle.h"
62#include "gtkintl.h"
63#include "gtklabel.h"
64#include "gtkmain.h"
65#include "gtkmarshalers.h"
66#include "gtkpopovermenu.h"
67#include "gtkprivate.h"
68#include "gtkshow.h"
69#include "gtksizerequest.h"
70#include "gtktooltip.h"
71#include "gtkwidgetprivate.h"
72
73#include <string.h>
74
75typedef struct _GtkLinkButtonClass GtkLinkButtonClass;
76
77struct _GtkLinkButton
78{
79 /*< private >*/
80 GtkButton parent_instance;
81
82 char *uri;
83 gboolean visited;
84 GtkWidget *popup_menu;
85};
86
87struct _GtkLinkButtonClass
88{
89 /*< private >*/
90 GtkButtonClass parent_class;
91
92 /*< public >*/
93 gboolean (* activate_link) (GtkLinkButton *button);
94};
95
96enum
97{
98 PROP_0,
99 PROP_URI,
100 PROP_VISITED
101};
102
103enum
104{
105 ACTIVATE_LINK,
106
107 LAST_SIGNAL
108};
109
110static void gtk_link_button_finalize (GObject *object);
111static void gtk_link_button_get_property (GObject *object,
112 guint prop_id,
113 GValue *value,
114 GParamSpec *pspec);
115static void gtk_link_button_set_property (GObject *object,
116 guint prop_id,
117 const GValue *value,
118 GParamSpec *pspec);
119static void gtk_link_button_clicked (GtkButton *button);
120static void gtk_link_button_popup_menu (GtkWidget *widget,
121 const char *action_name,
122 GVariant *parameters);
123static gboolean gtk_link_button_query_tooltip_cb (GtkWidget *widget,
124 int x,
125 int y,
126 gboolean keyboard_tip,
127 GtkTooltip *tooltip,
128 gpointer data);
129static void gtk_link_button_pressed_cb (GtkGestureClick *gesture,
130 int n_press,
131 double x,
132 double y,
133 gpointer user_data);
134
135static gboolean gtk_link_button_activate_link (GtkLinkButton *link_button);
136
137static const char *link_drop_types[] = {
138 "text/uri-list",
139 "_NETSCAPE_URL"
140};
141
142static guint link_signals[LAST_SIGNAL] = { 0, };
143
144G_DEFINE_TYPE (GtkLinkButton, gtk_link_button, GTK_TYPE_BUTTON)
145
146static void
147gtk_link_button_activate_clipboard_copy (GtkWidget *widget,
148 const char *name,
149 GVariant *parameter)
150{
151 GtkLinkButton *link_button = GTK_LINK_BUTTON (widget);
152
153 gdk_clipboard_set_text (clipboard: gtk_widget_get_clipboard (widget), text: link_button->uri);
154}
155
156static void
157gtk_link_button_class_init (GtkLinkButtonClass *klass)
158{
159 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
160 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
161 GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
162
163 gobject_class->set_property = gtk_link_button_set_property;
164 gobject_class->get_property = gtk_link_button_get_property;
165 gobject_class->finalize = gtk_link_button_finalize;
166
167 button_class->clicked = gtk_link_button_clicked;
168
169 klass->activate_link = gtk_link_button_activate_link;
170
171 /**
172 * GtkLinkButton:uri: (attributes org.gtk.Property.get=gtk_link_button_get_uri org.gtk.Property.set=gtk_link_button_set_uri)
173 *
174 * The URI bound to this button.
175 */
176 g_object_class_install_property (oclass: gobject_class,
177 property_id: PROP_URI,
178 pspec: g_param_spec_string (name: "uri",
179 P_("URI"),
180 P_("The URI bound to this button"),
181 NULL,
182 GTK_PARAM_READWRITE));
183
184 /**
185 * GtkLinkButton:visited: (attributes org.gtk.Property.get=gtk_link_button_get_visited org.gtk.Property.set=gtk_link_button_set_visited)
186 *
187 * The 'visited' state of this button.
188 *
189 * A visited link is drawn in a different color.
190 */
191 g_object_class_install_property (oclass: gobject_class,
192 property_id: PROP_VISITED,
193 pspec: g_param_spec_boolean (name: "visited",
194 P_("Visited"),
195 P_("Whether this link has been visited."),
196 FALSE,
197 GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
198
199 /**
200 * GtkLinkButton::activate-link:
201 * @button: the `GtkLinkButton` that emitted the signal
202 *
203 * Emitted each time the `GtkLinkButton` is clicked.
204 *
205 * The default handler will call [func@Gtk.show_uri] with the URI
206 * stored inside the [property@Gtk.LinkButton:uri] property.
207 *
208 * To override the default behavior, you can connect to the
209 * ::activate-link signal and stop the propagation of the signal
210 * by returning %TRUE from your handler.
211 *
212 * Returns: %TRUE if the signal has been handled
213 */
214 link_signals[ACTIVATE_LINK] =
215 g_signal_new (I_("activate-link"),
216 G_TYPE_FROM_CLASS (klass),
217 signal_flags: G_SIGNAL_RUN_LAST,
218 G_STRUCT_OFFSET (GtkLinkButtonClass, activate_link),
219 accumulator: _gtk_boolean_handled_accumulator, NULL,
220 c_marshaller: _gtk_marshal_BOOLEAN__VOID,
221 G_TYPE_BOOLEAN, n_params: 0);
222
223 gtk_widget_class_set_css_name (widget_class, I_("button"));
224 gtk_widget_class_set_accessible_role (widget_class, accessible_role: GTK_ACCESSIBLE_ROLE_LINK);
225
226 /**
227 * GtkLinkButton|clipboard.copy:
228 *
229 * Copies the url to the clipboard.
230 */
231 gtk_widget_class_install_action (widget_class, action_name: "clipboard.copy", NULL,
232 activate: gtk_link_button_activate_clipboard_copy);
233
234 /**
235 * GtkLinkButton|menu.popup:
236 *
237 * Opens the context menu.
238 */
239 gtk_widget_class_install_action (widget_class, action_name: "menu.popup", NULL, activate: gtk_link_button_popup_menu);
240
241 gtk_widget_class_add_binding_action (widget_class,
242 GDK_KEY_F10, mods: GDK_SHIFT_MASK,
243 action_name: "menu.popup",
244 NULL);
245 gtk_widget_class_add_binding_action (widget_class,
246 GDK_KEY_Menu, mods: 0,
247 action_name: "menu.popup",
248 NULL);
249}
250
251static GMenuModel *
252gtk_link_button_get_menu_model (void)
253{
254 GMenu *menu, *section;
255
256 menu = g_menu_new ();
257
258 section = g_menu_new ();
259 g_menu_append (menu: section, _("_Copy URL"), detailed_action: "clipboard.copy");
260 g_menu_append_section (menu, NULL, G_MENU_MODEL (section));
261 g_object_unref (object: section);
262
263 return G_MENU_MODEL (menu);
264}
265
266#define GTK_TYPE_LINK_CONTENT (gtk_link_content_get_type ())
267#define GTK_LINK_CONTENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_LINK_CONTENT, GtkLinkContent))
268
269typedef struct _GtkLinkContent GtkLinkContent;
270typedef struct _GtkLinkContentClass GtkLinkContentClass;
271
272struct _GtkLinkContent
273{
274 GdkContentProvider parent;
275 GtkLinkButton *link;
276};
277
278struct _GtkLinkContentClass
279{
280 GdkContentProviderClass parent_class;
281};
282
283GType gtk_link_content_get_type (void) G_GNUC_CONST;
284
285G_DEFINE_TYPE (GtkLinkContent, gtk_link_content, GDK_TYPE_CONTENT_PROVIDER)
286
287static GdkContentFormats *
288gtk_link_content_ref_formats (GdkContentProvider *provider)
289{
290 GtkLinkContent *content = GTK_LINK_CONTENT (provider);
291
292 if (content->link)
293 return gdk_content_formats_union (first: gdk_content_formats_new_for_gtype (G_TYPE_STRING),
294 second: gdk_content_formats_new (mime_types: link_drop_types, G_N_ELEMENTS (link_drop_types)));
295 else
296 return gdk_content_formats_new (NULL, n_mime_types: 0);
297}
298
299static gboolean
300gtk_link_content_get_value (GdkContentProvider *provider,
301 GValue *value,
302 GError **error)
303{
304 GtkLinkContent *content = GTK_LINK_CONTENT (provider);
305
306 if (G_VALUE_HOLDS (value, G_TYPE_STRING) &&
307 content->link != NULL)
308 {
309 char *uri;
310
311 uri = g_strdup_printf (format: "%s\r\n", content->link->uri);
312 g_value_set_string (value, v_string: uri);
313 g_free (mem: uri);
314
315 return TRUE;
316 }
317
318 return GDK_CONTENT_PROVIDER_CLASS (gtk_link_content_parent_class)->get_value (provider, value, error);
319}
320
321static void
322gtk_link_content_class_init (GtkLinkContentClass *class)
323{
324 GdkContentProviderClass *provider_class = GDK_CONTENT_PROVIDER_CLASS (class);
325
326 provider_class->ref_formats = gtk_link_content_ref_formats;
327 provider_class->get_value = gtk_link_content_get_value;
328}
329
330static void
331gtk_link_content_init (GtkLinkContent *content)
332{
333}
334
335static void
336gtk_link_button_init (GtkLinkButton *link_button)
337{
338 GtkGesture *gesture;
339 GdkContentProvider *content;
340 GtkDragSource *source;
341
342 gtk_button_set_has_frame (GTK_BUTTON (link_button), FALSE);
343 gtk_widget_set_state_flags (GTK_WIDGET (link_button), flags: GTK_STATE_FLAG_LINK, FALSE);
344 gtk_widget_set_has_tooltip (GTK_WIDGET (link_button), TRUE);
345
346 g_signal_connect (link_button, "query-tooltip",
347 G_CALLBACK (gtk_link_button_query_tooltip_cb), NULL);
348
349 source = gtk_drag_source_new ();
350 content = g_object_new (GTK_TYPE_LINK_CONTENT, NULL);
351 GTK_LINK_CONTENT (content)->link = link_button;
352 gtk_drag_source_set_content (source, content);
353 g_object_unref (object: content);
354 gtk_widget_add_controller (GTK_WIDGET (link_button), GTK_EVENT_CONTROLLER (source));
355
356 gesture = gtk_gesture_click_new ();
357 gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), FALSE);
358 gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), button: 0);
359 gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (gesture), phase: GTK_PHASE_BUBBLE);
360 g_signal_connect (gesture, "pressed", G_CALLBACK (gtk_link_button_pressed_cb),
361 link_button);
362 gtk_widget_add_controller (GTK_WIDGET (link_button), GTK_EVENT_CONTROLLER (gesture));
363
364 gtk_widget_add_css_class (GTK_WIDGET (link_button), css_class: "link");
365
366 gtk_widget_set_cursor_from_name (GTK_WIDGET (link_button), name: "pointer");
367}
368
369static void
370gtk_link_button_finalize (GObject *object)
371{
372 GtkLinkButton *link_button = GTK_LINK_BUTTON (object);
373
374 g_free (mem: link_button->uri);
375
376 g_clear_pointer (&link_button->popup_menu, gtk_widget_unparent);
377
378 G_OBJECT_CLASS (gtk_link_button_parent_class)->finalize (object);
379}
380
381static void
382gtk_link_button_get_property (GObject *object,
383 guint prop_id,
384 GValue *value,
385 GParamSpec *pspec)
386{
387 GtkLinkButton *link_button = GTK_LINK_BUTTON (object);
388
389 switch (prop_id)
390 {
391 case PROP_URI:
392 g_value_set_string (value, v_string: link_button->uri);
393 break;
394 case PROP_VISITED:
395 g_value_set_boolean (value, v_boolean: link_button->visited);
396 break;
397 default:
398 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
399 break;
400 }
401}
402
403static void
404gtk_link_button_set_property (GObject *object,
405 guint prop_id,
406 const GValue *value,
407 GParamSpec *pspec)
408{
409 GtkLinkButton *link_button = GTK_LINK_BUTTON (object);
410
411 switch (prop_id)
412 {
413 case PROP_URI:
414 gtk_link_button_set_uri (link_button, uri: g_value_get_string (value));
415 break;
416 case PROP_VISITED:
417 gtk_link_button_set_visited (link_button, visited: g_value_get_boolean (value));
418 break;
419 default:
420 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
421 break;
422 }
423}
424
425static void
426gtk_link_button_do_popup (GtkLinkButton *link_button,
427 double x,
428 double y)
429{
430 if (!link_button->popup_menu)
431 {
432 GMenuModel *model;
433
434 model = gtk_link_button_get_menu_model ();
435 link_button->popup_menu = gtk_popover_menu_new_from_model (model);
436 gtk_widget_set_parent (widget: link_button->popup_menu, GTK_WIDGET (link_button));
437 gtk_popover_set_position (GTK_POPOVER (link_button->popup_menu), position: GTK_POS_BOTTOM);
438
439 gtk_popover_set_has_arrow (GTK_POPOVER (link_button->popup_menu), FALSE);
440 gtk_widget_set_halign (widget: link_button->popup_menu, align: GTK_ALIGN_START);
441
442 g_object_unref (object: model);
443 }
444
445 if (x != -1 && y != -1)
446 {
447 GdkRectangle rect = { x, y, 1, 1 };
448 gtk_popover_set_pointing_to (GTK_POPOVER (link_button->popup_menu), rect: &rect);
449 }
450 else
451 gtk_popover_set_pointing_to (GTK_POPOVER (link_button->popup_menu), NULL);
452
453 gtk_popover_popup (GTK_POPOVER (link_button->popup_menu));
454}
455
456static void
457gtk_link_button_pressed_cb (GtkGestureClick *gesture,
458 int n_press,
459 double x,
460 double y,
461 gpointer user_data)
462{
463 GtkLinkButton *link_button = user_data;
464 GdkEventSequence *sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
465 GdkEvent *event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
466
467 if (!gtk_widget_has_focus (GTK_WIDGET (link_button)))
468 gtk_widget_grab_focus (GTK_WIDGET (link_button));
469
470 if (gdk_event_triggers_context_menu (event) &&
471 link_button->uri != NULL)
472 {
473 gtk_link_button_do_popup (link_button, x, y);
474 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_CLAIMED);
475 }
476 else
477 {
478 gtk_gesture_set_state (GTK_GESTURE (gesture), state: GTK_EVENT_SEQUENCE_DENIED);
479 }
480}
481
482static gboolean
483gtk_link_button_activate_link (GtkLinkButton *link_button)
484{
485 GtkWidget *toplevel;
486
487 toplevel = GTK_WIDGET (gtk_widget_get_root (GTK_WIDGET (link_button)));
488
489 gtk_show_uri (GTK_WINDOW (toplevel), uri: link_button->uri, GDK_CURRENT_TIME);
490 gtk_link_button_set_visited (link_button, TRUE);
491
492 return TRUE;
493}
494
495static void
496gtk_link_button_clicked (GtkButton *button)
497{
498 gboolean retval = FALSE;
499
500 g_signal_emit (instance: button, signal_id: link_signals[ACTIVATE_LINK], detail: 0, &retval);
501}
502
503static void
504gtk_link_button_popup_menu (GtkWidget *widget,
505 const char *action_name,
506 GVariant *parameters)
507{
508 gtk_link_button_do_popup (GTK_LINK_BUTTON (widget), x: -1, y: -1);
509}
510
511/**
512 * gtk_link_button_new:
513 * @uri: a valid URI
514 *
515 * Creates a new `GtkLinkButton` with the URI as its text.
516 *
517 * Returns: a new link button widget.
518 */
519GtkWidget *
520gtk_link_button_new (const char *uri)
521{
522 char *utf8_uri = NULL;
523 GtkWidget *retval;
524
525 g_return_val_if_fail (uri != NULL, NULL);
526
527 if (g_utf8_validate (str: uri, max_len: -1, NULL))
528 {
529 utf8_uri = g_strdup (str: uri);
530 }
531 else
532 {
533 GError *conv_err = NULL;
534
535 utf8_uri = g_locale_to_utf8 (opsysstring: uri, len: -1, NULL, NULL, error: &conv_err);
536 if (conv_err)
537 {
538 g_warning ("Attempting to convert URI '%s' to UTF-8, but failed "
539 "with error: %s",
540 uri,
541 conv_err->message);
542 g_error_free (error: conv_err);
543
544 utf8_uri = g_strdup (_("Invalid URI"));
545 }
546 }
547
548 retval = g_object_new (GTK_TYPE_LINK_BUTTON,
549 first_property_name: "label", utf8_uri,
550 "uri", uri,
551 NULL);
552
553 g_free (mem: utf8_uri);
554
555 return retval;
556}
557
558/**
559 * gtk_link_button_new_with_label:
560 * @uri: a valid URI
561 * @label: (nullable): the text of the button
562 *
563 * Creates a new `GtkLinkButton` containing a label.
564 *
565 * Returns: (transfer none): a new link button widget.
566 */
567GtkWidget *
568gtk_link_button_new_with_label (const char *uri,
569 const char *label)
570{
571 GtkWidget *retval;
572
573 g_return_val_if_fail (uri != NULL, NULL);
574
575 if (!label)
576 return gtk_link_button_new (uri);
577
578 retval = g_object_new (GTK_TYPE_LINK_BUTTON,
579 first_property_name: "label", label,
580 "uri", uri,
581 NULL);
582
583 return retval;
584}
585
586static gboolean
587gtk_link_button_query_tooltip_cb (GtkWidget *widget,
588 int x,
589 int y,
590 gboolean keyboard_tip,
591 GtkTooltip *tooltip,
592 gpointer data)
593{
594 GtkLinkButton *link_button = GTK_LINK_BUTTON (widget);
595 const char *label, *uri;
596 const char *text, *markup;
597
598 label = gtk_button_get_label (GTK_BUTTON (link_button));
599 uri = link_button->uri;
600 text = gtk_widget_get_tooltip_text (widget);
601 markup = gtk_widget_get_tooltip_markup (widget);
602
603 if (text == NULL &&
604 markup == NULL &&
605 label && *label != '\0' && uri && strcmp (s1: label, s2: uri) != 0)
606 {
607 gtk_tooltip_set_text (tooltip, text: uri);
608 return TRUE;
609 }
610
611 return FALSE;
612}
613
614/**
615 * gtk_link_button_set_uri: (attributes org.gtk.Method.set_property=uri)
616 * @link_button: a `GtkLinkButton`
617 * @uri: a valid URI
618 *
619 * Sets @uri as the URI where the `GtkLinkButton` points.
620 *
621 * As a side-effect this unsets the “visited” state of the button.
622 */
623void
624gtk_link_button_set_uri (GtkLinkButton *link_button,
625 const char *uri)
626{
627 g_return_if_fail (GTK_IS_LINK_BUTTON (link_button));
628 g_return_if_fail (uri != NULL);
629
630 g_free (mem: link_button->uri);
631 link_button->uri = g_strdup (str: uri);
632
633 g_object_notify (G_OBJECT (link_button), property_name: "uri");
634
635 gtk_link_button_set_visited (link_button, FALSE);
636}
637
638/**
639 * gtk_link_button_get_uri: (attributes org.gtk.Method.get_property=uri)
640 * @link_button: a `GtkLinkButton`
641 *
642 * Retrieves the URI of the `GtkLinkButton`.
643 *
644 * Returns: a valid URI. The returned string is owned by the link button
645 * and should not be modified or freed.
646 */
647const char *
648gtk_link_button_get_uri (GtkLinkButton *link_button)
649{
650 g_return_val_if_fail (GTK_IS_LINK_BUTTON (link_button), NULL);
651
652 return link_button->uri;
653}
654
655/**
656 * gtk_link_button_set_visited: (attributes org.gtk.Method.set_property=visited)
657 * @link_button: a `GtkLinkButton`
658 * @visited: the new “visited” state
659 *
660 * Sets the “visited” state of the `GtkLinkButton`.
661 *
662 * See [method@Gtk.LinkButton.get_visited] for more details.
663 */
664void
665gtk_link_button_set_visited (GtkLinkButton *link_button,
666 gboolean visited)
667{
668 g_return_if_fail (GTK_IS_LINK_BUTTON (link_button));
669
670 visited = visited != FALSE;
671
672 if (link_button->visited != visited)
673 {
674 link_button->visited = visited;
675
676 if (visited)
677 {
678 gtk_widget_unset_state_flags (GTK_WIDGET (link_button), flags: GTK_STATE_FLAG_LINK);
679 gtk_widget_set_state_flags (GTK_WIDGET (link_button), flags: GTK_STATE_FLAG_VISITED, FALSE);
680 }
681 else
682 {
683 gtk_widget_unset_state_flags (GTK_WIDGET (link_button), flags: GTK_STATE_FLAG_VISITED);
684 gtk_widget_set_state_flags (GTK_WIDGET (link_button), flags: GTK_STATE_FLAG_LINK, FALSE);
685 }
686
687 g_object_notify (G_OBJECT (link_button), property_name: "visited");
688 }
689}
690
691/**
692 * gtk_link_button_get_visited: (attributes org.gtk.Method.get_property=visited)
693 * @link_button: a `GtkLinkButton`
694 *
695 * Retrieves the “visited” state of the `GtkLinkButton`.
696 *
697 * The button becomes visited when it is clicked. If the URI
698 * is changed on the button, the “visited” state is unset again.
699 *
700 * The state may also be changed using [method@Gtk.LinkButton.set_visited].
701 *
702 * Returns: %TRUE if the link has been visited, %FALSE otherwise
703 */
704gboolean
705gtk_link_button_get_visited (GtkLinkButton *link_button)
706{
707 g_return_val_if_fail (GTK_IS_LINK_BUTTON (link_button), FALSE);
708
709 return link_button->visited;
710}
711

source code of gtk/gtk/gtklinkbutton.c