[gnome-shell] StWidgetAccessible: accessibility support for StWidget
- From: Alejandro Piñeiro Iglesias <apinheiro src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] StWidgetAccessible: accessibility support for StWidget
- Date: Thu, 20 Jan 2011 14:50:19 +0000 (UTC)
commit 125adb4d3215b29bbeea84cecbf1842f0423d063
Author: Alejandro Piñeiro <apinheiro igalia com>
Date: Tue Jan 4 13:14:15 2011 +0100
StWidgetAccessible: accessibility support for StWidget
It includes:
* Expose a proper focusable state, instead of the default one from
cally, using StWidget::can_focus, and also notifying the state change
* Management of the selected stated, using the current pseudo_class.
* Defines a new virtual method on StWidget: get_accessible_type. In
this way it is not required to reimplement get_accessible just for
a accessible type change. get_accessible is reimplemented using this.
You can see that as a substitute of the atk object factory
https://bugzilla.gnome.org/show_bug.cgi?id=636716
src/Makefile-st.am | 1 +
src/st/st-widget-accessible.h | 76 +++++++++++++++
src/st/st-widget.c | 205 +++++++++++++++++++++++++++++++++++++++++
src/st/st-widget.h | 2 +
4 files changed, 284 insertions(+), 0 deletions(-)
---
diff --git a/src/Makefile-st.am b/src/Makefile-st.am
index e952a4a..225ff5b 100644
--- a/src/Makefile-st.am
+++ b/src/Makefile-st.am
@@ -98,6 +98,7 @@ st_source_h = \
st/st-tooltip.h \
st/st-types.h \
st/st-widget.h \
+ st/st-widget-accessible.h \
$(NULL)
st.h: stamp-st.h
diff --git a/src/st/st-widget-accessible.h b/src/st/st-widget-accessible.h
new file mode 100644
index 0000000..c60f778
--- /dev/null
+++ b/src/st/st-widget-accessible.h
@@ -0,0 +1,76 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
+/*
+ * st-widget-accessible.h: Accessible object for StWidget
+ *
+ * Copyright 2010 Igalia, S.L.
+ * Author: Alejandro Piñeiro Iglesias <apinheiro igalia com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU Lesser General Public License,
+ * version 2.1, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined(ST_H_INSIDE) && !defined(ST_COMPILATION)
+#error "Only <st/st.h> can be included directly.h"
+#endif
+
+#ifndef __ST_WIDGET_ACCESSIBLE_H__
+#define __ST_WIDGET_ACCESSIBLE_H__
+
+G_BEGIN_DECLS
+
+#include <st/st-widget.h>
+#include <cally/cally.h>
+
+#define ST_TYPE_WIDGET_ACCESSIBLE st_widget_accessible_get_type ()
+
+#define ST_WIDGET_ACCESSIBLE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ ST_TYPE_WIDGET_ACCESSIBLE, StWidgetAccessible))
+
+#define ST_IS_WIDGET_ACCESSIBLE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ ST_TYPE_WIDGET_ACCESSIBLE))
+
+#define ST_WIDGET_ACCESSIBLE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST ((klass), \
+ ST_TYPE_WIDGET_ACCESSIBLE, StWidgetAccessibleClass))
+
+#define ST_IS_WIDGET_ACCESSIBLE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+ ST_TYPE_WIDGET_ACCESSIBLE))
+
+#define ST_WIDGET_ACCESSIBLE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ ST_TYPE_WIDGET_ACCESSIBLE, StWidgetAccessibleClass))
+
+typedef struct _StWidgetAccessible StWidgetAccessible;
+typedef struct _StWidgetAccessibleClass StWidgetAccessibleClass;
+typedef struct _StWidgetAccessiblePrivate StWidgetAccessiblePrivate;
+
+struct _StWidgetAccessible
+{
+ CallyActor parent;
+
+ /*< private >*/
+ StWidgetAccessiblePrivate *priv;
+};
+
+struct _StWidgetAccessibleClass
+{
+ CallyActorClass parent_class;
+};
+
+GType st_widget_accessible_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __ST_WIDGET_ACCESSIBLE_H__ */
diff --git a/src/st/st-widget.c b/src/st/st-widget.c
index 23b591d..8ebe1dd 100644
--- a/src/st/st-widget.c
+++ b/src/st/st-widget.c
@@ -42,6 +42,8 @@
#include "st-tooltip.h"
#include "st-theme-node-transition.h"
+#include "st-widget-accessible.h"
+
/*
* Forward declaration for sake of StWidgetChild
*/
@@ -67,6 +69,8 @@ struct _StWidgetPrivate
StTooltip *tooltip;
StTextDirection direction;
+
+ AtkObject *accessible;
};
/**
@@ -117,6 +121,8 @@ static gboolean st_widget_real_navigate_focus (StWidget *widget,
ClutterActor *from,
GtkDirectionType direction);
+static AtkObject * st_widget_get_accessible (ClutterActor *actor);
+
static void
st_widget_set_property (GObject *gobject,
guint prop_id,
@@ -281,6 +287,12 @@ st_widget_dispose (GObject *gobject)
priv->tooltip = NULL;
}
+ /* The real dispose of this accessible is done on
+ * AtkGObjectAccessible weak ref callback
+ */
+ if (priv->accessible)
+ priv->accessible = NULL;
+
G_OBJECT_CLASS (st_widget_parent_class)->dispose (gobject);
}
@@ -725,8 +737,11 @@ st_widget_class_init (StWidgetClass *klass)
actor_class->key_focus_out = st_widget_key_focus_out;
actor_class->hide = st_widget_hide;
+ actor_class->get_accessible = st_widget_get_accessible;
+
klass->style_changed = st_widget_real_style_changed;
klass->navigate_focus = st_widget_real_navigate_focus;
+ klass->get_accessible_type = st_widget_accessible_get_type;
/**
* StWidget:pseudo-class:
@@ -1948,3 +1963,193 @@ st_get_slow_down_factor ()
{
return st_slow_down_factor;
}
+
+/******************************************************************************/
+/*************************** ACCESSIBILITY SUPPORT ****************************/
+/******************************************************************************/
+
+/* GObject */
+
+static void st_widget_accessible_class_init (StWidgetAccessibleClass *klass);
+static void st_widget_accessible_init (StWidgetAccessible *widget);
+
+/* AtkObject */
+static AtkStateSet *st_widget_accessible_ref_state_set (AtkObject *obj);
+static void st_widget_accessible_initialize (AtkObject *obj,
+ gpointer data);
+
+/* Private methods */
+static void on_pseudo_class_notify (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer data);
+static void on_can_focus_notify (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer data);
+static void check_selected (StWidgetAccessible *self,
+ StWidget *widget);
+
+G_DEFINE_TYPE (StWidgetAccessible, st_widget_accessible, CALLY_TYPE_ACTOR)
+
+#define ST_WIDGET_ACCESSIBLE_GET_PRIVATE(obj) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_WIDGET_ACCESSIBLE, \
+ StWidgetAccessiblePrivate))
+
+struct _StWidgetAccessiblePrivate
+{
+ /* Cached values (used to avoid extra notifications) */
+ gboolean selected;
+};
+
+
+static AtkObject *
+st_widget_get_accessible (ClutterActor *actor)
+{
+ StWidget *widget = NULL;
+
+ g_return_val_if_fail (ST_IS_WIDGET (actor), NULL);
+
+ widget = ST_WIDGET (actor);
+
+ if (widget->priv->accessible == NULL)
+ {
+ widget->priv->accessible =
+ g_object_new (ST_WIDGET_GET_CLASS (widget)->get_accessible_type (),
+ NULL);
+
+ atk_object_initialize (widget->priv->accessible, actor);
+ }
+
+ return widget->priv->accessible;
+}
+
+
+static void
+st_widget_accessible_class_init (StWidgetAccessibleClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
+
+ atk_class->ref_state_set = st_widget_accessible_ref_state_set;
+ atk_class->initialize = st_widget_accessible_initialize;
+
+ g_type_class_add_private (gobject_class, sizeof (StWidgetAccessiblePrivate));
+}
+
+static void
+st_widget_accessible_init (StWidgetAccessible *self)
+{
+ StWidgetAccessiblePrivate *priv = ST_WIDGET_ACCESSIBLE_GET_PRIVATE (self);
+
+ self->priv = priv;
+}
+
+static void
+st_widget_accessible_initialize (AtkObject *obj,
+ gpointer data)
+{
+ ATK_OBJECT_CLASS (st_widget_accessible_parent_class)->initialize (obj, data);
+
+ g_signal_connect (data, "notify::pseudo-class",
+ G_CALLBACK (on_pseudo_class_notify),
+ obj);
+
+ g_signal_connect (data, "notify::can-focus",
+ G_CALLBACK (on_can_focus_notify),
+ obj);
+
+ /* Check the cached selected state and notify the first selection.
+ * Ie: it is required to ensure a first notification when Alt+Tab
+ * popup appears
+ */
+ check_selected (ST_WIDGET_ACCESSIBLE (obj), ST_WIDGET (data));
+}
+
+static AtkStateSet *
+st_widget_accessible_ref_state_set (AtkObject *obj)
+{
+ AtkStateSet *result = NULL;
+ ClutterActor *actor = NULL;
+ StWidget *widget = NULL;
+ StWidgetAccessible *self = NULL;
+
+ result = ATK_OBJECT_CLASS (st_widget_accessible_parent_class)->ref_state_set (obj);
+
+ actor = CLUTTER_ACTOR (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (obj)));
+
+ if (actor == NULL) /* State is defunct */
+ return result;
+
+ widget = ST_WIDGET (actor);
+ self = ST_WIDGET_ACCESSIBLE (obj);
+
+ /* priv->selected should be properly updated on the
+ * ATK_STATE_SELECTED notification callbacks
+ */
+ if (self->priv->selected)
+ atk_state_set_add_state (result, ATK_STATE_SELECTED);
+
+ /* On clutter there isn't any tip to know if a actor is focusable or
+ * not, anyone can receive the key_focus. For this reason
+ * cally_actor sets any actor as FOCUSABLE. This is not the case on
+ * St, where we have can_focus. But this means that we need to
+ * remove the state FOCUSABLE if it is not focusable
+ */
+ if (st_widget_get_can_focus (widget))
+ atk_state_set_add_state (result, ATK_STATE_FOCUSABLE);
+ else
+ atk_state_set_remove_state (result, ATK_STATE_FOCUSABLE);
+
+ return result;
+}
+
+static void
+on_pseudo_class_notify (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ check_selected (ST_WIDGET_ACCESSIBLE (data),
+ ST_WIDGET (gobject));
+}
+
+/*
+ * This method checks if the widget is selected, and notify a atk
+ * state change if required
+ *
+ * In order to decide if there was a selection, we use the current
+ * pseudo-class of the widget searching for "selected", the current
+ * homogeneus way to check if a item is selected (see bug 637830)
+ *
+ * In a ideal world we would have a more standard way to check if the
+ * item is selected or not, like the widget-context (as in the case of
+ * gtktreeview-cells), or something like the property "can-focus". But
+ * for the moment this is enough, and we can update that in the future
+ * if required.
+ */
+static void
+check_selected (StWidgetAccessible *self,
+ StWidget *widget)
+{
+ gboolean found = FALSE;
+
+ found = st_widget_has_style_pseudo_class (widget,
+ "selected");
+
+ if (found != self->priv->selected)
+ {
+ self->priv->selected = found;
+ atk_object_notify_state_change (ATK_OBJECT (self),
+ ATK_STATE_SELECTED,
+ found);
+ }
+}
+
+static void
+on_can_focus_notify (GObject *gobject,
+ GParamSpec *pspec,
+ gpointer data)
+{
+ gboolean can_focus = st_widget_get_can_focus (ST_WIDGET (gobject));
+
+ atk_object_notify_state_change (ATK_OBJECT (data),
+ ATK_STATE_FOCUSABLE, can_focus);
+}
diff --git a/src/st/st-widget.h b/src/st/st-widget.h
index cc3b47c..8945436 100644
--- a/src/st/st-widget.h
+++ b/src/st/st-widget.h
@@ -82,6 +82,8 @@ struct _StWidgetClass
gboolean (* navigate_focus) (StWidget *self,
ClutterActor *from,
GtkDirectionType direction);
+
+ GType (*get_accessible_type) (void);
};
GType st_widget_get_type (void) G_GNUC_CONST;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]