1 /* GTK+ - accessibility implementations
2  * Copyright 2011 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #include "config.h"
19 
20 #include <gtk/gtk.h>
21 #include "gtklinkbuttonaccessible.h"
22 
23 typedef struct _GtkLinkButtonAccessibleLink GtkLinkButtonAccessibleLink;
24 typedef struct _GtkLinkButtonAccessibleLinkClass GtkLinkButtonAccessibleLinkClass;
25 
26 struct _GtkLinkButtonAccessiblePrivate
27 {
28   AtkHyperlink *link;
29 };
30 
31 struct _GtkLinkButtonAccessibleLink
32 {
33   AtkHyperlink parent;
34 
35   GtkLinkButtonAccessible *button;
36 };
37 
38 struct _GtkLinkButtonAccessibleLinkClass
39 {
40   AtkHyperlinkClass parent_class;
41 };
42 
43 static void atk_action_interface_init (AtkActionIface *iface);
44 
45 GType _gtk_link_button_accessible_link_get_type (void);
46 
G_DEFINE_TYPE_WITH_CODE(GtkLinkButtonAccessibleLink,_gtk_link_button_accessible_link,ATK_TYPE_HYPERLINK,G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION,atk_action_interface_init))47 G_DEFINE_TYPE_WITH_CODE (GtkLinkButtonAccessibleLink, _gtk_link_button_accessible_link, ATK_TYPE_HYPERLINK,
48                          G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init))
49 
50 static AtkHyperlink *
51 gtk_link_button_accessible_link_new (GtkLinkButtonAccessible *button)
52 {
53   GtkLinkButtonAccessibleLink *l;
54 
55   l = g_object_new (_gtk_link_button_accessible_link_get_type (), NULL);
56   l->button = button;
57 
58   return ATK_HYPERLINK (l);
59 }
60 
61 static gchar *
gtk_link_button_accessible_link_get_uri(AtkHyperlink * atk_link,gint i)62 gtk_link_button_accessible_link_get_uri (AtkHyperlink *atk_link,
63                                          gint          i)
64 {
65   GtkLinkButtonAccessibleLink *l = (GtkLinkButtonAccessibleLink *)atk_link;
66   GtkWidget *widget;
67   const gchar *uri;
68 
69   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (l->button));
70   uri = gtk_link_button_get_uri (GTK_LINK_BUTTON (widget));
71 
72   return g_strdup (uri);
73 }
74 
75 static gint
gtk_link_button_accessible_link_get_n_anchors(AtkHyperlink * atk_link)76 gtk_link_button_accessible_link_get_n_anchors (AtkHyperlink *atk_link)
77 {
78   return 1;
79 }
80 
81 static gboolean
gtk_link_button_accessible_link_is_valid(AtkHyperlink * atk_link)82 gtk_link_button_accessible_link_is_valid (AtkHyperlink *atk_link)
83 {
84   return TRUE;
85 }
86 
87 static AtkObject *
gtk_link_button_accessible_link_get_object(AtkHyperlink * atk_link,gint i)88 gtk_link_button_accessible_link_get_object (AtkHyperlink *atk_link,
89                                             gint          i)
90 {
91   GtkLinkButtonAccessibleLink *l = (GtkLinkButtonAccessibleLink *)atk_link;
92 
93   return ATK_OBJECT (l->button);
94 }
95 
96 static void
_gtk_link_button_accessible_link_init(GtkLinkButtonAccessibleLink * l)97 _gtk_link_button_accessible_link_init (GtkLinkButtonAccessibleLink *l)
98 {
99 }
100 
101 static void
_gtk_link_button_accessible_link_class_init(GtkLinkButtonAccessibleLinkClass * class)102 _gtk_link_button_accessible_link_class_init (GtkLinkButtonAccessibleLinkClass *class)
103 {
104   AtkHyperlinkClass *atk_link_class = ATK_HYPERLINK_CLASS (class);
105 
106   atk_link_class->get_uri = gtk_link_button_accessible_link_get_uri;
107   atk_link_class->get_n_anchors = gtk_link_button_accessible_link_get_n_anchors;
108   atk_link_class->is_valid = gtk_link_button_accessible_link_is_valid;
109   atk_link_class->get_object = gtk_link_button_accessible_link_get_object;
110 }
111 
112 static gboolean
gtk_link_button_accessible_link_do_action(AtkAction * action,gint i)113 gtk_link_button_accessible_link_do_action (AtkAction *action,
114                                            gint       i)
115 {
116   GtkLinkButtonAccessibleLink *l = (GtkLinkButtonAccessibleLink *)action;
117   GtkWidget *widget;
118 
119   widget = GTK_WIDGET (l->button);
120   if (widget == NULL)
121     return FALSE;
122 
123   if (i != 0)
124     return FALSE;
125 
126   if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_visible (widget))
127     return FALSE;
128 
129   gtk_button_clicked (GTK_BUTTON (widget));
130 
131   return TRUE;
132 }
133 
134 static gint
gtk_link_button_accessible_link_get_n_actions(AtkAction * action)135 gtk_link_button_accessible_link_get_n_actions (AtkAction *action)
136 {
137   return 1;
138 }
139 
140 static const gchar *
gtk_link_button_accessible_link_get_name(AtkAction * action,gint i)141 gtk_link_button_accessible_link_get_name (AtkAction *action,
142                                           gint       i)
143 {
144   if (i != 0)
145     return NULL;
146 
147   return "activate";
148 }
149 
150 static void
atk_action_interface_init(AtkActionIface * iface)151 atk_action_interface_init (AtkActionIface *iface)
152 {
153   iface->do_action = gtk_link_button_accessible_link_do_action;
154   iface->get_n_actions = gtk_link_button_accessible_link_get_n_actions;
155   iface->get_name = gtk_link_button_accessible_link_get_name;
156 }
157 
158 static gboolean
activate_link(GtkLinkButton * button,AtkHyperlink * atk_link)159 activate_link (GtkLinkButton *button,
160                AtkHyperlink  *atk_link)
161 {
162   g_signal_emit_by_name (atk_link, "link-activated");
163 
164   return FALSE;
165 }
166 
167 static AtkHyperlink *
gtk_link_button_accessible_get_hyperlink(AtkHyperlinkImpl * impl)168 gtk_link_button_accessible_get_hyperlink (AtkHyperlinkImpl *impl)
169 {
170   GtkLinkButtonAccessible *button = GTK_LINK_BUTTON_ACCESSIBLE (impl);
171 
172   if (!button->priv->link)
173     {
174       button->priv->link = gtk_link_button_accessible_link_new (button);
175       g_signal_connect (gtk_accessible_get_widget (GTK_ACCESSIBLE (button)),
176                         "activate-link", G_CALLBACK (activate_link), button->priv->link);
177     }
178 
179   return g_object_ref (button->priv->link);
180 }
181 
182 static void atk_hypertext_impl_interface_init (AtkHyperlinkImplIface *iface);
183 
G_DEFINE_TYPE_WITH_CODE(GtkLinkButtonAccessible,gtk_link_button_accessible,GTK_TYPE_BUTTON_ACCESSIBLE,G_ADD_PRIVATE (GtkLinkButtonAccessible)G_IMPLEMENT_INTERFACE (ATK_TYPE_HYPERLINK_IMPL,atk_hypertext_impl_interface_init))184 G_DEFINE_TYPE_WITH_CODE (GtkLinkButtonAccessible, gtk_link_button_accessible, GTK_TYPE_BUTTON_ACCESSIBLE,
185                          G_ADD_PRIVATE (GtkLinkButtonAccessible)
186                          G_IMPLEMENT_INTERFACE (ATK_TYPE_HYPERLINK_IMPL, atk_hypertext_impl_interface_init))
187 
188 static void
189 gtk_link_button_accessible_init (GtkLinkButtonAccessible *button)
190 {
191   button->priv = gtk_link_button_accessible_get_instance_private (button);
192 }
193 
194 static void
gtk_link_button_accessible_finalize(GObject * object)195 gtk_link_button_accessible_finalize (GObject *object)
196 {
197   GtkLinkButtonAccessible *button = GTK_LINK_BUTTON_ACCESSIBLE (object);
198 
199   if (button->priv->link)
200     g_object_unref (button->priv->link);
201 
202   G_OBJECT_CLASS (gtk_link_button_accessible_parent_class)->finalize (object);
203 }
204 
205 static AtkStateSet *
gtk_link_button_ref_state_set(AtkObject * accessible)206 gtk_link_button_ref_state_set (AtkObject *accessible)
207 {
208   AtkStateSet *state_set;
209   GtkWidget *widget;
210 
211   state_set = ATK_OBJECT_CLASS (gtk_link_button_accessible_parent_class)->ref_state_set (accessible);
212 
213   widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible));
214   if (widget != NULL)
215     {
216       if (gtk_link_button_get_visited (GTK_LINK_BUTTON (widget)))
217         atk_state_set_add_state (state_set, ATK_STATE_VISITED);
218     }
219 
220   return state_set;
221 }
222 
223 static void
gtk_link_button_accessible_class_init(GtkLinkButtonAccessibleClass * klass)224 gtk_link_button_accessible_class_init (GtkLinkButtonAccessibleClass *klass)
225 {
226   G_OBJECT_CLASS (klass)->finalize = gtk_link_button_accessible_finalize;
227   ATK_OBJECT_CLASS (klass)->ref_state_set = gtk_link_button_ref_state_set;
228 }
229 
230 static void
atk_hypertext_impl_interface_init(AtkHyperlinkImplIface * iface)231 atk_hypertext_impl_interface_init (AtkHyperlinkImplIface *iface)
232 {
233   iface->get_hyperlink = gtk_link_button_accessible_get_hyperlink;
234 }
235