diff options
| author | Marco Trevisan (Treviño) <mail@3v1n0.net> | 2015-12-17 16:35:11 +0100 |
|---|---|---|
| committer | Marco Trevisan (Treviño) <mail@3v1n0.net> | 2015-12-17 16:35:11 +0100 |
| commit | 9f5548b87d39d29908c16b03e14e5842e7c8b0a9 (patch) | |
| tree | 46d617d2abca2140e325de22fab610f3b51983ed /a11y | |
| parent | c01a01cbeae97ccb1f0a77b6503af8208996e0e1 (diff) | |
a11y: move accessibility stuff to its own directory, adding a private lib for building
(bzr r4054.2.4)
Diffstat (limited to 'a11y')
58 files changed, 9363 insertions, 0 deletions
diff --git a/a11y/CMakeLists.txt b/a11y/CMakeLists.txt new file mode 100644 index 000000000..9a4714d67 --- /dev/null +++ b/a11y/CMakeLists.txt @@ -0,0 +1,48 @@ +pkg_check_modules(A11Y_DEPS REQUIRED atk atk-bridge-2.0) + +set(CFLAGS + ${CACHED_UNITY_DEPS_CFLAGS} + ${CACHED_UNITY_DEPS_CFLAGS_OTHER} + ${PIC_FLAGS} + ${A11Y_DEPS_CFLAGS}) + +include_directories(.. ../unity-shared ../dash ../panel ../launcher ../shutdown ../plugins/unityshell/src ${CMAKE_BINARY_DIR}) + +string(REPLACE ";" " " CFLAGS "${CFLAGS}") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CFLAGS}") +set(LIBS ${CACHED_UNITY_DEPS_LDFLAGS} ${A11Y_DEPS_LDFLAGS}) + +set(A11Y_SOURCES + nux-area-accessible.cpp + nux-base-window-accessible.cpp + nux-layout-accessible.cpp + nux-object-accessible.cpp + nux-text-entry-accessible.cpp + nux-view-accessible.cpp + unity-dash-view-accessible.cpp + unity-expander-view-accessible.cpp + unity-filter-basic-button-accessible.cpp + unity-launcher-accessible.cpp + unity-launcher-icon-accessible.cpp + unity-panel-view-accessible.cpp + unity-places-group-accessible.cpp + unity-quicklist-accessible.cpp + unity-quicklist-menu-accessible.cpp + unity-quicklist-menu-item-accessible.cpp + unity-result-accessible.cpp + unity-root-accessible.cpp + unity-rvgrid-accessible.cpp + unity-scope-bar-icon-accessible.cpp + unity-sctext-accessible.cpp + unity-search-bar-accessible.cpp + unity-session-button-accessible.cpp + unity-switcher-accessible.cpp + unity-text-input-accessible.cpp + unity-util-accessible.cpp + unitya11y.cpp + unitya11ytests.cpp +) + +add_library(a11y-lib STATIC ${A11Y_SOURCES}) +target_link_libraries(a11y-lib ${LIBS}) +add_pch(pch/a11y_pch.hh a11y-lib) diff --git a/a11y/nux-area-accessible.cpp b/a11y/nux-area-accessible.cpp new file mode 100644 index 000000000..bffad5ad3 --- /dev/null +++ b/a11y/nux-area-accessible.cpp @@ -0,0 +1,601 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:nux-area-accessible + * @Title: NuxAreaAccessible + * @short_description: Implementation of the ATK interfaces for #nux::Area + * @see_also: nux::Area + * + * #NuxAreaAccessible implements the required ATK interfaces of + * nux::Area, exposing the common elements on each basic individual + * element (position, extents, etc) + * + * In this object the main support for the focused object is also + * implemented. This is complex due to several reasons: + * + * * We need to ensure the proper order when the objects get the focus + * + * * It doesn't make sense to give the focus to an object that is + * inside an inactive window too, so it is also convenient to emit + * the window:active event before the focus change. + * + * => this is the reason why there is a system to delay the focus + * notification, until the top level window becomes active, implemented + * + * * But the main complexity comes from the fact that not all the + * objects of Unity are implementing key nav the same way. + * + * * The Launcher uses InputArea methods like + * SetKeyboardFocus, OnStartKeyboardReceiver, etc exclusively. + * This is the key focus at a low level abstraction + * + * * Dash objects use the events from Focusable. But in the same + * way, they require the low level key focus (OnStartFocus) and + * so on + * + * + */ + +#include "nux-area-accessible.h" + +#include "unitya11y.h" + +/* GObject */ +static void nux_area_accessible_class_init(NuxAreaAccessibleClass* klass); +static void nux_area_accessible_init(NuxAreaAccessible* area_accessible); + +/* AtkObject.h */ +static void nux_area_accessible_initialize(AtkObject* accessible, + gpointer data); +static AtkObject* nux_area_accessible_get_parent(AtkObject* obj); +static AtkStateSet* nux_area_accessible_ref_state_set(AtkObject* obj); + +/* AtkComponent.h */ +static void atk_component_interface_init(AtkComponentIface* iface); +static void nux_area_accessible_get_extents(AtkComponent* component, + gint* x, + gint* y, + gint* width, + gint* height, + AtkCoordType coord_type); +static gboolean nux_area_accessible_grab_focus(AtkComponent* component); +static guint nux_area_accessible_add_focus_handler(AtkComponent* component, + AtkFocusHandler handler); +static void nux_area_accessible_remove_focus_handler(AtkComponent* component, + guint handler_id); +static void nux_area_accessible_focus_handler(AtkObject* accessible, + gboolean focus_in); +/* private */ +static void on_focus_changed_cb(nux::Area* area, + bool has_focus, + nux::KeyNavDirection direction, + AtkObject* accessible); +static void on_parent_window_activate_cb(AtkObject* parent_window, + NuxAreaAccessible* self); +static void on_parent_window_deactivate_cb(AtkObject* parent_window, + NuxAreaAccessible* self); +static AtkObject* search_for_parent_window(AtkObject* object); +static gboolean nux_area_accessible_real_check_pending_notification(NuxAreaAccessible* self); +static void check_parent_window_connected(NuxAreaAccessible* self); +static void check_focus(NuxAreaAccessible* self); + +G_DEFINE_TYPE_WITH_CODE(NuxAreaAccessible, + nux_area_accessible, + NUX_TYPE_OBJECT_ACCESSIBLE, + G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT, + atk_component_interface_init)) + +#define NUX_AREA_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NUX_TYPE_AREA_ACCESSIBLE, \ + NuxAreaAccessiblePrivate)) + +struct _NuxAreaAccessiblePrivate +{ + /* focused as Focusable events */ + gboolean focused; + + /* if there is any pending notification */ + gboolean pending_notification; + + /* Top level parent window, it is not required to be the direct + parent */ + AtkObject* parent_window; +}; + + +static void +nux_area_accessible_class_init(NuxAreaAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + NuxAreaAccessibleClass* area_class = NUX_AREA_ACCESSIBLE_CLASS(klass); + + /* AtkObject */ + atk_class->initialize = nux_area_accessible_initialize; + atk_class->get_parent = nux_area_accessible_get_parent; + atk_class->ref_state_set = nux_area_accessible_ref_state_set; + + /* NuxAreaAccessible */ + area_class->check_pending_notification = nux_area_accessible_real_check_pending_notification; + + g_type_class_add_private(gobject_class, sizeof(NuxAreaAccessiblePrivate)); +} + +static void +nux_area_accessible_init(NuxAreaAccessible* area_accessible) +{ + NuxAreaAccessiblePrivate* priv = + NUX_AREA_ACCESSIBLE_GET_PRIVATE(area_accessible); + + area_accessible->priv = priv; +} + +AtkObject* +nux_area_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<nux::Area*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(NUX_TYPE_AREA_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +nux_area_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + nux::Area* area = NULL; + + ATK_OBJECT_CLASS(nux_area_accessible_parent_class)->initialize(accessible, data); + + accessible->role = ATK_ROLE_UNKNOWN; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + area = static_cast<nux::Area*>(nux_object); + + /* focus support based on Focusable, used on the Dash */ + area->key_nav_focus_change.connect(sigc::bind(sigc::ptr_fun(on_focus_changed_cb), accessible)); + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + atk_component_add_focus_handler(ATK_COMPONENT(accessible), + nux_area_accessible_focus_handler); +G_GNUC_END_IGNORE_DEPRECATIONS + + /* NOTE: we can't search for the parent window on initialization as a + general rule, or we could enter an infinite loop. At area this + is done on the focus event. On the Switcher this is done on their + initialization itself */ +} + +static AtkObject* +nux_area_accessible_get_parent(AtkObject* obj) +{ + nux::Object* nux_object = NULL; + nux::Area* area = NULL; + nux::Area* parent = NULL; + + g_return_val_if_fail(NUX_IS_AREA_ACCESSIBLE(obj), NULL); + + if (obj->accessible_parent) + return obj->accessible_parent; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + + if (nux_object == NULL) /* defunct */ + return NULL; + + area = static_cast<nux::Area*>(nux_object); + parent = area->GetParentObject(); + + return parent ? unity_a11y_get_accessible(parent) : NULL; +} + +/* + * Checks if the parent actor, and his parent, etc are all visible + * Used to check the showing state + */ +static gboolean +_check_all_parents_visible(nux::Area* area) +{ + nux::Area* iter_parent = NULL; + gboolean result = TRUE; + + for (iter_parent = area; iter_parent; + iter_parent = iter_parent->GetParentObject()) + { + if (!iter_parent->IsVisible()) + { + result = FALSE; + break; + } + } + + return result; +} + +static AtkStateSet* +nux_area_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + nux::Object* nux_object = NULL; + nux::Area* area = NULL; + + g_return_val_if_fail(NUX_IS_AREA_ACCESSIBLE(obj), NULL); + + state_set = ATK_OBJECT_CLASS(nux_area_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + + if (nux_object == NULL) /* defunct */ + return state_set; + + area = static_cast<nux::Area*>(nux_object); + + if (area->IsSensitive()) + { + atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state(state_set, ATK_STATE_ENABLED); + } + + if (area->IsVisible()) + { + atk_state_set_add_state(state_set, ATK_STATE_VISIBLE); + + if (_check_all_parents_visible(area)) + atk_state_set_add_state(state_set, ATK_STATE_SHOWING); + } + + // FIXME CanFocus is no longer part of Nux API +// if (area->CanFocus()) +// atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); + + if (area->HasKeyFocus()) + atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); + + return state_set; +} + +/* AtkComponent implementation */ +static void +atk_component_interface_init(AtkComponentIface* iface) +{ + g_return_if_fail(iface != NULL); + + /* placement */ + iface->get_extents = nux_area_accessible_get_extents; + + /* focus management based on Focusable */ + iface->grab_focus = nux_area_accessible_grab_focus; + iface->add_focus_handler = nux_area_accessible_add_focus_handler; + iface->remove_focus_handler = nux_area_accessible_remove_focus_handler; +} + +static void +nux_area_accessible_get_extents(AtkComponent* component, + gint* x, + gint* y, + gint* width, + gint* height, + AtkCoordType coord_type) +{ + gint top_level_x = 0; + gint top_level_y = 0; + nux::Object* nux_object = NULL; + nux::Area* area = NULL; + nux::Geometry geometry; + + g_return_if_fail(NUX_IS_AREA_ACCESSIBLE(component)); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(component)); + + if (nux_object == NULL) /* defunct */ + return; + + area = static_cast<nux::Area*>(nux_object); + geometry = area->GetGeometry(); + + *width = geometry.GetWidth(); + *height = geometry.GetWidth(); + *x = geometry.x; + *y = geometry.y; + + /* In the ATK_XY_WINDOW case + * + * http://library.gnome.org/devel/atk/stable/AtkUtil.html#AtkCoordType + */ + + if (coord_type == ATK_XY_SCREEN) + { + /* For the moment Unity is a full-screen app, so ATK_XY_SCREEN + and ATK_XY_WINDOW are the same */ + *x += top_level_x; + *y += top_level_y; + } + + return; +} + +static gboolean +nux_area_accessible_grab_focus(AtkComponent* component) +{ + nux::Object* nux_object = NULL; + //nux::Area* area = NULL; + + g_return_val_if_fail(NUX_IS_AREA_ACCESSIBLE(component), FALSE); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(component)); + if (nux_object == NULL) /* defunct */ + return FALSE; + + /* FIXME: SetFocused doesn't return if the force was successful or + not, we suppose that this is the case like in cally and gail */ + + return TRUE; +} + +/* + * comment C&P from cally-actor: + * + * "These methods are basically taken from gail, as I don't see any + * reason to modify it. It makes me wonder why it is really required + * to be implemented in the toolkit" + */ + +static guint +nux_area_accessible_add_focus_handler(AtkComponent* component, + AtkFocusHandler handler) +{ + GSignalMatchType match_type; + gulong ret; + guint signal_id; + + g_return_val_if_fail(NUX_IS_AREA_ACCESSIBLE(component), 0); + + match_type = (GSignalMatchType)(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC); + signal_id = g_signal_lookup("focus-event", ATK_TYPE_OBJECT); + + ret = g_signal_handler_find(component, match_type, signal_id, 0, NULL, + (gpointer) handler, NULL); + if (!ret) + { + return g_signal_connect_closure_by_id(component, + signal_id, 0, + g_cclosure_new(G_CALLBACK(handler), NULL, + (GClosureNotify) NULL), + FALSE); + } + else + return 0; +} + +static void +nux_area_accessible_remove_focus_handler(AtkComponent* component, + guint handler_id) +{ + g_return_if_fail(NUX_IS_AREA_ACCESSIBLE(component)); + + g_signal_handler_disconnect(component, handler_id); +} + +static void +nux_area_accessible_focus_handler(AtkObject* accessible, + gboolean focus_in) +{ + g_return_if_fail(NUX_IS_AREA_ACCESSIBLE(accessible)); + + atk_object_notify_state_change(accessible, ATK_STATE_FOCUSED, focus_in); +} + +/* private */ +static void +check_parent_window_connected(NuxAreaAccessible* self) +{ + AtkObject* window = NULL; + + if (self->priv->parent_window != NULL) + return; + + window = search_for_parent_window(ATK_OBJECT(self)); + + if (window != NULL) + { + self->priv->parent_window = window; + + g_signal_connect(self->priv->parent_window, + "activate", + G_CALLBACK(on_parent_window_activate_cb), + self); + g_signal_connect(self->priv->parent_window, + "deactivate", + G_CALLBACK(on_parent_window_deactivate_cb), + self); + } +} + +/* + * nux_area_accessible_parent_window_active + * @self: The accessible to check the focus change + * + * Returns if the top level parent window contains + * the state ATK_STATE_ACTIVE + * + * Returns: TRUE if the parent top level window contains + * ATK_STATE_ACTIVE, FALSE otherwise + */ +gboolean +nux_area_accessible_parent_window_active(NuxAreaAccessible* self) +{ + AtkStateSet* state_set = NULL; + gboolean active = FALSE; + + check_parent_window_connected(self); + + if (ATK_IS_OBJECT(self->priv->parent_window)) + { + state_set = atk_object_ref_state_set(ATK_OBJECT(self->priv->parent_window)); + active = atk_state_set_contains_state(state_set, ATK_STATE_ACTIVE); + g_object_unref(state_set); + } + + return active; +} + +static void +on_focus_changed_cb(nux::Area* area, + bool has_focus, + nux::KeyNavDirection direction, + AtkObject* accessible) +{ + check_focus(NUX_AREA_ACCESSIBLE(accessible)); +} + +/* Check to use GetTopLevelViewWindow */ +static AtkObject* +search_for_parent_window(AtkObject* object) +{ + AtkObject* parent = NULL; + + for (parent = atk_object_get_parent(object); + (parent != NULL) && (atk_object_get_role(parent) != ATK_ROLE_WINDOW); + parent = atk_object_get_parent(parent)); + + return parent; +} + +static void +on_parent_window_activate_cb(AtkObject* parent_window, + NuxAreaAccessible* self) +{ + nux_area_accessible_check_pending_notification(self); +} + +static void +on_parent_window_deactivate_cb(AtkObject* parent_window, + NuxAreaAccessible* self) +{ + g_return_if_fail(NUX_IS_AREA_ACCESSIBLE(self)); + + self->priv->focused = FALSE; +} + + +/* + * nux_area_check_pending_notification: + * @self: The accessible + * + * This method checks if there is any pending notification, and emits + * it if it is possible + * + * Returns: TRUE if an atk notification was emitted, FALSE otherwise + */ +gboolean +nux_area_accessible_check_pending_notification(NuxAreaAccessible* self) +{ + NuxAreaAccessibleClass* klass = NULL; + + klass = NUX_AREA_ACCESSIBLE_GET_CLASS(self); + if (klass->check_pending_notification) + return klass->check_pending_notification(self); + else + return FALSE; +} + +static gboolean +nux_area_accessible_real_check_pending_notification(NuxAreaAccessible* self) +{ + nux::Object* nux_object = NULL; + + g_return_val_if_fail(NUX_IS_AREA_ACCESSIBLE(self), FALSE); + + if (self->priv->pending_notification == FALSE) + return FALSE; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + if (nux_object == NULL) /* defunct */ + return FALSE; + + g_signal_emit_by_name(self, "focus-event", self->priv->focused); + atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_FOCUSED, self->priv->focused); + self->priv->pending_notification = FALSE; + + return TRUE; +} + +static void +check_focus(NuxAreaAccessible* self) +{ + gboolean focus_in = FALSE; + nux::Area* area = NULL; + nux::Object* nux_object = NULL; + + g_return_if_fail(NUX_IS_AREA_ACCESSIBLE(self)); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + if (nux_object == NULL) /* defunct */ + return; + + area = static_cast<nux::Area*>(nux_object); + + if (nux::GetWindowCompositor().GetKeyFocusArea() == area) + focus_in = TRUE; + + if (self->priv->focused != focus_in) + { + self->priv->focused = focus_in; + gboolean is_parent_window_active = nux_area_accessible_parent_window_active(self); + + /* we don't emit focus_in=TRUE events until the top level window + is active */ + if ((focus_in) && (!is_parent_window_active)) + { + self->priv->pending_notification = TRUE; + } + else + { + g_signal_emit_by_name(self, "focus_event", focus_in); + atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_FOCUSED, focus_in); + self->priv->pending_notification = FALSE; + } + } +} + + +/* public */ +/* + * nux_area_get_parent_window: + * @self: The accessible + * + * Returns: the top level window that contains this object + */ +AtkObject* +nux_area_accessible_get_parent_window(NuxAreaAccessible* self) +{ + g_return_val_if_fail(NUX_IS_AREA_ACCESSIBLE(self), NULL); + + /* At least ensure that we made a search for it */ + check_parent_window_connected(self); + + return self->priv->parent_window; +} diff --git a/a11y/nux-area-accessible.h b/a11y/nux-area-accessible.h new file mode 100644 index 000000000..a5326c63f --- /dev/null +++ b/a11y/nux-area-accessible.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef NUX_AREA_ACCESSIBLE_H +#define NUX_AREA_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-object-accessible.h" + +G_BEGIN_DECLS + +#define NUX_TYPE_AREA_ACCESSIBLE (nux_area_accessible_get_type ()) +#define NUX_AREA_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NUX_TYPE_AREA_ACCESSIBLE, NuxAreaAccessible)) +#define NUX_AREA_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NUX_TYPE_AREA_ACCESSIBLE, NuxAreaAccessibleClass)) +#define NUX_IS_AREA_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NUX_TYPE_AREA_ACCESSIBLE)) +#define NUX_IS_AREA_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NUX_TYPE_AREA_ACCESSIBLE)) +#define NUX_AREA_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NUX_TYPE_AREA_ACCESSIBLE, NuxAreaAccessibleClass)) + +typedef struct _NuxAreaAccessible NuxAreaAccessible; +typedef struct _NuxAreaAccessibleClass NuxAreaAccessibleClass; +typedef struct _NuxAreaAccessiblePrivate NuxAreaAccessiblePrivate; + +struct _NuxAreaAccessible +{ + NuxObjectAccessible parent; + + /*< private >*/ + NuxAreaAccessiblePrivate* priv; +}; + +struct _NuxAreaAccessibleClass +{ + NuxObjectAccessibleClass parent_class; + + /* + * Usually objects shouldn't emit events like focus or selection + * changes until the toplevel window is active. This method is + * called when the toplevel window becomes active. Redefine it if you + * need to check any pending state change notification. + */ + gboolean(*check_pending_notification)(NuxAreaAccessible* self); + +}; + +GType nux_area_accessible_get_type(void); +AtkObject* nux_area_accessible_new(nux::Object* object); + +gboolean nux_area_accessible_check_pending_notification(NuxAreaAccessible* self); +gboolean nux_area_accessible_parent_window_active(NuxAreaAccessible* self); +AtkObject* nux_area_accessible_get_parent_window(NuxAreaAccessible* self); + +G_END_DECLS + +#endif /* __NUX_AREA_ACCESSIBLE_H__ */ diff --git a/a11y/nux-base-window-accessible.cpp b/a11y/nux-base-window-accessible.cpp new file mode 100644 index 000000000..e82b536d7 --- /dev/null +++ b/a11y/nux-base-window-accessible.cpp @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:nux-base_window-accessible + * @Title: NuxBaseWindowAccessible + * @short_description: Implementation of the ATK interfaces for #nux::BaseWindow + * @see_also: nux::BaseWindow + * + * Right now it is used to: + * * Expose the child of BaseWindow (the layout) + * * Window event notification (activate, deactivate, and so on) + * + * BTW: we consider that one window is active, if it directly has + * keyboard focus, or if one of its children has keyboard focus (ie: + * the Launcher via GrabKeyboardFocus) + * + * HasKeyboardFocus is not reliable to check that: + * see bug https://bugs.launchpad.net/nux/+bug/745049 + * + * So we need to update the state of the objects using the information + * from the signals OnStartKeyboardReceiver and OnStopKeyboardReceiver + * + * #NuxBaseWindowAccessible implements the required ATK interfaces of + * nux::BaseWindow, exposing as a child the BaseWindow layout + * + */ + +#include "nux-base-window-accessible.h" + +#include <Nux/Area.h> +#include <Nux/Layout.h> + +/* GObject */ +static void nux_base_window_accessible_class_init(NuxBaseWindowAccessibleClass* klass); +static void nux_base_window_accessible_init(NuxBaseWindowAccessible* base_window_accessible); + +/* AtkObject.h */ +static void nux_base_window_accessible_initialize(AtkObject* accessible, + gpointer data); +static AtkObject* nux_base_window_accessible_get_parent(AtkObject* obj); +static AtkStateSet* nux_base_window_accessible_ref_state_set(AtkObject* obj); + +/* AtkWindow.h */ +static void atk_window_interface_init(AtkWindowIface* iface); + + +G_DEFINE_TYPE_WITH_CODE(NuxBaseWindowAccessible, nux_base_window_accessible, + NUX_TYPE_VIEW_ACCESSIBLE, + G_IMPLEMENT_INTERFACE(ATK_TYPE_WINDOW, + atk_window_interface_init)) + +struct _NuxBaseWindowAccessiblePrivate +{ + /* Cached values (used to avoid extra notifications) */ + gboolean active; +}; + +#define NUX_BASE_WINDOW_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NUX_TYPE_BASE_WINDOW_ACCESSIBLE, \ + NuxBaseWindowAccessiblePrivate)) + +static void +nux_base_window_accessible_class_init(NuxBaseWindowAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* AtkObject */ + atk_class->initialize = nux_base_window_accessible_initialize; + atk_class->get_parent = nux_base_window_accessible_get_parent; + atk_class->ref_state_set = nux_base_window_accessible_ref_state_set; + + g_type_class_add_private(gobject_class, sizeof(NuxBaseWindowAccessiblePrivate)); +} + +static void +nux_base_window_accessible_init(NuxBaseWindowAccessible* base_window_accessible) +{ + NuxBaseWindowAccessiblePrivate* priv = + NUX_BASE_WINDOW_ACCESSIBLE_GET_PRIVATE(base_window_accessible); + + base_window_accessible->priv = priv; +} + +AtkObject* +nux_base_window_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<nux::BaseWindow*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(NUX_TYPE_BASE_WINDOW_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +nux_base_window_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + ATK_OBJECT_CLASS(nux_base_window_accessible_parent_class)->initialize(accessible, data); + + atk_object_set_role(accessible, ATK_ROLE_WINDOW); +} + +static AtkObject* +nux_base_window_accessible_get_parent(AtkObject* obj) +{ + return atk_get_root(); +} + +static AtkStateSet* +nux_base_window_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + NuxBaseWindowAccessible* self = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(NUX_IS_BASE_WINDOW_ACCESSIBLE(obj), NULL); + + state_set = ATK_OBJECT_CLASS(nux_base_window_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + if (nux_object == NULL) /* defunct */ + return state_set; + + self = NUX_BASE_WINDOW_ACCESSIBLE(obj); + + atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); + + /* HasKeyboardFocus is not reliable here: + see bug https://bugs.launchpad.net/nux/+bug/745049 */ + if (self->priv->active) + { + atk_state_set_add_state(state_set, ATK_STATE_ACTIVE); + atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); + } + + return state_set; +} + +/* AtkWindow */ +static void +atk_window_interface_init(AtkWindowIface* iface) +{ + /* AtkWindow just defines signals at this moment */ +} + +/* public */ +/* + * Checks if we are the active window. + */ +void +nux_base_window_accessible_check_active(NuxBaseWindowAccessible* self, + nux::BaseWindow* active_window) +{ + gboolean is_active; + nux::Object* nux_object = NULL; + nux::BaseWindow* bwindow = NULL; + + g_return_if_fail(NUX_IS_BASE_WINDOW_ACCESSIBLE(self)); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + bwindow = dynamic_cast<nux::BaseWindow*>(nux_object); + if (bwindow == NULL) /* defunct */ + return; + + is_active = (bwindow == active_window); + + if (self->priv->active != is_active) + { + const gchar* signal_name; + self->priv->active = is_active; + + if (is_active) + signal_name = "activate"; + else + signal_name = "deactivate"; + + atk_object_notify_state_change(ATK_OBJECT(self), + ATK_STATE_ACTIVE, is_active); + g_signal_emit_by_name(self, signal_name, 0); + } +} diff --git a/a11y/nux-base-window-accessible.h b/a11y/nux-base-window-accessible.h new file mode 100644 index 000000000..0fa6382d4 --- /dev/null +++ b/a11y/nux-base-window-accessible.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef NUX_BASE_WINDOW_ACCESSIBLE_H +#define NUX_BASE_WINDOW_ACCESSIBLE_H + +#include <atk/atk.h> + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define NUX_TYPE_BASE_WINDOW_ACCESSIBLE (nux_base_window_accessible_get_type ()) +#define NUX_BASE_WINDOW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NUX_TYPE_BASE_WINDOW_ACCESSIBLE, NuxBaseWindowAccessible)) +#define NUX_BASE_WINDOW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NUX_TYPE_BASE_WINDOW_ACCESSIBLE, NuxBaseWindowAccessibleClass)) +#define NUX_IS_BASE_WINDOW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NUX_TYPE_BASE_WINDOW_ACCESSIBLE)) +#define NUX_IS_BASE_WINDOW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NUX_TYPE_BASE_WINDOW_ACCESSIBLE)) +#define NUX_BASE_WINDOW_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NUX_TYPE_BASE_WINDOW_ACCESSIBLE, NuxBaseWindowAccessibleClass)) + +typedef struct _NuxBaseWindowAccessible NuxBaseWindowAccessible; +typedef struct _NuxBaseWindowAccessibleClass NuxBaseWindowAccessibleClass; +typedef struct _NuxBaseWindowAccessiblePrivate NuxBaseWindowAccessiblePrivate; + +struct _NuxBaseWindowAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + NuxBaseWindowAccessiblePrivate* priv; +}; + +struct _NuxBaseWindowAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType nux_base_window_accessible_get_type(void); +AtkObject* nux_base_window_accessible_new(nux::Object* object); +void nux_base_window_accessible_check_active(NuxBaseWindowAccessible* self, + nux::BaseWindow* active_window); + + +G_END_DECLS + +#endif /* __NUX_BASE_WINDOW_ACCESSIBLE_H__ */ diff --git a/a11y/nux-layout-accessible.cpp b/a11y/nux-layout-accessible.cpp new file mode 100644 index 000000000..d4a3e3b4a --- /dev/null +++ b/a11y/nux-layout-accessible.cpp @@ -0,0 +1,226 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:nux-layout-accessible + * @Title: NuxLayoutAccessible + * @short_description: Implementation of the ATK interfaces for #nux::Layout + * @see_also: nux::Layout + * + * #NuxLayoutAccessible implements the required ATK interfaces of + * nux::Layout, implementing the container related methods on + * AtkObject, in order to expose its objects + * + */ + +#include "nux-layout-accessible.h" +#include "unity-util-accessible.h" + +#include "unitya11y.h" + +/* GObject */ +static void nux_layout_accessible_class_init(NuxLayoutAccessibleClass* klass); +static void nux_layout_accessible_init(NuxLayoutAccessible* layout_accessible); + +/* AtkObject.h */ +static void nux_layout_accessible_initialize(AtkObject* accessible, + gpointer data); +static gint nux_layout_accessible_get_n_children(AtkObject* obj); +static AtkObject* nux_layout_accessible_ref_child(AtkObject* obj, + gint i); + +/* private */ +static void on_view_changed_cb(nux::Layout* layout, + nux::Area* area, + AtkObject* acccessible, + gboolean is_add); +static int search_for_child(AtkObject* accessible, + nux::Layout* layout, + nux::Area* area); + +G_DEFINE_TYPE(NuxLayoutAccessible, nux_layout_accessible, NUX_TYPE_AREA_ACCESSIBLE) + +static void +nux_layout_accessible_class_init(NuxLayoutAccessibleClass* klass) +{ + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* AtkObject */ + atk_class->initialize = nux_layout_accessible_initialize; + atk_class->ref_child = nux_layout_accessible_ref_child; + atk_class->get_n_children = nux_layout_accessible_get_n_children; +} + +static void +nux_layout_accessible_init(NuxLayoutAccessible* layout_accessible) +{ +} + +AtkObject* +nux_layout_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(static_cast<nux::Layout*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(NUX_TYPE_LAYOUT_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +nux_layout_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + nux::Layout* layout = NULL; + + ATK_OBJECT_CLASS(nux_layout_accessible_parent_class)->initialize(accessible, data); + + accessible->role = ATK_ROLE_PANEL; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + layout = static_cast<nux::Layout*>(nux_object); + + layout->ViewAdded.connect(sigc::bind(sigc::ptr_fun(on_view_changed_cb), + accessible, TRUE)); + + layout->ViewRemoved.connect(sigc::bind(sigc::ptr_fun(on_view_changed_cb), + accessible, FALSE)); +} + +static gint +nux_layout_accessible_get_n_children(AtkObject* obj) +{ + nux::Object* nux_object = NULL; + nux::Layout* layout = NULL; + std::list<nux::Area*> element_list; + + g_return_val_if_fail(NUX_IS_LAYOUT_ACCESSIBLE(obj), 0); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + if (!nux_object) /* state is defunct */ + return 0; + + layout = static_cast<nux::Layout*>(nux_object); + + element_list = layout->GetChildren(); + + return element_list.size(); +} + +static AtkObject* +nux_layout_accessible_ref_child(AtkObject* obj, + gint i) +{ + nux::Object* nux_object = NULL; + nux::Object* child = NULL; + AtkObject* child_accessible = NULL; + nux::Layout* layout = NULL; + std::list<nux::Area*> element_list; + gint num = 0; + std::list<nux::Area*>::iterator it; + AtkObject* parent = NULL; + + g_return_val_if_fail(NUX_IS_LAYOUT_ACCESSIBLE(obj), 0); + num = atk_object_get_n_accessible_children(obj); + g_return_val_if_fail((i < num) && (i >= 0), NULL); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + if (!nux_object) /* state is defunct */ + return 0; + + layout = static_cast<nux::Layout*>(nux_object); + + element_list = layout->GetChildren(); + + it = element_list.begin(); + std::advance(it, i); + + child = static_cast<nux::Object*>(*it); + child_accessible = unity_a11y_get_accessible(child); + + parent = atk_object_get_parent(child_accessible); + if (parent != obj) + atk_object_set_parent(child_accessible, obj); + + g_object_ref(child_accessible); + + return child_accessible; +} + +/* private */ +static void +on_view_changed_cb(nux::Layout* layout, + nux::Area* area, + AtkObject* accessible, + gboolean is_add) +{ + const gchar* signal_name = NULL; + AtkObject* atk_child = NULL; + gint index; + + g_return_if_fail(NUX_IS_LAYOUT_ACCESSIBLE(accessible)); + + atk_child = unity_a11y_get_accessible(area); + + if (is_add) + { + signal_name = "children-changed::add"; + index = nux_layout_accessible_get_n_children(accessible) - 1; + explore_children(accessible); + } + else + { + signal_name = "children-changed::remove"; + index = search_for_child(accessible, layout, area); + } + + g_signal_emit_by_name(accessible, signal_name, index, atk_child, NULL); +} + +static int +search_for_child(AtkObject* accessible, + nux::Layout* layout, + nux::Area* area) +{ + std::list<nux::Area*> element_list; + std::list<nux::Area*>::iterator it; + nux::Area* current_area = NULL; + gint result = 0; + gboolean found = FALSE; + + element_list = layout->GetChildren(); + + for (it = element_list.begin(); it != element_list.end(); ++it, result++) + { + current_area = *it; + if (current_area == area) + { + found = TRUE; + break; + } + } + + if (!found) result = -1; + + return result; +} diff --git a/a11y/nux-layout-accessible.h b/a11y/nux-layout-accessible.h new file mode 100644 index 000000000..cc9a50cd3 --- /dev/null +++ b/a11y/nux-layout-accessible.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef NUX_LAYOUT_ACCESSIBLE_H +#define NUX_LAYOUT_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-area-accessible.h" + +#include <Nux/Nux.h> +#include <Nux/Layout.h> + +G_BEGIN_DECLS + +#define NUX_TYPE_LAYOUT_ACCESSIBLE (nux_layout_accessible_get_type ()) +#define NUX_LAYOUT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NUX_TYPE_LAYOUT_ACCESSIBLE, NuxLayoutAccessible)) +#define NUX_LAYOUT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NUX_TYPE_LAYOUT_ACCESSIBLE, NuxLayoutAccessibleClass)) +#define NUX_IS_LAYOUT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NUX_TYPE_LAYOUT_ACCESSIBLE)) +#define NUX_IS_LAYOUT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NUX_TYPE_LAYOUT_ACCESSIBLE)) +#define NUX_LAYOUT_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NUX_TYPE_LAYOUT_ACCESSIBLE, NuxLayoutAccessibleClass)) + +typedef struct _NuxLayoutAccessible NuxLayoutAccessible; +typedef struct _NuxLayoutAccessibleClass NuxLayoutAccessibleClass; + +struct _NuxLayoutAccessible +{ + NuxAreaAccessible parent; +}; + +struct _NuxLayoutAccessibleClass +{ + NuxAreaAccessibleClass parent_class; +}; + +GType nux_layout_accessible_get_type(void); +AtkObject* nux_layout_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __NUX_LAYOUT_ACCESSIBLE_H__ */ diff --git a/a11y/nux-object-accessible.cpp b/a11y/nux-object-accessible.cpp new file mode 100644 index 000000000..4e25c2963 --- /dev/null +++ b/a11y/nux-object-accessible.cpp @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:nux-object-accessible + * @Title: NuxObjectAccessible + * @short_description: Implementation of the ATK interfaces for #nux::Object + * @see_also: nux::Object + * + * #NuxObjectAccessible implements the required ATK interfaces of + * nux::Object, exposing the common elements of each basic individual + * element (position, extents, etc) + * + */ + +#include "nux-object-accessible.h" + +#include <sigc++/connection.h> + +/* GObject */ +static void nux_object_accessible_class_init(NuxObjectAccessibleClass* klass); +static void nux_object_accessible_init(NuxObjectAccessible* object_accessible); +static void nux_object_accessible_finalize(GObject* object); + +/* AtkObject.h */ +static void nux_object_accessible_initialize(AtkObject* accessible, + gpointer data); +static AtkStateSet* nux_object_accessible_ref_state_set(AtkObject* accessible); + +/* Private methods */ +static void on_object_destroy_cb(nux::Object* base_object, + NuxObjectAccessible* object_accessible); + + +#define NUX_OBJECT_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NUX_TYPE_OBJECT_ACCESSIBLE, NuxObjectAccessiblePrivate)) + +G_DEFINE_TYPE(NuxObjectAccessible, nux_object_accessible, ATK_TYPE_OBJECT) + +struct _NuxObjectAccessiblePrivate +{ + nux::Object* object; + sigc::connection on_destroyed_connection; +}; + +static void +nux_object_accessible_class_init(NuxObjectAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->finalize = nux_object_accessible_finalize; + + /* AtkObject */ + atk_class->initialize = nux_object_accessible_initialize; + atk_class->ref_state_set = nux_object_accessible_ref_state_set; + + g_type_class_add_private(gobject_class, sizeof(NuxObjectAccessiblePrivate)); +} + +static void +nux_object_accessible_init(NuxObjectAccessible* object_accessible) +{ + object_accessible->priv = NUX_OBJECT_ACCESSIBLE_GET_PRIVATE(object_accessible); + + object_accessible->priv->object = NULL; +} + +AtkObject* +nux_object_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<nux::Object*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(NUX_TYPE_OBJECT_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +static void +nux_object_accessible_finalize(GObject* object) +{ + NuxObjectAccessible* self = NUX_OBJECT_ACCESSIBLE(object); + + self->priv->on_destroyed_connection.disconnect(); + + G_OBJECT_CLASS(nux_object_accessible_parent_class)->finalize(object); +} + +/* AtkObject.h */ +static void +nux_object_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + NuxObjectAccessible* self = NULL; + nux::Object* object = NULL; + + ATK_OBJECT_CLASS(nux_object_accessible_parent_class)->initialize(accessible, data); + + self = NUX_OBJECT_ACCESSIBLE(accessible); + object = (nux::Object*) data; + + self->priv->object = object; + + self->priv->on_destroyed_connection = + object->OnDestroyed.connect(sigc::bind(sigc::ptr_fun(on_object_destroy_cb), self)); + + accessible->role = ATK_ROLE_UNKNOWN; +} + +/** + * nux_object_accessible_get_object: + * + * Returns the nux::Object this object is providing accessibility support for. + * + * Note that there isn't a _set method. This is because setting that + * should only be done during initialization, and it doesn't make sense + * to change that during the lifetime of the object. + * + */ +nux::Object* +nux_object_accessible_get_object(NuxObjectAccessible* self) +{ + return self->priv->object; +} + +static AtkStateSet* +nux_object_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + + g_return_val_if_fail(NUX_IS_OBJECT_ACCESSIBLE(obj), NULL); + + state_set = ATK_OBJECT_CLASS(nux_object_accessible_parent_class)->ref_state_set(obj); + + if (NUX_OBJECT_ACCESSIBLE(obj)->priv->object == NULL) + atk_state_set_add_state(state_set, ATK_STATE_DEFUNCT); + + return state_set; +} + +/* Private methods */ +static void +on_object_destroy_cb(nux::Object* base_object, + NuxObjectAccessible* object_accessible) +{ + object_accessible->priv->object = NULL; + object_accessible->priv->on_destroyed_connection.disconnect(); + atk_object_notify_state_change(ATK_OBJECT(object_accessible), ATK_STATE_DEFUNCT, + TRUE); +} diff --git a/a11y/nux-object-accessible.h b/a11y/nux-object-accessible.h new file mode 100644 index 000000000..decf9b358 --- /dev/null +++ b/a11y/nux-object-accessible.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef NUX_OBJECT_ACCESSIBLE_H +#define NUX_OBJECT_ACCESSIBLE_H + +#include <atk/atk.h> + +#include <Nux/Nux.h> +#include <NuxCore/Object.h> + +G_BEGIN_DECLS + +#define NUX_TYPE_OBJECT_ACCESSIBLE (nux_object_accessible_get_type ()) +#define NUX_OBJECT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NUX_TYPE_OBJECT_ACCESSIBLE, NuxObjectAccessible)) +#define NUX_OBJECT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NUX_TYPE_OBJECT_ACCESSIBLE, NuxObjectAccessibleClass)) +#define NUX_IS_OBJECT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NUX_TYPE_OBJECT_ACCESSIBLE)) +#define NUX_IS_OBJECT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NUX_TYPE_OBJECT_ACCESSIBLE)) +#define NUX_OBJECT_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NUX_TYPE_OBJECT_ACCESSIBLE, NuxObjectAccessibleClass)) + +typedef struct _NuxObjectAccessible NuxObjectAccessible; +typedef struct _NuxObjectAccessibleClass NuxObjectAccessibleClass; +typedef struct _NuxObjectAccessiblePrivate NuxObjectAccessiblePrivate; + +struct _NuxObjectAccessible +{ + AtkObject parent; + + /* < private > */ + NuxObjectAccessiblePrivate* priv; +}; + +struct _NuxObjectAccessibleClass +{ + AtkObjectClass parent_class; +}; + +GType nux_object_accessible_get_type(void); +AtkObject* nux_object_accessible_new(nux::Object* object); + +nux::Object* nux_object_accessible_get_object(NuxObjectAccessible* self); + +G_END_DECLS + +#endif /* __NUX_OBJECT_ACCESSIBLE_H__ */ diff --git a/a11y/nux-text-entry-accessible.cpp b/a11y/nux-text-entry-accessible.cpp new file mode 100644 index 000000000..bda50a611 --- /dev/null +++ b/a11y/nux-text-entry-accessible.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:nux-text_entry-accessible + * @Title: NuxTextEntryAccessible + * @short_description: Implementation of the ATK interfaces for #TextEntry + * @see_also: nux::TextEntry + * + * #NuxTextEntryAccessible implements the required ATK interfaces for + * #StaticCairoText, mainly exposing the text as his name, as this + * #object is mainly used as a label + * + */ + +#include <glib/gi18n.h> + +#include "nux-text-entry-accessible.h" + +#include "unitya11y.h" +#include <Nux/TextEntry.h> + +/* GObject */ +static void nux_text_entry_accessible_class_init(NuxTextEntryAccessibleClass* klass); +static void nux_text_entry_accessible_init(NuxTextEntryAccessible* self); + +/* AtkObject.h */ +static void nux_text_entry_accessible_initialize(AtkObject* accessible, + gpointer data); +static AtkStateSet* nux_text_entry_accessible_ref_state_set(AtkObject* obj); + +/* Fixme: it should implement AtkText/AtkTextEditable interfaces */ +G_DEFINE_TYPE(NuxTextEntryAccessible, nux_text_entry_accessible, NUX_TYPE_VIEW_ACCESSIBLE); + + +static void +nux_text_entry_accessible_class_init(NuxTextEntryAccessibleClass* klass) +{ + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* AtkObject */ + atk_class->ref_state_set = nux_text_entry_accessible_ref_state_set; + atk_class->initialize = nux_text_entry_accessible_initialize; +} + +static void +nux_text_entry_accessible_init(NuxTextEntryAccessible* self) +{} + +AtkObject* +nux_text_entry_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<nux::TextEntry*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(NUX_TYPE_TEXT_ENTRY_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +nux_text_entry_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + nux::TextEntry* text_entry = NULL; + + ATK_OBJECT_CLASS(nux_text_entry_accessible_parent_class)->initialize(accessible, data); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + text_entry = dynamic_cast<nux::TextEntry*>(nux_object); + + atk_object_set_role(accessible, text_entry->PasswordMode() ? ATK_ROLE_PASSWORD_TEXT : ATK_ROLE_ENTRY); +} + +static AtkStateSet* +nux_text_entry_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(NUX_IS_TEXT_ENTRY_ACCESSIBLE(obj), NULL); + + state_set = ATK_OBJECT_CLASS(nux_text_entry_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + if (nux_object == NULL) /* defunct */ + return state_set; + + /* Text entry is editable by default */ + atk_state_set_add_state(state_set, ATK_STATE_EDITABLE); + + return state_set; +} diff --git a/a11y/nux-text-entry-accessible.h b/a11y/nux-text-entry-accessible.h new file mode 100644 index 000000000..b618bd85a --- /dev/null +++ b/a11y/nux-text-entry-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef NUX_TEXT_ENTRY_ACCESSIBLE_H +#define NUX_TEXT_ENTRY_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define NUX_TYPE_TEXT_ENTRY_ACCESSIBLE (nux_text_entry_accessible_get_type ()) +#define NUX_TEXT_ENTRY_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NUX_TYPE_TEXT_ENTRY_ACCESSIBLE, NuxTextEntryAccessible)) +#define NUX_TEXT_ENTRY_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NUX_TYPE_TEXT_ENTRY_ACCESSIBLE, NuxTextEntryAccessibleClass)) +#define NUX_IS_TEXT_ENTRY_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NUX_TYPE_TEXT_ENTRY_ACCESSIBLE)) +#define NUX_IS_TEXT_ENTRY_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NUX_TYPE_TEXT_ENTRY_ACCESSIBLE)) +#define NUX_TEXT_ENTRY_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NUX_TYPE_TEXT_ENTRY_ACCESSIBLE, NuxTextEntryAccessibleClass)) + +typedef struct _NuxTextEntryAccessible NuxTextEntryAccessible; +typedef struct _NuxTextEntryAccessibleClass NuxTextEntryAccessibleClass; +typedef struct _NuxTextEntryAccessiblePrivate NuxTextEntryAccessiblePrivate; + +struct _NuxTextEntryAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + NuxTextEntryAccessiblePrivate* priv; +}; + +struct _NuxTextEntryAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType nux_text_entry_accessible_get_type(void); +AtkObject* nux_text_entry_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __NUX_TEXT_ENTRY_ACCESSIBLE_H__ */ diff --git a/a11y/nux-view-accessible.cpp b/a11y/nux-view-accessible.cpp new file mode 100644 index 000000000..2718437eb --- /dev/null +++ b/a11y/nux-view-accessible.cpp @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:nux-view-accessible + * @Title: NuxViewAccessible + * @short_description: Implementation of the ATK interfaces for #nux::View + * @see_also: nux::View + * + * #NuxViewAccessible implements the required ATK interfaces of + * nux::View + * + */ + +#include "nux-view-accessible.h" +#include "unity-util-accessible.h" +#include "unitya11y.h" +#include "nux-base-window-accessible.h" + +#include <Nux/Layout.h> +#include <Nux/Area.h> + +/* GObject */ +static void nux_view_accessible_class_init(NuxViewAccessibleClass* klass); +static void nux_view_accessible_init(NuxViewAccessible* view_accessible); + +/* AtkObject.h */ +static void nux_view_accessible_initialize(AtkObject* accessible, + gpointer data); +static AtkStateSet* nux_view_accessible_ref_state_set(AtkObject* obj); +static gint nux_view_accessible_get_n_children(AtkObject* obj); +static AtkObject* nux_view_accessible_ref_child(AtkObject* obj, + gint i); +static AtkStateSet* nux_view_accessible_ref_state_set(AtkObject* obj); +static gint nux_view_accessible_get_n_children(AtkObject* obj); +static AtkObject* nux_view_accessible_ref_child(AtkObject* obj, + gint i); +/* NuxAreaAccessible */ +static gboolean nux_view_accessible_check_pending_notification(NuxAreaAccessible* self); + +/* private methods */ +static void on_layout_changed_cb(nux::View* view, + nux::Layout* layout, + AtkObject* accessible, + gboolean is_add); +static void on_change_keyboard_receiver_cb(AtkObject* accessible, + gboolean focus_in); + +G_DEFINE_TYPE(NuxViewAccessible, + nux_view_accessible, + NUX_TYPE_AREA_ACCESSIBLE) + +#define NUX_VIEW_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NUX_TYPE_VIEW_ACCESSIBLE, \ + NuxViewAccessiblePrivate)) + +struct _NuxViewAccessiblePrivate +{ + /* focused using InputArea OnStartKeyboardReceiver and OnStop... signals */ + gboolean key_focused; + + /* if the state from key_focused was notified or not */ + gboolean pending_notification; +}; + + +static void +nux_view_accessible_class_init(NuxViewAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + NuxAreaAccessibleClass* area_class = NUX_AREA_ACCESSIBLE_CLASS(klass); + + /* AtkObject */ + atk_class->initialize = nux_view_accessible_initialize; + atk_class->ref_state_set = nux_view_accessible_ref_state_set; + atk_class->ref_child = nux_view_accessible_ref_child; + atk_class->get_n_children = nux_view_accessible_get_n_children; + + /* NuxAreaAccessible */ + area_class->check_pending_notification = nux_view_accessible_check_pending_notification; + + g_type_class_add_private(gobject_class, sizeof(NuxViewAccessiblePrivate)); +} + +static void +nux_view_accessible_init(NuxViewAccessible* view_accessible) +{ + NuxViewAccessiblePrivate* priv = + NUX_VIEW_ACCESSIBLE_GET_PRIVATE(view_accessible); + + view_accessible->priv = priv; +} + +AtkObject* +nux_view_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<nux::View*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(NUX_TYPE_VIEW_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +nux_view_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + nux::View* view = NULL; + + ATK_OBJECT_CLASS(nux_view_accessible_parent_class)->initialize(accessible, data); + + accessible->role = ATK_ROLE_UNKNOWN; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + view = static_cast<nux::View*>(nux_object); + + view->LayoutAdded.connect(sigc::bind(sigc::ptr_fun(on_layout_changed_cb), + accessible, TRUE)); + view->LayoutRemoved.connect(sigc::bind(sigc::ptr_fun(on_layout_changed_cb), + accessible, FALSE)); + + /* Some extra focus things as Focusable is not used on Launcher and + some BaseWindow */ + view->begin_key_focus.connect(sigc::bind(sigc::ptr_fun(on_change_keyboard_receiver_cb), + accessible, TRUE)); + view->end_key_focus.connect(sigc::bind(sigc::ptr_fun(on_change_keyboard_receiver_cb), + accessible, FALSE)); +} + +static AtkStateSet* +nux_view_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + nux::Object* nux_object = NULL; + NuxViewAccessible* self = NULL; + + g_return_val_if_fail(NUX_IS_VIEW_ACCESSIBLE(obj), NULL); + self = NUX_VIEW_ACCESSIBLE(obj); + + state_set = ATK_OBJECT_CLASS(nux_view_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + + if (nux_object == NULL) /* defunct */ + return state_set; + + /* HasKeyboardFocus is not reliable here: + see bug https://bugs.launchpad.net/nux/+bug/745049 */ + if (self->priv->key_focused) + atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); + + return state_set; +} + +static gint +nux_view_accessible_get_n_children(AtkObject* obj) +{ + nux::Object* nux_object = NULL; + nux::View* view = NULL; + nux::Layout* layout = NULL; + + g_return_val_if_fail(NUX_IS_VIEW_ACCESSIBLE(obj), 0); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + if (nux_object == NULL) /* state is defunct */ + return 0; + + view = static_cast<nux::View*>(nux_object); + layout = view->GetLayout(); + + if (layout == NULL) + return 0; + else + return 1; +} + +static AtkObject* +nux_view_accessible_ref_child(AtkObject* obj, + gint i) +{ + nux::Object* nux_object = NULL; + nux::View* view = NULL; + nux::Layout* layout = NULL; + AtkObject* layout_accessible = NULL; + gint num = 0; + + g_return_val_if_fail(NUX_IS_VIEW_ACCESSIBLE(obj), 0); + + num = atk_object_get_n_accessible_children(obj); + g_return_val_if_fail((i < num) && (i >= 0), NULL); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + if (nux_object == NULL) /* state is defunct */ + return 0; + + view = static_cast<nux::View*>(nux_object); + layout = view->GetLayout(); + + layout_accessible = unity_a11y_get_accessible(layout); + + if (layout_accessible != NULL) + g_object_ref(layout_accessible); + + return layout_accessible; +} + +static void +on_layout_changed_cb(nux::View* view, + nux::Layout* layout, + AtkObject* accessible, + gboolean is_add) +{ + const gchar* signal_name = NULL; + AtkObject* atk_child = NULL; + + g_return_if_fail(NUX_IS_VIEW_ACCESSIBLE(accessible)); + + atk_child = unity_a11y_get_accessible(layout); + + if (is_add) + { + signal_name = "children-changed::add"; + explore_children(accessible); + } + else + { + signal_name = "children-changed::remove"; + } + + /* index is always 0 as there is always just one layout */ + g_signal_emit_by_name(accessible, signal_name, 0, atk_child, NULL); +} + +static void +on_change_keyboard_receiver_cb(AtkObject* accessible, + gboolean focus_in) +{ + NuxViewAccessible* self = NULL; + + g_return_if_fail(NUX_IS_VIEW_ACCESSIBLE(accessible)); + self = NUX_VIEW_ACCESSIBLE(accessible); + + if (self->priv->key_focused != focus_in) + { + self->priv->key_focused = focus_in; + + /* we always lead the focus notification to + _check_pending_notification, in order to allow the proper + window_activate -> focus_change order */ + self->priv->pending_notification = TRUE; + } +} + +static gboolean +nux_view_accessible_check_pending_notification(NuxAreaAccessible* area_accessible) +{ + NuxViewAccessible* self = NULL; + nux::Object* nux_object = NULL; + + /* We also call the parent implementation, as we are not totally + overriding check_pending_notification, just adding extra + functionality*/ + NUX_AREA_ACCESSIBLE_CLASS(nux_view_accessible_parent_class)->check_pending_notification(area_accessible); + + g_return_val_if_fail(NUX_IS_VIEW_ACCESSIBLE(area_accessible), FALSE); + self = NUX_VIEW_ACCESSIBLE(area_accessible); + + if (self->priv->pending_notification == FALSE) + return FALSE; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + if (nux_object == NULL) /* defunct */ + return FALSE; + + g_signal_emit_by_name(self, "focus_event", self->priv->key_focused); + atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_FOCUSED, self->priv->key_focused); + self->priv->pending_notification = FALSE; + + return TRUE; +} diff --git a/a11y/nux-view-accessible.h b/a11y/nux-view-accessible.h new file mode 100644 index 000000000..bca728ce6 --- /dev/null +++ b/a11y/nux-view-accessible.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef NUX_VIEW_ACCESSIBLE_H +#define NUX_VIEW_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-area-accessible.h" + +#include <Nux/Nux.h> +#include <Nux/View.h> + +G_BEGIN_DECLS + +#define NUX_TYPE_VIEW_ACCESSIBLE (nux_view_accessible_get_type ()) +#define NUX_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NUX_TYPE_VIEW_ACCESSIBLE, NuxViewAccessible)) +#define NUX_VIEW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NUX_TYPE_VIEW_ACCESSIBLE, NuxViewAccessibleClass)) +#define NUX_IS_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NUX_TYPE_VIEW_ACCESSIBLE)) +#define NUX_IS_VIEW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NUX_TYPE_VIEW_ACCESSIBLE)) +#define NUX_VIEW_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NUX_TYPE_VIEW_ACCESSIBLE, NuxViewAccessibleClass)) + +typedef struct _NuxViewAccessible NuxViewAccessible; +typedef struct _NuxViewAccessibleClass NuxViewAccessibleClass; +typedef struct _NuxViewAccessiblePrivate NuxViewAccessiblePrivate; + +struct _NuxViewAccessible +{ + NuxAreaAccessible parent; + + /*< private >*/ + NuxViewAccessiblePrivate* priv; +}; + +struct _NuxViewAccessibleClass +{ + NuxAreaAccessibleClass parent_class; +}; + +GType nux_view_accessible_get_type(void); +AtkObject* nux_view_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __NUX_VIEW_ACCESSIBLE_H__ */ diff --git a/a11y/pch/a11y_pch.hh b/a11y/pch/a11y_pch.hh new file mode 100644 index 000000000..ecae45c9c --- /dev/null +++ b/a11y/pch/a11y_pch.hh @@ -0,0 +1,33 @@ +// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*- +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Marco Trevisan <marco.trevisan@canonical.com> + */ + +/* + * These are the precompiled header includes for this module. + * Only system header files can be listed here. + */ + +#include <atk/atk.h> +#include <glib.h> +#include <gio/gio.h> +#include <gmodule.h> +#include <stdio.h> +#include <atk-bridge.h> +#include <Nux/Nux.h> +#include <Nux/WindowThread.h> +#include <NuxCore/Object.h> diff --git a/a11y/unity-dash-view-accessible.cpp b/a11y/unity-dash-view-accessible.cpp new file mode 100644 index 000000000..76258e128 --- /dev/null +++ b/a11y/unity-dash-view-accessible.cpp @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-dash_view-accessible + * @Title: UnityDashViewAccessible + * @short_description: Implementation of the ATK interfaces for #DashView + * @see_also: DashView + * + * #UnityDashViewAccessible implements the required ATK interfaces for + * #DashView, ie: exposing the different DashViewIcon on the model as + * #child of the object. + * + */ + +#include <glib/gi18n.h> + +#include "unity-dash-view-accessible.h" + +#include "unitya11y.h" +#include "DashView.h" + +using namespace unity::dash; + +/* GObject */ +static void unity_dash_view_accessible_class_init(UnityDashViewAccessibleClass* klass); +static void unity_dash_view_accessible_init(UnityDashViewAccessible* self); +static void unity_dash_view_accessible_finalize(GObject* object); + +/* AtkObject.h */ +static void unity_dash_view_accessible_initialize(AtkObject* accessible, + gpointer data); + +G_DEFINE_TYPE(UnityDashViewAccessible, unity_dash_view_accessible, NUX_TYPE_VIEW_ACCESSIBLE) + +#define UNITY_DASH_VIEW_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_DASH_VIEW_ACCESSIBLE, \ + UnityDashViewAccessiblePrivate)) + +struct _UnityDashViewAccessiblePrivate +{ + +}; + + +static void +unity_dash_view_accessible_class_init(UnityDashViewAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->finalize = unity_dash_view_accessible_finalize; + + /* AtkObject */ + atk_class->initialize = unity_dash_view_accessible_initialize; + + g_type_class_add_private(gobject_class, sizeof(UnityDashViewAccessiblePrivate)); +} + +static void +unity_dash_view_accessible_init(UnityDashViewAccessible* self) +{ + UnityDashViewAccessiblePrivate* priv = + UNITY_DASH_VIEW_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; +} + +static void +unity_dash_view_accessible_finalize(GObject* object) +{ + G_OBJECT_CLASS(unity_dash_view_accessible_parent_class)->finalize(object); +} + +AtkObject* +unity_dash_view_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<DashView*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_DASH_VIEW_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + atk_object_set_name(accessible, _("Dash")); + + return accessible; +} + +/* AtkObject.h */ +static void +unity_dash_view_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + ATK_OBJECT_CLASS(unity_dash_view_accessible_parent_class)->initialize(accessible, data); + + accessible->role = ATK_ROLE_PANEL; +} + diff --git a/a11y/unity-dash-view-accessible.h b/a11y/unity-dash-view-accessible.h new file mode 100644 index 000000000..9d3ef7cc1 --- /dev/null +++ b/a11y/unity-dash-view-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_DASH_VIEW_ACCESSIBLE_H +#define UNITY_DASH_VIEW_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_DASH_VIEW_ACCESSIBLE (unity_dash_view_accessible_get_type ()) +#define UNITY_DASH_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_DASH_VIEW_ACCESSIBLE, UnityDashViewAccessible)) +#define UNITY_DASH_VIEW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_DASH_VIEW_ACCESSIBLE, UnityDashViewAccessibleClass)) +#define UNITY_IS_DASH_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_DASH_VIEW_ACCESSIBLE)) +#define UNITY_IS_DASH_VIEW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_DASH_VIEW_ACCESSIBLE)) +#define UNITY_DASH_VIEW_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_DASH_VIEW_ACCESSIBLE, UnityDashViewAccessibleClass)) + +typedef struct _UnityDashViewAccessible UnityDashViewAccessible; +typedef struct _UnityDashViewAccessibleClass UnityDashViewAccessibleClass; +typedef struct _UnityDashViewAccessiblePrivate UnityDashViewAccessiblePrivate; + +struct _UnityDashViewAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnityDashViewAccessiblePrivate* priv; +}; + +struct _UnityDashViewAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_dash_view_accessible_get_type(void); +AtkObject* unity_dash_view_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_DASH_VIEW_ACCESSIBLE_H__ */ diff --git a/a11y/unity-expander-view-accessible.cpp b/a11y/unity-expander-view-accessible.cpp new file mode 100644 index 000000000..b16f5c3d2 --- /dev/null +++ b/a11y/unity-expander-view-accessible.cpp @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Luke Yelavich <luke.yelavich@canonical.com> + */ + +/** + * SECTION:unity-expander-view-accessible + * @Title: UnityExpanderViewAccessible + * @short_description: Implementation of the ATK interfaces for #ExpanderView + * @see_also: ExpanderView + * + * #UnityExpanderViewAccessible implements the required ATK interfaces for + * #ExpanderView, mainly exposing the text as his name, as this + * #object is mainly used as a label + * + */ + +#include <NuxCore/Logger.h> +#include <glib/gi18n.h> + +#include "unity-expander-view-accessible.h" + +#include "ExpanderView.h" +#include "StaticCairoText.h" + +DECLARE_LOGGER(logger, "unity.a11y.ExpanderView"); + +using namespace unity; + +/* GObject */ +static void unity_expander_view_accessible_class_init(UnityExpanderViewAccessibleClass* klass); +static void unity_expander_view_accessible_init(UnityExpanderViewAccessible* self); +static void unity_expander_view_accessible_dispose(GObject* object); + +/* AtkObject.h */ +static void unity_expander_view_accessible_initialize(AtkObject* accessible, + gpointer data); +static const gchar* unity_expander_view_accessible_get_name(AtkObject* obj); +static void on_focus_changed_cb(nux::Area* area, + bool has_focus, + nux::KeyNavDirection direction, + AtkObject* accessible); +static void on_expanded_changed_cb(bool is_expanded, + AtkObject* accessible); +static void on_name_changed_cb(std::string name, + AtkObject* accessible); + +G_DEFINE_TYPE(UnityExpanderViewAccessible, unity_expander_view_accessible, NUX_TYPE_VIEW_ACCESSIBLE); + + +#define UNITY_EXPANDER_VIEW_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_EXPANDER_VIEW_ACCESSIBLE, \ + UnityExpanderViewAccessiblePrivate)) + +struct _UnityExpanderViewAccessiblePrivate +{ + gchar* name; +}; + + +static void +unity_expander_view_accessible_class_init(UnityExpanderViewAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->dispose = unity_expander_view_accessible_dispose; + + /* AtkObject */ + atk_class->initialize = unity_expander_view_accessible_initialize; + atk_class->get_name = unity_expander_view_accessible_get_name; + + g_type_class_add_private(gobject_class, sizeof(UnityExpanderViewAccessiblePrivate)); +} + +static void +unity_expander_view_accessible_init(UnityExpanderViewAccessible* self) +{ + UnityExpanderViewAccessiblePrivate* priv = + UNITY_EXPANDER_VIEW_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; + self->priv->name = NULL; +} + +static void +unity_expander_view_accessible_dispose(GObject* object) +{ + UnityExpanderViewAccessible* self = UNITY_EXPANDER_VIEW_ACCESSIBLE(object); + + if (self->priv->name != NULL) + { + g_free(self->priv->name); + self->priv->name = NULL; + } + + G_OBJECT_CLASS(unity_expander_view_accessible_parent_class)->dispose(object); +} + +AtkObject* +unity_expander_view_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<ExpanderView*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_EXPANDER_VIEW_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +unity_expander_view_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* object = NULL; + ExpanderView* view = NULL; + + ATK_OBJECT_CLASS(unity_expander_view_accessible_parent_class)->initialize(accessible, data); + + object = (nux::Object*)data; + view = static_cast<ExpanderView*>(object); + view->key_nav_focus_change.connect(sigc::bind(sigc::ptr_fun(on_focus_changed_cb), accessible)); + view->expanded.changed.connect(sigc::bind(sigc::ptr_fun(on_expanded_changed_cb), accessible)); + view->label.changed.connect(sigc::bind(sigc::ptr_fun(on_name_changed_cb), accessible)); + + atk_object_set_role(accessible, ATK_ROLE_PANEL); +} + +static const gchar* +unity_expander_view_accessible_get_name(AtkObject* obj) +{ + g_return_val_if_fail(UNITY_IS_EXPANDER_VIEW_ACCESSIBLE(obj), NULL); + UnityExpanderViewAccessible* self = UNITY_EXPANDER_VIEW_ACCESSIBLE(obj); + + if (self->priv->name != NULL) + { + g_free(self->priv->name); + self->priv->name = NULL; + } + + self->priv->name = g_strdup(ATK_OBJECT_CLASS(unity_expander_view_accessible_parent_class)->get_name(obj)); + if (self->priv->name == NULL) + { + ExpanderView* view = NULL; + + view = dynamic_cast<ExpanderView*>(nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj))); + + if (view == NULL) /* state is defunct */ + return NULL; + + if (view->expanded) + self->priv->name = g_strdup_printf(_("%s: expanded"), view->label().c_str()); + else + self->priv->name = g_strdup_printf(_("%s: collapsed"), view->label().c_str()); + } + + return self->priv->name; +} + +static void +on_focus_changed_cb(nux::Area* area, + bool has_focus, + nux::KeyNavDirection direction, + AtkObject* accessible) +{ + g_return_if_fail(UNITY_IS_EXPANDER_VIEW_ACCESSIBLE(accessible)); + + LOG_WARN(logger) << "has_focus = " << has_focus; + g_signal_emit_by_name(accessible, "focus-event", has_focus); +} + +static void +on_expanded_changed_cb(bool is_expanded, + AtkObject* accessible) +{ + g_return_if_fail(UNITY_IS_EXPANDER_VIEW_ACCESSIBLE(accessible)); + + g_object_notify(G_OBJECT(accessible), "accessible-name"); +} + +static void +on_name_changed_cb(std::string name, + AtkObject* accessible) +{ + g_return_if_fail(UNITY_IS_EXPANDER_VIEW_ACCESSIBLE(accessible)); + + g_object_notify(G_OBJECT(accessible), "accessible-name"); +} diff --git a/a11y/unity-expander-view-accessible.h b/a11y/unity-expander-view-accessible.h new file mode 100644 index 000000000..0c9855d79 --- /dev/null +++ b/a11y/unity-expander-view-accessible.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Luke Yelavich <luke.yelavich@canonical.com> + */ + +#ifndef UNITY_EXPANDER_VIEW_ACCESSIBLE_H +#define UNITY_EXPANDER_VIEW_ACCESSIBLE_H + +#include <atk/atk.h> + +#include <Nux/Nux.h> +#include <Nux/Layout.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_EXPANDER_VIEW_ACCESSIBLE (unity_expander_view_accessible_get_type ()) +#define UNITY_EXPANDER_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_EXPANDER_VIEW_ACCESSIBLE, UnityExpanderViewAccessible)) +#define UNITY_EXPANDER_VIEW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_EXPANDER_VIEW_ACCESSIBLE, UnityExpanderViewAccessibleClass)) +#define UNITY_IS_EXPANDER_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_EXPANDER_VIEW_ACCESSIBLE)) +#define UNITY_IS_EXPANDER_VIEW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_EXPANDER_VIEW_ACCESSIBLE)) +#define UNITY_EXPANDER_VIEW_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_EXPANDER_VIEW_ACCESSIBLE, UnityExpanderViewAccessibleClass)) + +typedef struct _UnityExpanderViewAccessible UnityExpanderViewAccessible; +typedef struct _UnityExpanderViewAccessibleClass UnityExpanderViewAccessibleClass; +typedef struct _UnityExpanderViewAccessiblePrivate UnityExpanderViewAccessiblePrivate; + +struct _UnityExpanderViewAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnityExpanderViewAccessiblePrivate* priv; +}; + +struct _UnityExpanderViewAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_expander_view_accessible_get_type(void); +AtkObject* unity_expander_view_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_EXPANDER_VIEW_ACCESSIBLE_H__ */ diff --git a/a11y/unity-filter-basic-button-accessible.cpp b/a11y/unity-filter-basic-button-accessible.cpp new file mode 100644 index 000000000..1011e86f5 --- /dev/null +++ b/a11y/unity-filter-basic-button-accessible.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Luke Yelavich <luke.yelavich@canonical.com> + */ + +/** + * SECTION:unity-filter-basic-button_accessible + * @Title: UnityFilterBasicButtonAccessible + * @short_description: Implementation of the ATK interfaces for #unity::dash::FilterBasicButton + * + * #UnityFilterBasicButtonAccessible implements the required ATK interfaces of + * unity::dash::FilterBasicButton, exposing the common elements on each basic individual + * element (position, extents, etc) + * + */ + +#include <NuxCore/Logger.h> +#include "unity-filter-basic-button-accessible.h" +#include "FilterBasicButton.h" + +#include "unitya11y.h" + +DECLARE_LOGGER(logger, "unity.a11y.UnityFilterBasicButtonAccessible"); + +using namespace unity::dash; + +/* GObject */ +static void unity_filter_basic_button_accessible_class_init(UnityFilterBasicButtonAccessibleClass* klass); +static void unity_filter_basic_button_accessible_init(UnityFilterBasicButtonAccessible* session_button_accessible); +static void unity_filter_basic_button_accessible_dispose(GObject* object); +static void unity_filter_basic_button_accessible_finalize(GObject* object); + + +/* AtkObject.h */ +static void unity_filter_basic_button_accessible_initialize(AtkObject* accessible, + gpointer data); +static AtkStateSet* unity_filter_basic_button_accessible_ref_state_set(AtkObject* obj); +static const gchar* unity_filter_basic_button_accessible_get_name(AtkObject* obj); + + +/* AtkAction */ +static void atk_action_interface_init(AtkActionIface *iface); +static gboolean unity_filter_basic_button_accessible_do_action(AtkAction *action, + gint i); +static gint unity_filter_basic_button_accessible_get_n_actions(AtkAction *action); +static const gchar* unity_filter_basic_button_accessible_get_action_name(AtkAction *action, + gint i); +static void on_layout_changed_cb(nux::View* view, + nux::Layout* layout, + AtkObject* accessible, + gboolean is_add); +static void on_focus_changed_cb(nux::Area* area, + bool has_focus, + nux::KeyNavDirection direction, + AtkObject* accessible); + +G_DEFINE_TYPE_WITH_CODE(UnityFilterBasicButtonAccessible, + unity_filter_basic_button_accessible, + NUX_TYPE_VIEW_ACCESSIBLE, + G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION, + atk_action_interface_init)) + +static void +unity_filter_basic_button_accessible_class_init(UnityFilterBasicButtonAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->dispose = unity_filter_basic_button_accessible_dispose; + gobject_class->finalize = unity_filter_basic_button_accessible_finalize; + + /* AtkObject */ + atk_class->initialize = unity_filter_basic_button_accessible_initialize; + atk_class->get_name = unity_filter_basic_button_accessible_get_name; + atk_class->ref_state_set = unity_filter_basic_button_accessible_ref_state_set; +} + +static void +unity_filter_basic_button_accessible_init(UnityFilterBasicButtonAccessible* session_button_accessible) +{ +} + +static void +unity_filter_basic_button_accessible_dispose(GObject* object) +{ + G_OBJECT_CLASS(unity_filter_basic_button_accessible_parent_class)->dispose(object); +} + +static void +unity_filter_basic_button_accessible_finalize(GObject* object) +{ + G_OBJECT_CLASS(unity_filter_basic_button_accessible_parent_class)->finalize(object); +} + +AtkObject* +unity_filter_basic_button_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<FilterBasicButton*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_FILTER_BASIC_BUTTON_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +unity_filter_basic_button_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + FilterBasicButton* button = NULL; + + ATK_OBJECT_CLASS(unity_filter_basic_button_accessible_parent_class)->initialize(accessible, data); + + accessible->role = ATK_ROLE_TOGGLE_BUTTON; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + + if (nux_object == NULL) /* defunct */ + return; + + button = dynamic_cast<FilterBasicButton*>(nux_object); + + if (button == NULL) /* defunct */ + return; + + button->LayoutAdded.connect(sigc::bind(sigc::ptr_fun(on_layout_changed_cb), + accessible, TRUE)); + + button->key_nav_focus_change.connect(sigc::bind(sigc::ptr_fun(on_focus_changed_cb), accessible)); +} + +static const gchar* +unity_filter_basic_button_accessible_get_name(AtkObject* obj) +{ + const gchar* name; + + g_return_val_if_fail(UNITY_IS_FILTER_BASIC_BUTTON_ACCESSIBLE(obj), NULL); + + name = ATK_OBJECT_CLASS(unity_filter_basic_button_accessible_parent_class)->get_name(obj); + if (name == NULL) + { + FilterBasicButton* button = NULL; + + button = dynamic_cast<FilterBasicButton*>(nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj))); + + if (button == NULL) /* State is defunct */ + name = NULL; + else + name = button->GetLabel().c_str(); + } + + if (name == NULL) + { + LOG_WARN(logger) << "Name == NULL"; + } + + return name; +} + +static AtkStateSet* +unity_filter_basic_button_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + nux::Object* nux_object = NULL; + FilterBasicButton* button = NULL; + + g_return_val_if_fail(UNITY_IS_FILTER_BASIC_BUTTON_ACCESSIBLE(obj), NULL); + + state_set = ATK_OBJECT_CLASS(unity_filter_basic_button_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + + if (nux_object == NULL) /* defunct */ + return state_set; + + button = static_cast<FilterBasicButton*>(nux_object); + + atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); + atk_state_set_add_state(state_set, ATK_STATE_ENABLED); + atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state(state_set, ATK_STATE_VISIBLE); + atk_state_set_add_state(state_set, ATK_STATE_SHOWING); + + if (button->GetVisualState() == nux::ButtonVisualState::VISUAL_STATE_PRELIGHT) + { + atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); + atk_state_set_add_state(state_set, ATK_STATE_SELECTED); + atk_state_set_add_state(state_set, ATK_STATE_ACTIVE); + } + + if (button->Active()) + atk_state_set_add_state(state_set, ATK_STATE_CHECKED); + + return state_set; +} + +/* AtkAction */ +static void +atk_action_interface_init(AtkActionIface *iface) +{ + iface->do_action = unity_filter_basic_button_accessible_do_action; + iface->get_n_actions = unity_filter_basic_button_accessible_get_n_actions; + iface->get_name = unity_filter_basic_button_accessible_get_action_name; +} + +static gboolean +unity_filter_basic_button_accessible_do_action(AtkAction *action, + gint i) +{ + FilterBasicButton* button = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_FILTER_BASIC_BUTTON_ACCESSIBLE(action), FALSE); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(action)); + if (nux_object == NULL) + return FALSE; + + button = static_cast<FilterBasicButton*>(nux_object); + button->Activate(); + + return TRUE; +} + +static gint +unity_filter_basic_button_accessible_get_n_actions(AtkAction *action) +{ + g_return_val_if_fail(UNITY_IS_FILTER_BASIC_BUTTON_ACCESSIBLE(action), 0); + + return 1; +} + +static const gchar* +unity_filter_basic_button_accessible_get_action_name(AtkAction *action, + gint i) +{ + g_return_val_if_fail(UNITY_IS_FILTER_BASIC_BUTTON_ACCESSIBLE(action), NULL); + g_return_val_if_fail(i == 0, NULL); + + return "activate"; +} + +static void +on_layout_changed_cb(nux::View* view, + nux::Layout* layout, + AtkObject* accessible, + gboolean is_add) +{ + g_return_if_fail(UNITY_IS_FILTER_BASIC_BUTTON_ACCESSIBLE(accessible)); + + g_object_notify(G_OBJECT(accessible), "accessible-name"); +} + +static void +on_focus_changed_cb(nux::Area* area, + bool has_focus, + nux::KeyNavDirection direction, + AtkObject* accessible) +{ + g_return_if_fail(UNITY_IS_FILTER_BASIC_BUTTON_ACCESSIBLE(accessible)); + + g_signal_emit_by_name(accessible, "focus-event", has_focus); +} diff --git a/a11y/unity-filter-basic-button-accessible.h b/a11y/unity-filter-basic-button-accessible.h new file mode 100644 index 000000000..a5eed8df0 --- /dev/null +++ b/a11y/unity-filter-basic-button-accessible.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Luke Yelavich <luke.yelavich@canonical.com> + */ + +#ifndef UNITY_FILTER_BASIC_BUTTON_ACCESSIBLE_H +#define UNITY_FILTER_BASIC_BUTTON_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_FILTER_BASIC_BUTTON_ACCESSIBLE (unity_filter_basic_button_accessible_get_type ()) +#define UNITY_FILTER_BASIC_BUTTON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_FILTER_BASIC_BUTTON_ACCESSIBLE, UnityFilterBasicButtonAccessible)) +#define UNITY_FILTER_BASIC_BUTTON_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_FILTER_BASIC_BUTTON_ACCESSIBLE, UnityFilterBasicButtonAccessibleClass)) +#define UNITY_IS_FILTER_BASIC_BUTTON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_FILTER_BASIC_BUTTON_ACCESSIBLE)) +#define UNITY_IS_FILTER_BASIC_BUTTON_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_FILTER_BASIC_BUTTON_ACCESSIBLE)) +#define UNITY_FILTER_BASIC_BUTTON_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_FILTER_BASIC_BUTTON_ACCESSIBLE, UnityFilterBasicButtonAccessibleClass)) + +typedef struct _UnityFilterBasicButtonAccessible UnityFilterBasicButtonAccessible; +typedef struct _UnityFilterBasicButtonAccessibleClass UnityFilterBasicButtonAccessibleClass; + +struct _UnityFilterBasicButtonAccessible +{ + NuxViewAccessible parent; +}; + +struct _UnityFilterBasicButtonAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_filter_basic_button_accessible_get_type(void); +AtkObject* unity_filter_basic_button_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_FILTER_BASIC_BUTTON_ACCESSIBLE_H__ */ diff --git a/a11y/unity-launcher-accessible.cpp b/a11y/unity-launcher-accessible.cpp new file mode 100644 index 000000000..182ad524f --- /dev/null +++ b/a11y/unity-launcher-accessible.cpp @@ -0,0 +1,451 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-launcher-accessible + * @Title: UnityLauncherAccessible + * @short_description: Implementation of the ATK interfaces for #Launcher + * @see_also: Launcher + * + * #UnityLauncherAccessible implements the required ATK interfaces for + * #Launcher, ie: exposing the different AbstractLauncherIcon on the model as + * #child of the object. + * + */ + +#include <glib/gi18n.h> + +#include "unity-launcher-accessible.h" +#include "unity-launcher-icon-accessible.h" + +#include "unitya11y.h" +#include "Launcher.h" +#include "LauncherModel.h" + +using unity::launcher::Launcher; +using unity::launcher::AbstractLauncherIcon; +using unity::launcher::LauncherModel; + +/* GObject */ +static void unity_launcher_accessible_class_init(UnityLauncherAccessibleClass* klass); +static void unity_launcher_accessible_init(UnityLauncherAccessible* self); +static void unity_launcher_accessible_finalize(GObject* object); + +/* AtkObject.h */ +static void unity_launcher_accessible_initialize(AtkObject* accessible, + gpointer data); +static gint unity_launcher_accessible_get_n_children(AtkObject* obj); +static AtkObject* unity_launcher_accessible_ref_child(AtkObject* obj, + gint i); +static AtkStateSet* unity_launcher_accessible_ref_state_set(AtkObject* obj); + +/* AtkSelection */ +static void atk_selection_interface_init(AtkSelectionIface* iface); +static AtkObject* unity_launcher_accessible_ref_selection(AtkSelection* selection, + gint i); +static gint unity_launcher_accessible_get_selection_count(AtkSelection* selection); +static gboolean unity_launcher_accessible_is_child_selected(AtkSelection* selection, + gint i); + +/* private */ +static void on_selection_change_cb(AbstractLauncherIcon::Ptr const& selection, UnityLauncherAccessible* launcher_accessible); +static void on_icon_added_cb(AbstractLauncherIcon::Ptr const& icon, UnityLauncherAccessible* self); +static void on_icon_removed_cb(AbstractLauncherIcon::Ptr const& icon, UnityLauncherAccessible* self); +static void on_order_change_cb(UnityLauncherAccessible* self); +static void update_children_index(UnityLauncherAccessible* self); + +G_DEFINE_TYPE_WITH_CODE(UnityLauncherAccessible, unity_launcher_accessible, NUX_TYPE_VIEW_ACCESSIBLE, + G_IMPLEMENT_INTERFACE(ATK_TYPE_SELECTION, atk_selection_interface_init)) + +#define UNITY_LAUNCHER_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_LAUNCHER_ACCESSIBLE, \ + UnityLauncherAccessiblePrivate)) + +struct _UnityLauncherAccessiblePrivate +{ + sigc::connection on_selection_change_connection; + sigc::connection on_icon_added_connection; + sigc::connection on_icon_removed_connection; + sigc::connection on_order_changed_connection; +}; + + +static void +unity_launcher_accessible_class_init(UnityLauncherAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->finalize = unity_launcher_accessible_finalize; + + /* AtkObject */ + atk_class->get_n_children = unity_launcher_accessible_get_n_children; + atk_class->ref_child = unity_launcher_accessible_ref_child; + atk_class->initialize = unity_launcher_accessible_initialize; + atk_class->ref_state_set = unity_launcher_accessible_ref_state_set; + + g_type_class_add_private(gobject_class, sizeof(UnityLauncherAccessiblePrivate)); +} + +static void +unity_launcher_accessible_init(UnityLauncherAccessible* self) +{ + UnityLauncherAccessiblePrivate* priv = + UNITY_LAUNCHER_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; +} + +static void +unity_launcher_accessible_finalize(GObject* object) +{ + UnityLauncherAccessible* self = UNITY_LAUNCHER_ACCESSIBLE(object); + + self->priv->on_selection_change_connection.disconnect(); + self->priv->on_icon_added_connection.disconnect(); + self->priv->on_icon_removed_connection.disconnect(); + self->priv->on_order_changed_connection.disconnect(); + + G_OBJECT_CLASS(unity_launcher_accessible_parent_class)->finalize(object); +} + +AtkObject* +unity_launcher_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<Launcher*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_LAUNCHER_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + atk_object_set_name(accessible, _("Launcher")); + + return accessible; +} + +/* AtkObject.h */ +static void +unity_launcher_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + Launcher* launcher = NULL; + nux::Object* nux_object = NULL; + UnityLauncherAccessible* self = NULL; + LauncherModel::Ptr model = NULL; + + ATK_OBJECT_CLASS(unity_launcher_accessible_parent_class)->initialize(accessible, data); + + accessible->role = ATK_ROLE_TOOL_BAR; + + self = UNITY_LAUNCHER_ACCESSIBLE(accessible); + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + + launcher = static_cast<Launcher*>(nux_object); + model = launcher->GetModel(); + + if (model) + { + self->priv->on_selection_change_connection = + model->selection_changed.connect(sigc::bind(sigc::ptr_fun(on_selection_change_cb), self)); + + self->priv->on_icon_added_connection = + model->icon_added.connect(sigc::bind(sigc::ptr_fun(on_icon_added_cb), self)); + + self->priv->on_icon_removed_connection = + model->icon_removed.connect(sigc::bind(sigc::ptr_fun(on_icon_removed_cb), self)); + + self->priv->on_order_changed_connection = + model->order_changed.connect(sigc::bind(sigc::ptr_fun(on_order_change_cb), self)); + } +} + +static gint +unity_launcher_accessible_get_n_children(AtkObject* obj) +{ + nux::Object* object = NULL; + Launcher* launcher = NULL; + LauncherModel::Ptr launcher_model; + + g_return_val_if_fail(UNITY_IS_LAUNCHER_ACCESSIBLE(obj), 0); + + object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + if (!object) /* state is defunct */ + return 0; + + launcher = static_cast<Launcher*>(object); + + launcher_model = launcher->GetModel(); + + if (launcher_model) + return launcher_model->Size(); + else + return 0; +} + +static AtkObject* +unity_launcher_accessible_ref_child(AtkObject* obj, + gint i) +{ + gint num = 0; + nux::Object* nux_object = NULL; + Launcher* launcher = NULL; + LauncherModel::Ptr launcher_model; + LauncherModel::iterator it; + nux::Object* child = NULL; + AtkObject* child_accessible = NULL; + AtkObject* parent = NULL; + + g_return_val_if_fail(UNITY_IS_LAUNCHER_ACCESSIBLE(obj), NULL); + num = atk_object_get_n_accessible_children(obj); + g_return_val_if_fail((i < num) && (i >= 0), NULL); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + if (!nux_object) /* state is defunct */ + return 0; + + launcher = static_cast<Launcher*>(nux_object); + launcher_model = launcher->GetModel(); + + it = launcher_model->begin(); + std::advance(it, i); + + child = dynamic_cast<nux::Object*>((*it).GetPointer()); + child_accessible = unity_a11y_get_accessible(child); + + parent = atk_object_get_parent(child_accessible); + if (parent != obj) + atk_object_set_parent(child_accessible, obj); + + g_object_ref(child_accessible); + + return child_accessible; +} + +static AtkStateSet* +unity_launcher_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_LAUNCHER_ACCESSIBLE(obj), NULL); + + state_set = + ATK_OBJECT_CLASS(unity_launcher_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + + if (nux_object == NULL) /* defunct */ + return state_set; + + /* The Launcher is always focusable */ + atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); + + return state_set; +} + +/* AtkSelection */ +static void +atk_selection_interface_init(AtkSelectionIface* iface) +{ + iface->ref_selection = unity_launcher_accessible_ref_selection; + iface->get_selection_count = unity_launcher_accessible_get_selection_count; + iface->is_child_selected = unity_launcher_accessible_is_child_selected; + + /* NOTE: for the moment we don't provide the implementation for the + "interactable" methods, it is, the methods that allow to change + the selected icon. The Launcher doesn't provide that API, and + right now we are focusing on a normal user input.*/ + /* iface->add_selection = unity_launcher_accessible_add_selection; */ + /* iface->clear_selection = unity_launcher_accessible_clear_selection; */ + /* iface->remove_selection = unity_launcher_accessible_remove_selection; */ + + /* This method will never be implemented, as select all the launcher + icons makes no sense */ + /* iface->select_all = unity_launcher_accessible_select_all_selection; */ +} + +static AtkObject* +unity_launcher_accessible_ref_selection(AtkSelection* selection, + gint i) +{ + Launcher* launcher = NULL; + nux::Object* nux_object = NULL; + AtkObject* accessible_selected = NULL; + + g_return_val_if_fail(UNITY_IS_LAUNCHER_ACCESSIBLE(selection), 0); + /* there can be only just item selected */ + g_return_val_if_fail(i == 0, NULL); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection)); + if (!nux_object) /* state is defunct */ + return 0; + + launcher = static_cast<Launcher*>(nux_object); + AbstractLauncherIcon::Ptr const& selected_icon = launcher->GetSelectedMenuIcon(); + + if (selected_icon) + { + accessible_selected = unity_a11y_get_accessible(selected_icon.GetPointer()); + g_object_ref(accessible_selected); + } + + return accessible_selected; +} + +static gint +unity_launcher_accessible_get_selection_count(AtkSelection* selection) +{ + Launcher* launcher = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_LAUNCHER_ACCESSIBLE(selection), 0); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection)); + if (!nux_object) /* state is defunct */ + return 0; + + launcher = static_cast<Launcher*>(nux_object); + + if (!launcher->GetSelectedMenuIcon()) + return 0; + else + return 1; +} + +static gboolean +unity_launcher_accessible_is_child_selected(AtkSelection* selection, + gint i) +{ + Launcher* launcher = NULL; + LauncherModel::iterator it; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_LAUNCHER_ACCESSIBLE(selection), FALSE); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection)); + if (!nux_object) /* state is defunct */ + return 0; + + launcher = static_cast<Launcher*>(nux_object); + LauncherModel::Ptr const& launcher_model = launcher->GetModel(); + it = launcher_model->begin(); + std::advance(it, i); + + AbstractLauncherIcon::Ptr const& selected_icon = launcher->GetSelectedMenuIcon(); + + if (selected_icon == *it) + return TRUE; + else + return FALSE; +} + +/* private */ +static void on_selection_change_cb(AbstractLauncherIcon::Ptr const& selection, UnityLauncherAccessible* launcher_accessible) +{ + g_signal_emit_by_name(ATK_OBJECT(launcher_accessible), "selection-changed"); +} + + +static void +on_icon_added_cb(AbstractLauncherIcon::Ptr const& icon, + UnityLauncherAccessible* self) +{ + AtkObject* icon_accessible = NULL; + nux::Object* nux_object = NULL; + gint index = 0; + + g_return_if_fail(UNITY_IS_LAUNCHER_ACCESSIBLE(self)); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + if (nux_object == NULL) /* state is defunct */ + return; + + icon_accessible = unity_a11y_get_accessible(icon.GetPointer()); + atk_object_set_parent(icon_accessible, ATK_OBJECT(self)); + + update_children_index(self); + + index = atk_object_get_index_in_parent(icon_accessible); + + g_signal_emit_by_name(self, "children-changed::add", + index, icon_accessible, NULL); +} + +static void +on_icon_removed_cb(AbstractLauncherIcon::Ptr const& icon, + UnityLauncherAccessible* self) +{ + AtkObject* icon_accessible = NULL; + nux::Object* nux_object = NULL; + gint index = 0; + + g_return_if_fail(UNITY_IS_LAUNCHER_ACCESSIBLE(self)); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + if (nux_object == NULL) /* state is defunct */ + return; + + icon_accessible = unity_a11y_get_accessible(icon.GetPointer()); + + index = atk_object_get_index_in_parent(icon_accessible); + + g_signal_emit_by_name(self, "children-changed::remove", + index, icon_accessible, NULL); + + update_children_index(self); +} + +static void +update_children_index(UnityLauncherAccessible* self) +{ + gint index = 0; + nux::Object* nux_object = NULL; + Launcher* launcher = NULL; + LauncherModel::Ptr launcher_model; + LauncherModel::iterator it; + nux::Object* child = NULL; + AtkObject* child_accessible = NULL; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + if (!nux_object) /* state is defunct */ + return; + + launcher = static_cast<Launcher*>(nux_object); + launcher_model = launcher->GetModel(); + + if (launcher_model == NULL) + return; + + for (it = launcher_model->begin(); it != launcher_model->end(); ++it) + { + child = dynamic_cast<nux::Object*>((*it).GetPointer()); + child_accessible = unity_a11y_get_accessible(child); + + unity_launcher_icon_accessible_set_index(UNITY_LAUNCHER_ICON_ACCESSIBLE(child_accessible), + index++); + } +} + +static void +on_order_change_cb(UnityLauncherAccessible* self) +{ + g_return_if_fail(UNITY_IS_LAUNCHER_ACCESSIBLE(self)); + + update_children_index(self); +} diff --git a/a11y/unity-launcher-accessible.h b/a11y/unity-launcher-accessible.h new file mode 100644 index 000000000..faa9817a2 --- /dev/null +++ b/a11y/unity-launcher-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_LAUNCHER_ACCESSIBLE_H +#define UNITY_LAUNCHER_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_LAUNCHER_ACCESSIBLE (unity_launcher_accessible_get_type ()) +#define UNITY_LAUNCHER_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_LAUNCHER_ACCESSIBLE, UnityLauncherAccessible)) +#define UNITY_LAUNCHER_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_LAUNCHER_ACCESSIBLE, UnityLauncherAccessibleClass)) +#define UNITY_IS_LAUNCHER_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_LAUNCHER_ACCESSIBLE)) +#define UNITY_IS_LAUNCHER_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_LAUNCHER_ACCESSIBLE)) +#define UNITY_LAUNCHER_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_LAUNCHER_ACCESSIBLE, UnityLauncherAccessibleClass)) + +typedef struct _UnityLauncherAccessible UnityLauncherAccessible; +typedef struct _UnityLauncherAccessibleClass UnityLauncherAccessibleClass; +typedef struct _UnityLauncherAccessiblePrivate UnityLauncherAccessiblePrivate; + +struct _UnityLauncherAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnityLauncherAccessiblePrivate* priv; +}; + +struct _UnityLauncherAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_launcher_accessible_get_type(void); +AtkObject* unity_launcher_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_LAUNCHER_ACCESSIBLE_H__ */ diff --git a/a11y/unity-launcher-icon-accessible.cpp b/a11y/unity-launcher-icon-accessible.cpp new file mode 100644 index 000000000..8afb4e823 --- /dev/null +++ b/a11y/unity-launcher-icon-accessible.cpp @@ -0,0 +1,554 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:nux-launcher_icon-accessible + * @Title: UnityLauncherIconAccessible + * @short_description: Implementation of the ATK interfaces for #nux::LauncherIcon + * @see_also: nux::LauncherIcon + * + * #UnityLauncherIconAccessible implements the required ATK interfaces of + * nux::LauncherIcon, exposing the common elements on each basic individual + * element (position, extents, etc) + * + * Implementation notes: on previous implementations we implemented + * _get_parent using the LauncherIcon method GetLauncher. But this is + * not the case in all the situations. When the user is interacting + * with the Switcher, we consider that the parent of that LauncherIcon + * is the Switcher. + * + * The parent is set with atk_object_set_parent as usual. + * + * As this object is used both on UnityLauncherAccessible and + * UnitySwitcherAccessible, we have removed as much as possible any + * reference to the Launcher, LauncherModel, SwitcherView or + * SwitcherModel. + * + */ + +#include <glib/gi18n.h> + +#include "unity-launcher-icon-accessible.h" +#include "unity-launcher-accessible.h" +#include "Launcher.h" +#include "LauncherIcon.h" + +#include "unitya11y.h" + +using namespace unity::launcher; + +/* GObject */ +static void unity_launcher_icon_accessible_class_init(UnityLauncherIconAccessibleClass* klass); +static void unity_launcher_icon_accessible_init(UnityLauncherIconAccessible* launcher_icon_accessible); +static void unity_launcher_icon_accessible_dispose(GObject* object); + + +/* AtkObject.h */ +static void unity_launcher_icon_accessible_initialize(AtkObject* accessible, + gpointer data); +static AtkStateSet* unity_launcher_icon_accessible_ref_state_set(AtkObject* obj); +static const gchar* unity_launcher_icon_accessible_get_name(AtkObject* obj); +// static AtkObject* unity_launcher_icon_accessible_get_parent(AtkObject* obj); +static gint unity_launcher_icon_accessible_get_index_in_parent(AtkObject* obj); + +/* AtkComponent.h */ +static void atk_component_interface_init(AtkComponentIface* iface); +static guint unity_launcher_icon_accessible_add_focus_handler(AtkComponent* component, + AtkFocusHandler handler); +static void unity_launcher_icon_accessible_remove_focus_handler(AtkComponent* component, + guint handler_id); +static void unity_launcher_icon_accessible_focus_handler(AtkObject* accessible, + gboolean focus_in); + +/* AtkAction */ +static void atk_action_interface_init(AtkActionIface *iface); +static gboolean unity_launcher_icon_accessible_do_action(AtkAction *action, + gint i); +static gint unity_launcher_icon_accessible_get_n_actions(AtkAction *action); +static const gchar* unity_launcher_icon_accessible_get_name(AtkAction *action, + gint i); + +/* private/utility methods*/ +static void check_selected(UnityLauncherIconAccessible* self); +static void on_parent_selection_change_cb(AtkSelection* selection, + gpointer data); +static void on_parent_focus_event_cb(AtkObject* object, + gboolean in, + gpointer data); + +G_DEFINE_TYPE_WITH_CODE(UnityLauncherIconAccessible, + unity_launcher_icon_accessible, + NUX_TYPE_OBJECT_ACCESSIBLE, + G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT, + atk_component_interface_init) + G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION, + atk_action_interface_init)) + +#define UNITY_LAUNCHER_ICON_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_LAUNCHER_ICON_ACCESSIBLE, \ + UnityLauncherIconAccessiblePrivate)) + +struct _UnityLauncherIconAccessiblePrivate +{ + /* Cached values (used to avoid extra notifications) */ + gboolean selected; + gboolean parent_focused; + gboolean index_in_parent; + + guint on_parent_change_id; + guint on_parent_selection_change_id; + guint on_parent_focus_event_id; + + /* A textual representation of the icon's name and its quirks */ + gchar* name; +}; + +static void +unity_launcher_icon_accessible_class_init(UnityLauncherIconAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->dispose = unity_launcher_icon_accessible_dispose; + + /* AtkObject */ + atk_class->initialize = unity_launcher_icon_accessible_initialize; + atk_class->get_name = unity_launcher_icon_accessible_get_name; + atk_class->ref_state_set = unity_launcher_icon_accessible_ref_state_set; + // atk_class->get_parent = unity_launcher_icon_accessible_get_parent; + atk_class->get_index_in_parent = unity_launcher_icon_accessible_get_index_in_parent; + + g_type_class_add_private(gobject_class, sizeof(UnityLauncherIconAccessiblePrivate)); +} + +static void +unity_launcher_icon_accessible_init(UnityLauncherIconAccessible* launcher_icon_accessible) +{ + UnityLauncherIconAccessiblePrivate* priv = + UNITY_LAUNCHER_ICON_ACCESSIBLE_GET_PRIVATE(launcher_icon_accessible); + + launcher_icon_accessible->priv = priv; + launcher_icon_accessible->priv->name = NULL; +} + +static void +unity_launcher_icon_accessible_dispose(GObject* object) +{ + UnityLauncherIconAccessible* self = UNITY_LAUNCHER_ICON_ACCESSIBLE(object); + AtkObject* parent = NULL; + + parent = atk_object_get_parent(ATK_OBJECT(object)); + + if (parent != NULL) + { + if (self->priv->on_parent_selection_change_id != 0) + g_signal_handler_disconnect(parent, self->priv->on_parent_selection_change_id); + + if (self->priv->on_parent_focus_event_id != 0) + g_signal_handler_disconnect(parent, self->priv->on_parent_focus_event_id); + } + + if (self->priv->on_parent_change_id != 0) + g_signal_handler_disconnect(object, self->priv->on_parent_change_id); + + if (self->priv->name != NULL) + { + g_free(self->priv->name); + self->priv->name = NULL; + } + + G_OBJECT_CLASS(unity_launcher_icon_accessible_parent_class)->dispose(object); +} + + +AtkObject* +unity_launcher_icon_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<LauncherIcon*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_LAUNCHER_ICON_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +on_parent_change_cb(gchar* property, + GValue* value, + gpointer data) +{ + AtkObject* parent = NULL; + UnityLauncherIconAccessible* self = NULL; + AtkStateSet* state_set = NULL; + + g_return_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(data)); + + self = UNITY_LAUNCHER_ICON_ACCESSIBLE(data); + parent = atk_object_get_parent(ATK_OBJECT(data)); + + if (parent == NULL) + return; + + self->priv->on_parent_selection_change_id = + g_signal_connect(parent, "selection-changed", + G_CALLBACK(on_parent_selection_change_cb), self); + + self->priv->on_parent_focus_event_id = + g_signal_connect(parent, "focus-event", + G_CALLBACK(on_parent_focus_event_cb), self); + + state_set = atk_object_ref_state_set(parent); + if (atk_state_set_contains_state(state_set, ATK_STATE_FOCUSED)) + { + self->priv->parent_focused = TRUE; + } + g_object_unref(state_set); +} + +static void +on_quirks_change_cb(UnityLauncherIconAccessible* self) +{ + g_object_notify(G_OBJECT(self), "accessible-name"); +} + +static void +unity_launcher_icon_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + UnityLauncherIconAccessible* self = NULL; + nux::Object* object = NULL; + LauncherIcon* icon = NULL; + + ATK_OBJECT_CLASS(unity_launcher_icon_accessible_parent_class)->initialize(accessible, data); + self = UNITY_LAUNCHER_ICON_ACCESSIBLE(accessible); + object = (nux::Object*) data; + icon = dynamic_cast<LauncherIcon*>(object); + + accessible->role = ATK_ROLE_PUSH_BUTTON; + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + atk_component_add_focus_handler(ATK_COMPONENT(accessible), + unity_launcher_icon_accessible_focus_handler); +G_GNUC_END_IGNORE_DEPRECATIONS + + /* we could do that by redefining ->set_parent */ + self->priv->on_parent_change_id = + g_signal_connect(accessible, "notify::accessible-parent", + G_CALLBACK(on_parent_change_cb), self); + + icon->quirks_changed.connect(sigc::hide(sigc::hide(sigc::bind(sigc::ptr_fun(on_quirks_change_cb), self)))); + icon->windows_changed.connect(sigc::hide(sigc::bind(sigc::ptr_fun(on_quirks_change_cb), self))); +} + + +static const gchar* +unity_launcher_icon_accessible_get_name(AtkObject* obj) +{ + UnityLauncherIconAccessible* self = NULL; + + g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(obj), NULL); + self = UNITY_LAUNCHER_ICON_ACCESSIBLE(obj); + + if (self->priv->name != NULL) + { + g_free(self->priv->name); + self->priv->name = NULL; + } + + self->priv->name = g_strdup(ATK_OBJECT_CLASS(unity_launcher_icon_accessible_parent_class)->get_name(obj)); + if (self->priv->name == NULL) + { + LauncherIcon* icon = NULL; + Launcher* launcher = NULL; + + icon = dynamic_cast<LauncherIcon*>(nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj))); + launcher = dynamic_cast<Launcher*>(nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(atk_object_get_parent(obj)))); + + if (icon == NULL) /* State is defunct */ + self->priv->name = NULL; + else + { + /* We do not want to present the running state of apps in the switcher, + * Because showing in the switcher implies they are running + */ + if (launcher == NULL) + self->priv->name = g_strdup(icon->tooltip_text().c_str()); + else + { + if (icon->GetQuirk(LauncherIcon::Quirk::RUNNING)) + if (icon->Windows().size() > 0) + self->priv->name = g_strdup_printf(_("%s: running: %zu windows open"), + icon->tooltip_text().c_str(), + icon->Windows().size()); + else + self->priv->name = g_strdup_printf(_("%s: running"), icon->tooltip_text().c_str()); + else + self->priv->name = g_strdup(icon->tooltip_text().c_str()); + } + } + } + + return self->priv->name; +} + +static AtkStateSet* +unity_launcher_icon_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + UnityLauncherIconAccessible* self = NULL; + nux::Object* nux_object = NULL; + LauncherIcon* icon = NULL; + + g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(obj), NULL); + self = UNITY_LAUNCHER_ICON_ACCESSIBLE(obj); + + state_set = ATK_OBJECT_CLASS(unity_launcher_icon_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + + if (nux_object == NULL) /* defunct */ + return state_set; + + /* by default */ + atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); + atk_state_set_add_state(state_set, ATK_STATE_ENABLED); + atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE); + + icon = dynamic_cast<LauncherIcon*>(nux_object); + + if (icon->GetQuirk(LauncherIcon::Quirk::VISIBLE)) + { + atk_state_set_add_state(state_set, ATK_STATE_VISIBLE); + atk_state_set_add_state(state_set, ATK_STATE_SHOWING); + } + + if (self->priv->selected) + { + atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); + atk_state_set_add_state(state_set, ATK_STATE_SELECTED); + atk_state_set_add_state(state_set, ATK_STATE_ACTIVE); + } + + return state_set; +} + +/* private methods */ + +/* + * Checks if the current item is selected, and notify a selection + * change if the selection has changed + */ +static void +check_selected(UnityLauncherIconAccessible* self) +{ + AtkObject* parent = NULL; + gboolean found = FALSE; + + parent = atk_object_get_parent(ATK_OBJECT(self)); + if (parent == NULL) + return; + + found = atk_selection_is_child_selected(ATK_SELECTION(parent), + self->priv->index_in_parent); + + if ((found) && (self->priv->parent_focused == FALSE)) + return; + + if (found != self->priv->selected) + { + gboolean return_val = FALSE; + + self->priv->selected = found; + atk_object_notify_state_change(ATK_OBJECT(self), + ATK_STATE_SELECTED, + found); + atk_object_notify_state_change(ATK_OBJECT(self), + ATK_STATE_ACTIVE, + found); + + g_signal_emit_by_name(self, "focus-event", self->priv->selected, &return_val); + atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_FOCUSED, self->priv->selected); + } +} + +static void +on_parent_selection_change_cb(AtkSelection* selection, + gpointer data) +{ + g_return_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(data)); + + check_selected(UNITY_LAUNCHER_ICON_ACCESSIBLE(data)); +} + + +static void +on_parent_focus_event_cb(AtkObject* object, + gboolean in, + gpointer data) +{ + UnityLauncherIconAccessible* self = NULL; + + g_return_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(data)); + + self = UNITY_LAUNCHER_ICON_ACCESSIBLE(data); + self->priv->parent_focused = in; + + /* we check the selection stuff again, to report the focus change + now */ + check_selected(self); +} + +/* AtkComponent.h */ + +static void +atk_component_interface_init(AtkComponentIface* iface) +{ + g_return_if_fail(iface != NULL); + + /* focus management */ + iface->add_focus_handler = unity_launcher_icon_accessible_add_focus_handler; + iface->remove_focus_handler = unity_launcher_icon_accessible_remove_focus_handler; + + /* FIXME: still missing the size and position methods. Remember that + * this is not a nux::Area, and probably we would require to poke + * the Launcher to get those positions + */ +} + +/* + * comment C&P from cally-actor: + * + * "These methods are basically taken from gail, as I don't see any + * reason to modify it. It makes me wonder why it is really required + * to be implemented in the toolkit" + */ + +static guint +unity_launcher_icon_accessible_add_focus_handler(AtkComponent* component, + AtkFocusHandler handler) +{ + GSignalMatchType match_type; + gulong ret; + guint signal_id; + + g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(component), 0); + + match_type = (GSignalMatchType)(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC); + signal_id = g_signal_lookup("focus-event", ATK_TYPE_OBJECT); + + ret = g_signal_handler_find(component, match_type, signal_id, 0, NULL, + (gpointer) handler, NULL); + if (!ret) + { + return g_signal_connect_closure_by_id(component, + signal_id, 0, + g_cclosure_new(G_CALLBACK(handler), NULL, + (GClosureNotify) NULL), + FALSE); + } + else + return 0; +} + +static void +unity_launcher_icon_accessible_remove_focus_handler(AtkComponent* component, + guint handler_id) +{ + g_return_if_fail(NUX_IS_VIEW_ACCESSIBLE(component)); + + g_signal_handler_disconnect(component, handler_id); +} + +static void +unity_launcher_icon_accessible_focus_handler(AtkObject* accessible, + gboolean focus_in) +{ + g_return_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(accessible)); + + atk_object_notify_state_change(accessible, ATK_STATE_FOCUSED, focus_in); +} + +static gint +unity_launcher_icon_accessible_get_index_in_parent(AtkObject* obj) +{ + g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(obj), -1); + + return UNITY_LAUNCHER_ICON_ACCESSIBLE(obj)->priv->index_in_parent; +} + +/* AtkAction */ +static void +atk_action_interface_init(AtkActionIface *iface) +{ + iface->do_action = unity_launcher_icon_accessible_do_action; + iface->get_n_actions = unity_launcher_icon_accessible_get_n_actions; + iface->get_name = unity_launcher_icon_accessible_get_name; +} + +static gboolean +unity_launcher_icon_accessible_do_action(AtkAction *action, + gint i) +{ + LauncherIcon* icon = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(action), FALSE); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(action)); + if (nux_object == NULL) + return FALSE; + + icon = dynamic_cast<LauncherIcon*>(nux_object); + + icon->Activate(ActionArg(ActionArg::Source::LAUNCHER, 0)); + + return TRUE; +} + +static gint +unity_launcher_icon_accessible_get_n_actions(AtkAction *action) +{ + g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(action), 0); + + return 1; +} + +static const gchar* +unity_launcher_icon_accessible_get_name(AtkAction *action, + gint i) +{ + g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(action), NULL); + g_return_val_if_fail(i == 0, NULL); + + return "activate"; +} + +/* Public */ + +void +unity_launcher_icon_accessible_set_index(UnityLauncherIconAccessible* self, + gint index) +{ + g_return_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(self)); + + self->priv->index_in_parent = index; +} diff --git a/a11y/unity-launcher-icon-accessible.h b/a11y/unity-launcher-icon-accessible.h new file mode 100644 index 000000000..94cd7cc13 --- /dev/null +++ b/a11y/unity-launcher-icon-accessible.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_LAUNCHER_ICON_ACCESSIBLE_H +#define UNITY_LAUNCHER_ICON_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-object-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_LAUNCHER_ICON_ACCESSIBLE (unity_launcher_icon_accessible_get_type ()) +#define UNITY_LAUNCHER_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_LAUNCHER_ICON_ACCESSIBLE, UnityLauncherIconAccessible)) +#define UNITY_LAUNCHER_ICON_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_LAUNCHER_ICON_ACCESSIBLE, UnityLauncherIconAccessibleClass)) +#define UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_LAUNCHER_ICON_ACCESSIBLE)) +#define UNITY_IS_LAUNCHER_ICON_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_LAUNCHER_ICON_ACCESSIBLE)) +#define UNITY_LAUNCHER_ICON_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_LAUNCHER_ICON_ACCESSIBLE, UnityLauncherIconAccessibleClass)) + +typedef struct _UnityLauncherIconAccessible UnityLauncherIconAccessible; +typedef struct _UnityLauncherIconAccessibleClass UnityLauncherIconAccessibleClass; +typedef struct _UnityLauncherIconAccessiblePrivate UnityLauncherIconAccessiblePrivate; + +struct _UnityLauncherIconAccessible +{ + NuxObjectAccessible parent; + + /*< private >*/ + UnityLauncherIconAccessiblePrivate* priv; +}; + +struct _UnityLauncherIconAccessibleClass +{ + NuxObjectAccessibleClass parent_class; +}; + +GType unity_launcher_icon_accessible_get_type(void); +AtkObject* unity_launcher_icon_accessible_new(nux::Object* object); + +void unity_launcher_icon_accessible_set_index(UnityLauncherIconAccessible* self, + gint index); + +G_END_DECLS + +#endif /* __UNITY_LAUNCHER_ICON_ACCESSIBLE_H__ */ diff --git a/a11y/unity-panel-view-accessible.cpp b/a11y/unity-panel-view-accessible.cpp new file mode 100644 index 000000000..4b23e7e4c --- /dev/null +++ b/a11y/unity-panel-view-accessible.cpp @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Rodrigo Moya <rodrigo.moya@canonical.com> + */ + +/** + * SECTION:unity-panel-view-accessible + * @Title: UnityPanelViewAccessible + * @short_description: Implementation of the ATK interfaces for #PanelView + * @see_also: PanelView + * + * #UnityPanelViewAccessible implements the required ATK interfaces for + * #PanelView, ie: exposing the different items contained in the panel + * as children. + * + */ + +#include "config.h" +#include "unitya11y.h" + +#include <glib/gi18n-lib.h> +#include <Nux/Nux.h> +#include "PanelView.h" +#include "unity-panel-view-accessible.h" + +using namespace unity::panel; + +/* GObject */ +static void unity_panel_view_accessible_class_init(UnityPanelViewAccessibleClass* klass); +static void unity_panel_view_accessible_init(UnityPanelViewAccessible* self); + +/* AtkObject */ +static void unity_panel_view_accessible_initialize(AtkObject* accessible, gpointer data); +static gint unity_panel_view_accessible_get_n_children(AtkObject* accessible); +static AtkObject* unity_panel_view_accessible_ref_child(AtkObject* accessible, gint i); + +G_DEFINE_TYPE(UnityPanelViewAccessible, unity_panel_view_accessible, NUX_TYPE_VIEW_ACCESSIBLE) + +static void +unity_panel_view_accessible_class_init(UnityPanelViewAccessibleClass* klass) +{ + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* AtkObject */ + atk_class->initialize = unity_panel_view_accessible_initialize; + atk_class->get_n_children = unity_panel_view_accessible_get_n_children; + atk_class->ref_child = unity_panel_view_accessible_ref_child; +} + +static void +unity_panel_view_accessible_init(UnityPanelViewAccessible* self) +{ +} + +AtkObject* +unity_panel_view_accessible_new(nux::Object* object) +{ + AtkObject* accessible; + + g_return_val_if_fail(dynamic_cast<PanelView*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_PANEL_VIEW_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +static void +unity_panel_view_accessible_initialize(AtkObject* accessible, gpointer data) +{ + ATK_OBJECT_CLASS(unity_panel_view_accessible_parent_class)->initialize(accessible, data); + + accessible->role = ATK_ROLE_PANEL; +} + +static gint +unity_panel_view_accessible_get_n_children(AtkObject* accessible) +{ + nux::Object* nux_object = NULL; + gint rc = 0; + + g_return_val_if_fail(UNITY_IS_PANEL_VIEW_ACCESSIBLE(accessible), 0); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + if (!nux_object) /* state is defunct */ + return 0; + + return rc; +} + +static AtkObject* +unity_panel_view_accessible_ref_child(AtkObject* accessible, gint i) +{ + nux::Object* nux_object = NULL; + AtkObject* child_accessible = NULL; + + g_return_val_if_fail(UNITY_IS_PANEL_VIEW_ACCESSIBLE(accessible), NULL); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + if (!nux_object) /* state is defunct */ + return NULL; + + return child_accessible; +} diff --git a/a11y/unity-panel-view-accessible.h b/a11y/unity-panel-view-accessible.h new file mode 100644 index 000000000..dcca2e899 --- /dev/null +++ b/a11y/unity-panel-view-accessible.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Rodrigo Moya <rodrigo.moya@canonical.com> + */ + +#ifndef UNITY_PANEL_VIEW_ACCESSIBLE_H +#define UNITY_PANEL_VIEW_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_PANEL_VIEW_ACCESSIBLE (unity_panel_view_accessible_get_type ()) +#define UNITY_PANEL_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_PANEL_VIEW_ACCESSIBLE, UnityPanelViewAccessible)) +#define UNITY_PANEL_VIEW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_PANEL_VIEW_ACCESSIBLE, UnityPanelViewAccessibleClass)) +#define UNITY_IS_PANEL_VIEW_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_PANEL_VIEW_ACCESSIBLE)) +#define UNITY_IS_PANEL_VIEW_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_PANEL_VIEW_ACCESSIBLE)) +#define UNITY_PANEL_VIEW_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_PANEL_VIEW_ACCESSIBLE, UnityPanelViewAccessibleClass)) + +typedef struct _UnityPanelViewAccessible UnityPanelViewAccessible; +typedef struct _UnityPanelViewAccessibleClass UnityPanelViewAccessibleClass; + +struct _UnityPanelViewAccessible +{ + NuxViewAccessible parent; +}; + +struct _UnityPanelViewAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_panel_view_accessible_get_type(void); +AtkObject* unity_panel_view_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif diff --git a/a11y/unity-places-group-accessible.cpp b/a11y/unity-places-group-accessible.cpp new file mode 100644 index 000000000..8abfe78fa --- /dev/null +++ b/a11y/unity-places-group-accessible.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-places_group-accessible + * @Title: UnityPlacesGroupAccessible + * @short_description: Implementation of the ATK interfaces for #PlacesGroup + * @see_also: PlacesGroup + * + * #UnityPlacesGroupAccessible implements the required ATK interfaces for + * #PlacesGroup, mainly exposing the text as his name, as this + * #object is mainly used as a label + * + */ + +#include <glib/gi18n.h> + +#include "unity-places-group-accessible.h" + +#include "unitya11y.h" +#include "PlacesGroup.h" + +/* GObject */ +static void unity_places_group_accessible_class_init(UnityPlacesGroupAccessibleClass* klass); +static void unity_places_group_accessible_init(UnityPlacesGroupAccessible* self); + +/* AtkObject.h */ +static void unity_places_group_accessible_initialize(AtkObject* accessible, + gpointer data); + +G_DEFINE_TYPE(UnityPlacesGroupAccessible, unity_places_group_accessible, NUX_TYPE_VIEW_ACCESSIBLE); + + +#define UNITY_PLACES_GROUP_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_PLACES_GROUP_ACCESSIBLE, \ + UnityPlacesGroupAccessiblePrivate)) + +struct _UnityPlacesGroupAccessiblePrivate +{ + gchar* stripped_name; +}; + + +static void +unity_places_group_accessible_class_init(UnityPlacesGroupAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* AtkObject */ + atk_class->initialize = unity_places_group_accessible_initialize; + + g_type_class_add_private(gobject_class, sizeof(UnityPlacesGroupAccessiblePrivate)); +} + +static void +unity_places_group_accessible_init(UnityPlacesGroupAccessible* self) +{ + UnityPlacesGroupAccessiblePrivate* priv = + UNITY_PLACES_GROUP_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; + priv->stripped_name = NULL; +} + +AtkObject* +unity_places_group_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<unity::dash::PlacesGroup*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_PLACES_GROUP_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +/* expand label are usually focused during the key nav, but it don't + * get a proper name always. In those cases we use the label. + * + * In the same way, it is possible that the PlacesGroup get focused + * so we also set the own name with this label + */ +static void +ensure_proper_name(UnityPlacesGroupAccessible* self) +{ + unity::dash::PlacesGroup* group = NULL; + nux::Object* nux_object = NULL; + unity::StaticCairoText* label = NULL; + unity::StaticCairoText* expand_label = NULL; + AtkObject* label_accessible = NULL; + AtkObject* expand_label_accessible = NULL; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + group = dynamic_cast<unity::dash::PlacesGroup*>(nux_object); + + if (group == NULL) + return; + + label = group->GetLabel(); + expand_label = group->GetExpandLabel(); + + + label_accessible = unity_a11y_get_accessible(label); + expand_label_accessible = unity_a11y_get_accessible(expand_label); + + if ((label_accessible == NULL) || (expand_label_accessible == NULL)) + return; + + atk_object_set_name(ATK_OBJECT(self), atk_object_get_name(label_accessible)); + + if (expand_label->GetText() == "") + atk_object_set_name(expand_label_accessible, atk_object_get_name(label_accessible)); +} + + +static void +on_label_text_change_cb(unity::StaticCairoText* label, UnityPlacesGroupAccessible* self) +{ + ensure_proper_name(self); +} + +static void +unity_places_group_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + unity::dash::PlacesGroup* group = NULL; + nux::Object* nux_object = NULL; + unity::StaticCairoText* label = NULL; + + ATK_OBJECT_CLASS(unity_places_group_accessible_parent_class)->initialize(accessible, data); + + atk_object_set_role(accessible, ATK_ROLE_PANEL); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + group = dynamic_cast<unity::dash::PlacesGroup*>(nux_object); + + if (group == NULL) + return; + + label = group->GetLabel(); + + if (label == NULL) + return; + + ensure_proper_name(UNITY_PLACES_GROUP_ACCESSIBLE(accessible)); + label->sigTextChanged.connect(sigc::bind(sigc::ptr_fun(on_label_text_change_cb), + UNITY_PLACES_GROUP_ACCESSIBLE(accessible))); +} + diff --git a/a11y/unity-places-group-accessible.h b/a11y/unity-places-group-accessible.h new file mode 100644 index 000000000..594c9a219 --- /dev/null +++ b/a11y/unity-places-group-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_PLACES_GROUP_ACCESSIBLE_H +#define UNITY_PLACES_GROUP_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_PLACES_GROUP_ACCESSIBLE (unity_places_group_accessible_get_type ()) +#define UNITY_PLACES_GROUP_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_PLACES_GROUP_ACCESSIBLE, UnityPlacesGroupAccessible)) +#define UNITY_PLACES_GROUP_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_PLACES_GROUP_ACCESSIBLE, UnityPlacesGroupAccessibleClass)) +#define UNITY_IS_PLACES_GROUP_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_PLACES_GROUP_ACCESSIBLE)) +#define UNITY_IS_PLACES_GROUP_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_PLACES_GROUP_ACCESSIBLE)) +#define UNITY_PLACES_GROUP_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_PLACES_GROUP_ACCESSIBLE, UnityPlacesGroupAccessibleClass)) + +typedef struct _UnityPlacesGroupAccessible UnityPlacesGroupAccessible; +typedef struct _UnityPlacesGroupAccessibleClass UnityPlacesGroupAccessibleClass; +typedef struct _UnityPlacesGroupAccessiblePrivate UnityPlacesGroupAccessiblePrivate; + +struct _UnityPlacesGroupAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnityPlacesGroupAccessiblePrivate* priv; +}; + +struct _UnityPlacesGroupAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_places_group_accessible_get_type(void); +AtkObject* unity_places_group_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_PLACES_GROUP_ACCESSIBLE_H__ */ diff --git a/a11y/unity-quicklist-accessible.cpp b/a11y/unity-quicklist-accessible.cpp new file mode 100644 index 000000000..eaebd8bf4 --- /dev/null +++ b/a11y/unity-quicklist-accessible.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-quicklist-accessible + * @Title: UnityQuicklistAccessible + * @short_description: Implementation of the ATK interfaces for #QuicklistView + * @see_also: QuicklistView + * + * #UnityQuicklistAccessible implements the required ATK interfaces for + * #QuicklistView. + * + * IMPLEMENTATION NOTES: + * + * The desired accessible object hierarchy is the following one: + * Role:menu + * Role:menu-item + * Role:menu-item. + * + * But this quicklist is also a base window, so we can't set a role + * menu, and then keeping it sending window messages. + * + * So a new object, with role menu will be added to the hierarchy: + * QuicklistMenu. It also hide the intermediate container objects. + * + * So we will have: + * Role:window (the quicklist itself) + * Role:menu (a dummy object having the role menu) + * Role:menuitem (From QuicklistView->GetChildren) + * Role:menuitem + * + */ + +#include <glib/gi18n.h> + +#include "unity-quicklist-accessible.h" +#include "unity-quicklist-menu-accessible.h" + +#include "unitya11y.h" +#include "Launcher.h" /*without this I get a error with the following include*/ +#include "QuicklistView.h" + +/* GObject */ +static void unity_quicklist_accessible_class_init(UnityQuicklistAccessibleClass* klass); +static void unity_quicklist_accessible_init(UnityQuicklistAccessible* self); + +/* AtkObject.h */ +static void unity_quicklist_accessible_initialize(AtkObject* accessible, + gpointer data); +static gint unity_quicklist_accessible_get_n_children(AtkObject* obj); +static AtkObject* unity_quicklist_accessible_ref_child(AtkObject* obj, + gint i); + +G_DEFINE_TYPE(UnityQuicklistAccessible, unity_quicklist_accessible, NUX_TYPE_BASE_WINDOW_ACCESSIBLE); + + +#define UNITY_QUICKLIST_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_QUICKLIST_ACCESSIBLE, \ + UnityQuicklistAccessiblePrivate)) + +struct _UnityQuicklistAccessiblePrivate +{ + AtkObject* menu_accessible; +}; + +using unity::QuicklistView; + +static void +unity_quicklist_accessible_class_init(UnityQuicklistAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* AtkObject */ + atk_class->initialize = unity_quicklist_accessible_initialize; + atk_class->get_n_children = unity_quicklist_accessible_get_n_children; + atk_class->ref_child = unity_quicklist_accessible_ref_child; + + g_type_class_add_private(gobject_class, sizeof(UnityQuicklistAccessiblePrivate)); +} + +static void +unity_quicklist_accessible_init(UnityQuicklistAccessible* self) +{ + UnityQuicklistAccessiblePrivate* priv = + UNITY_QUICKLIST_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; + priv->menu_accessible = NULL; +} + +AtkObject* +unity_quicklist_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<QuicklistView*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_QUICKLIST_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +unity_quicklist_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + QuicklistView* quicklist = NULL; + + ATK_OBJECT_CLASS(unity_quicklist_accessible_parent_class)->initialize(accessible, data); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + quicklist = dynamic_cast<QuicklistView*>(nux_object); + + if (quicklist == NULL) /* status defunct */ + return; +} + +static gint +unity_quicklist_accessible_get_n_children(AtkObject* obj) +{ + QuicklistView* quicklist = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_QUICKLIST_ACCESSIBLE(obj), 0); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + quicklist = dynamic_cast<QuicklistView*>(nux_object); + + if (quicklist == NULL) + return 0; + else + return 1; +} + +static AtkObject* +unity_quicklist_accessible_ref_child(AtkObject* obj, + gint i) +{ + UnityQuicklistAccessible* self = NULL; + QuicklistView* quicklist = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_QUICKLIST_ACCESSIBLE(obj), NULL); + self = UNITY_QUICKLIST_ACCESSIBLE(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + quicklist = dynamic_cast<QuicklistView*>(nux_object); + if (quicklist == NULL) + return NULL; + + if (self->priv->menu_accessible == NULL) + { + self->priv->menu_accessible = unity_quicklist_menu_accessible_new(quicklist); + atk_object_set_parent(self->priv->menu_accessible, ATK_OBJECT(self)); + } + + g_object_ref(self->priv->menu_accessible); + + return self->priv->menu_accessible; +} diff --git a/a11y/unity-quicklist-accessible.h b/a11y/unity-quicklist-accessible.h new file mode 100644 index 000000000..e1a30b85c --- /dev/null +++ b/a11y/unity-quicklist-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_QUICKLIST_ACCESSIBLE_H +#define UNITY_QUICKLIST_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-base-window-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_QUICKLIST_ACCESSIBLE (unity_quicklist_accessible_get_type ()) +#define UNITY_QUICKLIST_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_QUICKLIST_ACCESSIBLE, UnityQuicklistAccessible)) +#define UNITY_QUICKLIST_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_QUICKLIST_ACCESSIBLE, UnityQuicklistAccessibleClass)) +#define UNITY_IS_QUICKLIST_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_QUICKLIST_ACCESSIBLE)) +#define UNITY_IS_QUICKLIST_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_QUICKLIST_ACCESSIBLE)) +#define UNITY_QUICKLIST_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_QUICKLIST_ACCESSIBLE, UnityQuicklistAccessibleClass)) + +typedef struct _UnityQuicklistAccessible UnityQuicklistAccessible; +typedef struct _UnityQuicklistAccessibleClass UnityQuicklistAccessibleClass; +typedef struct _UnityQuicklistAccessiblePrivate UnityQuicklistAccessiblePrivate; + +struct _UnityQuicklistAccessible +{ + NuxBaseWindowAccessible parent; + + /*< private >*/ + UnityQuicklistAccessiblePrivate* priv; +}; + +struct _UnityQuicklistAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_quicklist_accessible_get_type(void); +AtkObject* unity_quicklist_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_QUICKLIST_ACCESSIBLE_H__ */ diff --git a/a11y/unity-quicklist-menu-accessible.cpp b/a11y/unity-quicklist-menu-accessible.cpp new file mode 100644 index 000000000..8967b4738 --- /dev/null +++ b/a11y/unity-quicklist-menu-accessible.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-quicklist-accessible + * @Title: UnityQuicklistMenuAccessible + * @short_description: Implementation of the ATK interfaces for #QuicklistView as a menu + * @see_also: QuicklistView + * + * #UnityQuicklistAccessible implements the required ATK interfaces for + * #QuicklistView, exposing himself as a menu. + * + * Note that this object is a QuicklistAccessible delegated object. If + * you call unitya11y->get_accessible with a Quicklist it will return + * a QuicklistAccessible. QuicklistMenuAccessible should only be + * instantiated by QuicklistAccessible + * + * IMPLEMENTATION NOTES: + * + * The desired accessible object hierarchy is the following one: + * Role:menu + * Role:menu-item + * Role:menu-item. + * + * But this quicklist is also a base window, so we can't set a role + * menu, and then keeping it sending window messages. + * + * So a new object, with role menu will be added to the hierarchy: + * QuicklistMenu. It also hide the intermediate container objects. + * + * So we will have: + * Role:window (the quicklist itself) + * Role:menu (a dummy object having the role menu) + * Role:menuitem (From QuicklistView->GetChildren) + * Role:menuitem + * + */ + +#include <glib/gi18n.h> + +#include "unity-quicklist-menu-accessible.h" + +#include "unitya11y.h" +#include "Launcher.h" /*without this I get a error with the following include*/ +#include "QuicklistView.h" + +/* GObject */ +static void unity_quicklist_menu_accessible_class_init(UnityQuicklistMenuAccessibleClass* klass); +static void unity_quicklist_menu_accessible_init(UnityQuicklistMenuAccessible* self); +static void unity_quicklist_menu_accessible_finalize(GObject* object); + +/* AtkObject.h */ +static void unity_quicklist_menu_accessible_initialize(AtkObject* accessible, + gpointer data); +static gint unity_quicklist_menu_accessible_get_n_children(AtkObject* obj); +static AtkObject* unity_quicklist_menu_accessible_ref_child(AtkObject* obj, + gint i); + +/* AtkSelection */ +static void atk_selection_interface_init(AtkSelectionIface* iface); +static AtkObject* unity_quicklist_menu_accessible_ref_selection(AtkSelection* selection, + gint i); +static gint unity_quicklist_menu_accessible_get_selection_count(AtkSelection* selection); +static gboolean unity_quicklist_menu_accessible_is_child_selected(AtkSelection* selection, + gint i); +/* private */ +static void on_selection_change_cb(UnityQuicklistMenuAccessible* self); +static void on_parent_activate_change_cb(AtkObject* parent_window, + UnityQuicklistMenuAccessible* self); +static void on_parent_change_cb(gchar* property, + GValue* value, + gpointer data); + +G_DEFINE_TYPE_WITH_CODE(UnityQuicklistMenuAccessible, + unity_quicklist_menu_accessible, NUX_TYPE_OBJECT_ACCESSIBLE, + G_IMPLEMENT_INTERFACE(ATK_TYPE_SELECTION, atk_selection_interface_init)); + + +#define UNITY_QUICKLIST_MENU_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_QUICKLIST_MENU_ACCESSIBLE, \ + UnityQuicklistMenuAccessiblePrivate)) + +struct _UnityQuicklistMenuAccessiblePrivate +{ + sigc::connection on_selection_change_connection; + guint on_parent_change_id; + guint on_parent_activate_change_id; +}; + +using unity::QuicklistView; +using unity::QuicklistMenuItem; + +static void +unity_quicklist_menu_accessible_class_init(UnityQuicklistMenuAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->finalize = unity_quicklist_menu_accessible_finalize; + + /* AtkObject */ + atk_class->initialize = unity_quicklist_menu_accessible_initialize; + atk_class->get_n_children = unity_quicklist_menu_accessible_get_n_children; + atk_class->ref_child = unity_quicklist_menu_accessible_ref_child; + + g_type_class_add_private(gobject_class, sizeof(UnityQuicklistMenuAccessiblePrivate)); +} + +static void +unity_quicklist_menu_accessible_init(UnityQuicklistMenuAccessible* self) +{ + UnityQuicklistMenuAccessiblePrivate* priv = + UNITY_QUICKLIST_MENU_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; +} + +static void +unity_quicklist_menu_accessible_finalize(GObject* object) +{ + UnityQuicklistMenuAccessible* self = UNITY_QUICKLIST_MENU_ACCESSIBLE(object); + + self->priv->on_selection_change_connection.disconnect(); + + if (self->priv->on_parent_change_id != 0) + g_signal_handler_disconnect(object, self->priv->on_parent_change_id); + + G_OBJECT_CLASS(unity_quicklist_menu_accessible_parent_class)->finalize(object); +} + +AtkObject* +unity_quicklist_menu_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<QuicklistView*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_QUICKLIST_MENU_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +unity_quicklist_menu_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + QuicklistView* quicklist = NULL; + UnityQuicklistMenuAccessible* self = NULL; + + ATK_OBJECT_CLASS(unity_quicklist_menu_accessible_parent_class)->initialize(accessible, data); + self = UNITY_QUICKLIST_MENU_ACCESSIBLE(accessible); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + quicklist = dynamic_cast<QuicklistView*>(nux_object); + + if (quicklist == NULL) /* status defunct */ + return; + + atk_object_set_role(accessible, ATK_ROLE_MENU); + atk_object_set_name(accessible, _("Quicklist")); + + self->priv->on_selection_change_connection = + quicklist->selection_change.connect(sigc::bind(sigc::ptr_fun(on_selection_change_cb), self)); + + self->priv->on_parent_change_id = + g_signal_connect(accessible, "notify::accessible-parent", + G_CALLBACK(on_parent_change_cb), self); +} + +static gint +unity_quicklist_menu_accessible_get_n_children(AtkObject* obj) +{ + QuicklistView* quicklist = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_QUICKLIST_MENU_ACCESSIBLE(obj), 0); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + quicklist = dynamic_cast<QuicklistView*>(nux_object); + + if (quicklist == NULL) + return 0; + + return quicklist->GetNumItems(); +} + +static AtkObject* +unity_quicklist_menu_accessible_ref_child(AtkObject* obj, + gint i) +{ + QuicklistView* quicklist = NULL; + QuicklistMenuItem* child = NULL; + AtkObject* child_accessible = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_QUICKLIST_MENU_ACCESSIBLE(obj), NULL); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + quicklist = dynamic_cast<QuicklistView*>(nux_object); + + if (quicklist == NULL) + return NULL; + + child = quicklist->GetNthItems(i); + child_accessible = unity_a11y_get_accessible(child); + + if (child_accessible != NULL) + { + AtkObject* parent = NULL; + g_object_ref(child_accessible); + parent = atk_object_get_parent(child_accessible); + if (parent != obj) + atk_object_set_parent(child_accessible, obj); + } + + return child_accessible; +} + +/* AtkSelection */ +static void +atk_selection_interface_init(AtkSelectionIface* iface) +{ + iface->ref_selection = unity_quicklist_menu_accessible_ref_selection; + iface->get_selection_count = unity_quicklist_menu_accessible_get_selection_count; + iface->is_child_selected = unity_quicklist_menu_accessible_is_child_selected; + + /* NOTE: for the moment we don't provide the implementation for the + "interactable" methods, it is, the methods that allow to change + the selected icon. The QuicklistView doesn't provide that API, and + right now we are focusing on a normal user input.*/ +} + +static AtkObject* +unity_quicklist_menu_accessible_ref_selection(AtkSelection* selection, + gint i) +{ + QuicklistView* quicklist = NULL; + QuicklistMenuItem* child = NULL; + AtkObject* child_accessible = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_QUICKLIST_MENU_ACCESSIBLE(selection), NULL); + /* there can be only one item selected */ + g_return_val_if_fail(i == 0, NULL); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection)); + quicklist = dynamic_cast<QuicklistView*>(nux_object); + + if (quicklist == NULL) /*state is defunct */ + return NULL; + + child = quicklist->GetSelectedMenuItem(); + + if (child != NULL) + { + child_accessible = unity_a11y_get_accessible(child); + + if (child_accessible != NULL) + g_object_ref(child_accessible); + } + + return child_accessible; +} + +static gint +unity_quicklist_menu_accessible_get_selection_count(AtkSelection* selection) +{ + QuicklistView* quicklist = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_QUICKLIST_MENU_ACCESSIBLE(selection), 0); + + /* + * Looking at QuicklistView code, there is always one item selected, + * anyway we check that there is at least one item + */ + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection)); + quicklist = dynamic_cast<QuicklistView*>(nux_object); + + if (quicklist == NULL) /*state is defunct */ + return 0; + + if (quicklist->GetNumItems() > 0) + return 1; + else + return 0; +} + +static gboolean +unity_quicklist_menu_accessible_is_child_selected(AtkSelection* selection, + gint i) +{ + QuicklistView* quicklist = NULL; + QuicklistMenuItem* selected = NULL; + QuicklistMenuItem* ith_item = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_QUICKLIST_MENU_ACCESSIBLE(selection), FALSE); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection)); + quicklist = dynamic_cast<QuicklistView*>(nux_object); + + if (quicklist == NULL) /*state is defunct */ + return FALSE; + + selected = quicklist->GetSelectedMenuItem(); + ith_item = quicklist->GetNthItems(i); + + if (selected == ith_item) + return TRUE; + else + return FALSE; +} + +/* private */ +static void +on_selection_change_cb(UnityQuicklistMenuAccessible* self) +{ + g_signal_emit_by_name(ATK_OBJECT(self), "selection-changed"); +} + +static void +on_parent_activate_change_cb(AtkObject* parent_window, + UnityQuicklistMenuAccessible* self) +{ + /* We consider that when our parent window is activated, the focus + should be on the menu, specifically on one of the menu-item. So + we emit a selection-change in order to notify that a selection + was made */ + g_signal_emit_by_name(ATK_OBJECT(self), "selection-changed"); +} + + +static void +on_parent_change_cb(gchar* property, + GValue* value, + gpointer data) +{ + AtkObject* parent = NULL; + UnityQuicklistMenuAccessible* self = NULL; + + g_return_if_fail(UNITY_IS_QUICKLIST_MENU_ACCESSIBLE(data)); + self = UNITY_QUICKLIST_MENU_ACCESSIBLE(data); + + parent = atk_object_get_parent(ATK_OBJECT(self)); + + if (parent == NULL) + return; + + self->priv->on_parent_activate_change_id = + g_signal_connect(parent, "activate", + G_CALLBACK(on_parent_activate_change_cb), self); +} + diff --git a/a11y/unity-quicklist-menu-accessible.h b/a11y/unity-quicklist-menu-accessible.h new file mode 100644 index 000000000..99aeab75a --- /dev/null +++ b/a11y/unity-quicklist-menu-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_QUICKLIST_MENU_ACCESSIBLE_H +#define UNITY_QUICKLIST_MENU_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-base-window-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_QUICKLIST_MENU_ACCESSIBLE (unity_quicklist_menu_accessible_get_type ()) +#define UNITY_QUICKLIST_MENU_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_QUICKLIST_MENU_ACCESSIBLE, UnityQuicklistMenuAccessible)) +#define UNITY_QUICKLIST_MENU_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_QUICKLIST_MENU_ACCESSIBLE, UnityQuicklistMenuAccessibleClass)) +#define UNITY_IS_QUICKLIST_MENU_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_QUICKLIST_MENU_ACCESSIBLE)) +#define UNITY_IS_QUICKLIST_MENU_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_QUICKLIST_MENU_ACCESSIBLE)) +#define UNITY_QUICKLIST_MENU_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_QUICKLIST_MENU_ACCESSIBLE, UnityQuicklistMenuAccessibleClass)) + +typedef struct _UnityQuicklistMenuAccessible UnityQuicklistMenuAccessible; +typedef struct _UnityQuicklistMenuAccessibleClass UnityQuicklistMenuAccessibleClass; +typedef struct _UnityQuicklistMenuAccessiblePrivate UnityQuicklistMenuAccessiblePrivate; + +struct _UnityQuicklistMenuAccessible +{ + NuxObjectAccessible parent; + + /*< private >*/ + UnityQuicklistMenuAccessiblePrivate* priv; +}; + +struct _UnityQuicklistMenuAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_quicklist_menu_accessible_get_type(void); +AtkObject* unity_quicklist_menu_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_QUICKLIST_MENU_ACCESSIBLE_H__ */ diff --git a/a11y/unity-quicklist-menu-item-accessible.cpp b/a11y/unity-quicklist-menu-item-accessible.cpp new file mode 100644 index 000000000..97bc898cc --- /dev/null +++ b/a11y/unity-quicklist-menu-item-accessible.cpp @@ -0,0 +1,319 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-quicklist_menu_item-accessible + * @Title: UnityQuicklistMenuItemAccessible + * @short_description: Implementation of the ATK interfaces for #QuicklistMenuItem + * @see_also: QuicklistMenuItem + * + * #UnityQuicklistMenuItemAccessible implements the required ATK interfaces for + * #QuicklistMenuItem, mainly exposing the text as his name, as this + * #object is mainly used as a label + * + */ + +#include <glib/gi18n.h> + +#include "unity-quicklist-menu-item-accessible.h" + +#include "unitya11y.h" +#include "QuicklistMenuItem.h" +#include "QuicklistMenuItemLabel.h" +#include "QuicklistMenuItemSeparator.h" + +/* GObject */ +static void unity_quicklist_menu_item_accessible_class_init(UnityQuicklistMenuItemAccessibleClass* klass); +static void unity_quicklist_menu_item_accessible_init(UnityQuicklistMenuItemAccessible* self); +static void unity_quicklist_menu_item_accessible_dispose(GObject* object); + +/* AtkObject.h */ +static void unity_quicklist_menu_item_accessible_initialize(AtkObject* accessible, + gpointer data); +static const gchar* unity_quicklist_menu_item_accessible_get_name(AtkObject* obj); +static AtkStateSet* unity_quicklist_menu_item_accessible_ref_state_set(AtkObject* obj); + +/* private */ +static void on_parent_selection_change_cb(AtkSelection* selection, + gpointer data); + +G_DEFINE_TYPE(UnityQuicklistMenuItemAccessible, unity_quicklist_menu_item_accessible, NUX_TYPE_VIEW_ACCESSIBLE); + + +#define UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_QUICKLIST_MENU_ITEM_ACCESSIBLE, \ + UnityQuicklistMenuItemAccessiblePrivate)) + +struct _UnityQuicklistMenuItemAccessiblePrivate +{ + gboolean selected; + + guint on_parent_selection_change_id; + guint on_parent_change_id; + + gchar *name; +}; + +using unity::QuicklistMenuItem; +using unity::QuicklistMenuItemLabel; +using unity::QuicklistMenuItemSeparator; + +static void +unity_quicklist_menu_item_accessible_class_init(UnityQuicklistMenuItemAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->dispose = unity_quicklist_menu_item_accessible_dispose; + + /* AtkObject */ + atk_class->get_name = unity_quicklist_menu_item_accessible_get_name; + atk_class->initialize = unity_quicklist_menu_item_accessible_initialize; + atk_class->ref_state_set = unity_quicklist_menu_item_accessible_ref_state_set; + + g_type_class_add_private(gobject_class, sizeof(UnityQuicklistMenuItemAccessiblePrivate)); +} + +static void +unity_quicklist_menu_item_accessible_init(UnityQuicklistMenuItemAccessible* self) +{ + UnityQuicklistMenuItemAccessiblePrivate* priv = + UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; + self->priv->name = NULL; +} + +static void +unity_quicklist_menu_item_accessible_dispose(GObject* object) +{ + UnityQuicklistMenuItemAccessible* self = UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE(object); + AtkObject* parent = NULL; + + parent = atk_object_get_parent(ATK_OBJECT(object)); + + if (UNITY_IS_QUICKLIST_MENU_ITEM_ACCESSIBLE(parent)) + { + if (self->priv->on_parent_selection_change_id != 0) + g_signal_handler_disconnect(parent, self->priv->on_parent_selection_change_id); + } + + if (self->priv->on_parent_change_id != 0) + g_signal_handler_disconnect(object, self->priv->on_parent_change_id); + + if (self->priv->name != NULL) + { + g_free(self->priv->name); + self->priv->name = NULL; + } + + G_OBJECT_CLASS(unity_quicklist_menu_item_accessible_parent_class)->dispose(object); +} + +AtkObject* +unity_quicklist_menu_item_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<QuicklistMenuItem*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_QUICKLIST_MENU_ITEM_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static gboolean +menu_item_is_a_separator(QuicklistMenuItem* menu_item) +{ + QuicklistMenuItemSeparator* separator = NULL; + + separator = dynamic_cast<QuicklistMenuItemSeparator*>(menu_item); + + if (separator != NULL) + return TRUE; + else + return FALSE; +} + +static void +on_parent_change_cb(gchar* property, + GValue* value, + gpointer data) +{ + AtkObject* parent = NULL; + UnityQuicklistMenuItemAccessible* self = NULL; + + g_return_if_fail(UNITY_IS_QUICKLIST_MENU_ITEM_ACCESSIBLE(data)); + self = UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE(data); + + parent = atk_object_get_parent(ATK_OBJECT(self)); + + if (parent == NULL) + return; + + self->priv->on_parent_selection_change_id = + g_signal_connect(parent, "selection-changed", + G_CALLBACK(on_parent_selection_change_cb), self); +} + +static void +unity_quicklist_menu_item_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + QuicklistMenuItem* menu_item = NULL; + UnityQuicklistMenuItemAccessible* self = NULL; + + ATK_OBJECT_CLASS(unity_quicklist_menu_item_accessible_parent_class)->initialize(accessible, data); + self = UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE(accessible); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + menu_item = dynamic_cast<QuicklistMenuItem*>(nux_object); + + if (menu_item == NULL) + return; + + if (menu_item_is_a_separator(menu_item)) + atk_object_set_role(accessible, ATK_ROLE_SEPARATOR); + else + atk_object_set_role(accessible, ATK_ROLE_MENU_ITEM); + + /* we could do that by redefining ->set_parent */ + self->priv->on_parent_change_id = + g_signal_connect(accessible, "notify::accessible-parent", + G_CALLBACK(on_parent_change_cb), self); +} + + + +static const gchar* +unity_quicklist_menu_item_accessible_get_name(AtkObject* obj) +{ + g_return_val_if_fail(UNITY_IS_QUICKLIST_MENU_ITEM_ACCESSIBLE(obj), NULL); + UnityQuicklistMenuItemAccessible *self = UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE(obj); + + if (self->priv->name) + { + g_free(self->priv->name); + self->priv->name = NULL; + } + + self->priv->name = g_strdup(ATK_OBJECT_CLASS(unity_quicklist_menu_item_accessible_parent_class)->get_name(obj)); + if (self->priv->name == NULL) + { + QuicklistMenuItem* menu_item = NULL; + + menu_item = dynamic_cast<QuicklistMenuItem*>(nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj))); + if (menu_item != NULL) + { + self->priv->name = g_strdup(menu_item->GetPlainTextLabel().c_str()); + } + } + + return self->priv->name; +} + +static AtkStateSet* +unity_quicklist_menu_item_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + UnityQuicklistMenuItemAccessible* self = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_QUICKLIST_MENU_ITEM_ACCESSIBLE(obj), NULL); + self = UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE(obj); + + state_set = ATK_OBJECT_CLASS(unity_quicklist_menu_item_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + + if (nux_object == NULL) /* defunct */ + return state_set; + + /* by default */ + atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); + atk_state_set_add_state(state_set, ATK_STATE_ENABLED); + atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE); + + if (self->priv->selected) + { + atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); + atk_state_set_add_state(state_set, ATK_STATE_SELECTED); + atk_state_set_add_state(state_set, ATK_STATE_ACTIVE); + } + else + { + /* we clean the states that could come from NuxAreaAccessible */ + atk_state_set_remove_state(state_set, ATK_STATE_FOCUSED); + } + + return state_set; +} + +/* private */ +static void +check_selected(UnityQuicklistMenuItemAccessible* self) +{ + AtkObject* selected_item = NULL; + AtkObject* parent = NULL; + nux::Object* nux_object = NULL; + gboolean found = FALSE; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + if (nux_object == NULL) /* state is defunct */ + return; + + parent = atk_object_get_parent(ATK_OBJECT(self)); + if (parent == NULL) + return; + + selected_item = atk_selection_ref_selection(ATK_SELECTION(parent), 0); + + if (ATK_OBJECT(self) == selected_item) + found = TRUE; + + if (found != self->priv->selected) + { + gboolean return_val = FALSE; + + self->priv->selected = found; + atk_object_notify_state_change(ATK_OBJECT(self), + ATK_STATE_FOCUSED, + found); + atk_object_notify_state_change(ATK_OBJECT(self), + ATK_STATE_SELECTED, + found); + atk_object_notify_state_change(ATK_OBJECT(self), + ATK_STATE_ACTIVE, + found); + + g_signal_emit_by_name(self, "focus-event", self->priv->selected, &return_val); + } +} + +static void +on_parent_selection_change_cb(AtkSelection* selection, + gpointer data) +{ + g_return_if_fail(UNITY_IS_QUICKLIST_MENU_ITEM_ACCESSIBLE(data)); + + check_selected(UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE(data)); +} diff --git a/a11y/unity-quicklist-menu-item-accessible.h b/a11y/unity-quicklist-menu-item-accessible.h new file mode 100644 index 000000000..5c0c2b3b1 --- /dev/null +++ b/a11y/unity-quicklist-menu-item-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE_H +#define UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_QUICKLIST_MENU_ITEM_ACCESSIBLE (unity_quicklist_menu_item_accessible_get_type ()) +#define UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_QUICKLIST_MENU_ITEM_ACCESSIBLE, UnityQuicklistMenuItemAccessible)) +#define UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_QUICKLIST_MENU_ITEM_ACCESSIBLE, UnityQuicklistMenuItemAccessibleClass)) +#define UNITY_IS_QUICKLIST_MENU_ITEM_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_QUICKLIST_MENU_ITEM_ACCESSIBLE)) +#define UNITY_IS_QUICKLIST_MENU_ITEM_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_QUICKLIST_MENU_ITEM_ACCESSIBLE)) +#define UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_QUICKLIST_MENU_ITEM_ACCESSIBLE, UnityQuicklistMenuItemAccessibleClass)) + +typedef struct _UnityQuicklistMenuItemAccessible UnityQuicklistMenuItemAccessible; +typedef struct _UnityQuicklistMenuItemAccessibleClass UnityQuicklistMenuItemAccessibleClass; +typedef struct _UnityQuicklistMenuItemAccessiblePrivate UnityQuicklistMenuItemAccessiblePrivate; + +struct _UnityQuicklistMenuItemAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnityQuicklistMenuItemAccessiblePrivate* priv; +}; + +struct _UnityQuicklistMenuItemAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_quicklist_menu_item_accessible_get_type(void); +AtkObject* unity_quicklist_menu_item_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_QUICKLIST_MENU_ITEM_ACCESSIBLE_H__ */ diff --git a/a11y/unity-result-accessible.cpp b/a11y/unity-result-accessible.cpp new file mode 100644 index 000000000..b2f431e18 --- /dev/null +++ b/a11y/unity-result-accessible.cpp @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:nux-result-accessible + * @Title: UnityResultAccessible + * @short_description: Implementation of the ATK interfaces for a #Result + * @see_also: unity::dash::Result + * + * #UnityResultAccessible implements the required ATK interfaces of + * nux::Result, in order to represent each one of the elements of a + * ResultGrid. + * + * The idea is having it as a fly-weight object. Note: it represents + * it, but it doesn't maintain a reference to it. + * + */ + +#include "unity-result-accessible.h" +#include "unity-rvgrid-accessible.h" + +#include "unitya11y.h" + +/* GObject */ +static void unity_result_accessible_class_init(UnityResultAccessibleClass* klass); +static void unity_result_accessible_init(UnityResultAccessible* result_accessible); + +/* AtkObject.h */ +static void unity_result_accessible_initialize(AtkObject* accessible, + gpointer data); +static AtkStateSet* unity_result_accessible_ref_state_set(AtkObject* obj); + +G_DEFINE_TYPE(UnityResultAccessible, + unity_result_accessible, + ATK_TYPE_OBJECT); + +#define UNITY_RESULT_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_RESULT_ACCESSIBLE, \ + UnityResultAccessiblePrivate)) + +struct _UnityResultAccessiblePrivate +{ +}; + +static void +unity_result_accessible_class_init(UnityResultAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* AtkObject */ + atk_class->initialize = unity_result_accessible_initialize; + atk_class->ref_state_set = unity_result_accessible_ref_state_set; + + g_type_class_add_private(gobject_class, sizeof(UnityResultAccessiblePrivate)); +} + +static void +unity_result_accessible_init(UnityResultAccessible* result_accessible) +{ + UnityResultAccessiblePrivate* priv = + UNITY_RESULT_ACCESSIBLE_GET_PRIVATE(result_accessible); + + result_accessible->priv = priv; +} + +AtkObject* +unity_result_accessible_new() +{ + AtkObject* accessible = NULL; + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_RESULT_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, NULL); + + return accessible; +} + +/* AtkObject.h */ +static void +unity_result_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + ATK_OBJECT_CLASS(unity_result_accessible_parent_class)->initialize(accessible, data); + + /* On unity Result is just data, but on the accessible + implementation we are using this object to represent each icon + selected on the result grid, so a push button */ + atk_object_set_role(accessible, ATK_ROLE_PUSH_BUTTON); +} + +static AtkStateSet* +unity_result_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + + g_return_val_if_fail(UNITY_IS_RESULT_ACCESSIBLE(obj), NULL); + + state_set = ATK_OBJECT_CLASS(unity_result_accessible_parent_class)->ref_state_set(obj); + + /* by default, this is a fly-weight/dummy object, so if created we have + this information */ + atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); + atk_state_set_add_state(state_set, ATK_STATE_ENABLED); + atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE); + + atk_state_set_add_state(state_set, ATK_STATE_VISIBLE); + atk_state_set_add_state(state_set, ATK_STATE_SHOWING); + + /* This object is not focused, the focused is the parent + ResultViewGrid */ + // atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); + atk_state_set_add_state(state_set, ATK_STATE_SELECTED); + atk_state_set_add_state(state_set, ATK_STATE_ACTIVE); + + return state_set; +} diff --git a/a11y/unity-result-accessible.h b/a11y/unity-result-accessible.h new file mode 100644 index 000000000..764a4c70c --- /dev/null +++ b/a11y/unity-result-accessible.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_LAUNCHER_ICON_ACCESSIBLE_H +#define UNITY_LAUNCHER_ICON_ACCESSIBLE_H + +#include <atk/atk.h> + +G_BEGIN_DECLS + +#define UNITY_TYPE_RESULT_ACCESSIBLE (unity_result_accessible_get_type ()) +#define UNITY_RESULT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_RESULT_ACCESSIBLE, UnityResultAccessible)) +#define UNITY_RESULT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_RESULT_ACCESSIBLE, UnityResultAccessibleClass)) +#define UNITY_IS_RESULT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_RESULT_ACCESSIBLE)) +#define UNITY_IS_RESULT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_RESULT_ACCESSIBLE)) +#define UNITY_RESULT_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_RESULT_ACCESSIBLE, UnityResultAccessibleClass)) + +typedef struct _UnityResultAccessible UnityResultAccessible; +typedef struct _UnityResultAccessibleClass UnityResultAccessibleClass; +typedef struct _UnityResultAccessiblePrivate UnityResultAccessiblePrivate; + +struct _UnityResultAccessible +{ + AtkObject parent; + + /*< private >*/ + UnityResultAccessiblePrivate* priv; +}; + +struct _UnityResultAccessibleClass +{ + AtkObjectClass parent_class; +}; + +GType unity_result_accessible_get_type(void); +AtkObject* unity_result_accessible_new(); + + +G_END_DECLS + +#endif /* __UNITY_RESULT_ACCESSIBLE_H__ */ diff --git a/a11y/unity-root-accessible.cpp b/a11y/unity-root-accessible.cpp new file mode 100644 index 000000000..92dd63cd9 --- /dev/null +++ b/a11y/unity-root-accessible.cpp @@ -0,0 +1,365 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-accessible-root + * @short_description: Root object for the UNITY accessible support + * + * #UnityRootAccessible is the root object of the accessibility + * tree-like hierarchy, exposing the application level. You can see it + * as the one exposing UnityScreen information to the a11y framework + * + */ + +#include "unity-root-accessible.h" +#include "unity-util-accessible.h" +#include "nux-base-window-accessible.h" +#include "unitya11y.h" + +#include <UnityCore/Variant.h> + +#include "UBusWrapper.h" +#include "UBusMessages.h" + +/* GObject */ +static void unity_root_accessible_class_init(UnityRootAccessibleClass* klass); +static void unity_root_accessible_init(UnityRootAccessible* root); +static void unity_root_accessible_finalize(GObject* object); + +/* AtkObject.h */ +static void unity_root_accessible_initialize(AtkObject* accessible, + gpointer data); +static gint unity_root_accessible_get_n_children(AtkObject* obj); +static AtkObject* unity_root_accessible_ref_child(AtkObject* obj, + gint i); +static AtkObject* unity_root_accessible_get_parent(AtkObject* obj); +/* private */ +static void check_active_window(UnityRootAccessible* self); +static void register_interesting_messages(UnityRootAccessible* self); +static void add_window(UnityRootAccessible* self, + nux::BaseWindow* window); +static void remove_window(UnityRootAccessible* self, + nux::BaseWindow* window); + +#define UNITY_ROOT_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_ROOT_ACCESSIBLE, UnityRootAccessiblePrivate)) + +G_DEFINE_TYPE(UnityRootAccessible, unity_root_accessible, ATK_TYPE_OBJECT) + +struct _UnityRootAccessiblePrivate +{ + /* we save on window_list the accessible object for the windows + registered */ + GSList* window_list; + nux::BaseWindow* active_window; + nux::BaseWindow* launcher_window; +}; + +static void +unity_root_accessible_class_init(UnityRootAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->finalize = unity_root_accessible_finalize; + + /* AtkObject */ + atk_class->get_n_children = unity_root_accessible_get_n_children; + atk_class->ref_child = unity_root_accessible_ref_child; + atk_class->get_parent = unity_root_accessible_get_parent; + atk_class->initialize = unity_root_accessible_initialize; + + g_type_class_add_private(gobject_class, sizeof(UnityRootAccessiblePrivate)); +} + +static void +unity_root_accessible_init(UnityRootAccessible* root) +{ + root->priv = UNITY_ROOT_ACCESSIBLE_GET_PRIVATE(root); + + root->priv->window_list = NULL; + root->priv->active_window = NULL; + root->priv->launcher_window = NULL; +} + +AtkObject* +unity_root_accessible_new(void) +{ + AtkObject* accessible = NULL; + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_ROOT_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, NULL); + + return accessible; +} + +static void +unity_root_accessible_finalize(GObject* object) +{ + UnityRootAccessible* root = UNITY_ROOT_ACCESSIBLE(object); + + g_return_if_fail(UNITY_IS_ROOT_ACCESSIBLE(object)); + + if (root->priv->window_list) + { + g_slist_free_full(root->priv->window_list, g_object_unref); + root->priv->window_list = NULL; + } + + G_OBJECT_CLASS(unity_root_accessible_parent_class)->finalize(object); +} + +/* AtkObject.h */ +static void +unity_root_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + accessible->role = ATK_ROLE_APPLICATION; + + // FIXME: compiz doesn't set the program name using g_set_prgname, + // and AFAIK, there isn't a way to get it. Requires further investigation. + // accessible->name = g_get_prgname(); + atk_object_set_name(accessible, "unity"); + atk_object_set_parent(accessible, NULL); + + register_interesting_messages(UNITY_ROOT_ACCESSIBLE(accessible)); + + ATK_OBJECT_CLASS(unity_root_accessible_parent_class)->initialize(accessible, data); +} + +static gint +unity_root_accessible_get_n_children(AtkObject* obj) +{ + UnityRootAccessible* root = UNITY_ROOT_ACCESSIBLE(obj); + + return g_slist_length(root->priv->window_list); +} + +static AtkObject* +unity_root_accessible_ref_child(AtkObject* obj, + gint i) +{ + UnityRootAccessible* root = NULL; + gint num = 0; + AtkObject* item = NULL; + + root = UNITY_ROOT_ACCESSIBLE(obj); + num = atk_object_get_n_accessible_children(obj); + g_return_val_if_fail((i < num) && (i >= 0), NULL); + + item = ATK_OBJECT(g_slist_nth_data(root->priv->window_list, i)); + + if (!item) + return NULL; + + g_object_ref(item); + + return item; +} + +static AtkObject* +unity_root_accessible_get_parent(AtkObject* obj) +{ + return NULL; +} + + +/* private */ +/* + * Call all the children (NuxBaseWindowAccessible) to check if they + * are in the proper active or deactive status. + */ +static void +check_active_window(UnityRootAccessible* self) +{ + GSList* iter = NULL; + NuxBaseWindowAccessible* window = NULL; + + for (iter = self->priv->window_list; iter != NULL; iter = g_slist_next(iter)) + { + window = NUX_BASE_WINDOW_ACCESSIBLE(iter->data); + nux_base_window_accessible_check_active(window, self->priv->active_window); + } +} + +/* + * It adds a window to the internal window_list managed by the Root object + * + * Checks if the object is already present. Adds a reference to the + * accessible object of the window. + */ +static void +add_window(UnityRootAccessible* self, + nux::BaseWindow* window) +{ + AtkObject* window_accessible = NULL; + gint index = 0; + + g_return_if_fail(UNITY_IS_ROOT_ACCESSIBLE(self)); + + window_accessible = + unity_a11y_get_accessible(window); + + /* FIXME: temporal */ + atk_object_set_name (window_accessible, window->GetWindowName().c_str()); + + if (g_slist_find(self->priv->window_list, window_accessible)) + return; + + self->priv->window_list = + g_slist_append(self->priv->window_list, window_accessible); + g_object_ref(window_accessible); + + index = g_slist_index(self->priv->window_list, window_accessible); + + explore_children(window_accessible); + + g_signal_emit_by_name(self, "children-changed::add", + index, window_accessible, NULL); +} + + +/* + * It removes the window to the internal window_list managed by the + * Root object + * + * Checks if the object is already present. Removes a reference to the + * accessible object of the window. + */ +static void +remove_window(UnityRootAccessible* self, + nux::BaseWindow* window) +{ + AtkObject* window_accessible = NULL; + gint index = 0; + + g_return_if_fail(UNITY_IS_ROOT_ACCESSIBLE(self)); + + window_accessible = + unity_a11y_get_accessible(window); + + return; + + if (!g_slist_find(self->priv->window_list, window_accessible)) + return; + + index = g_slist_index(self->priv->window_list, window_accessible); + + self->priv->window_list = + g_slist_remove(self->priv->window_list, window_accessible); + g_object_unref(window_accessible); + + g_signal_emit_by_name(self, "children-changed::remove", + index, window_accessible, NULL); +} + +static void +set_active_window(UnityRootAccessible* self, + nux::BaseWindow* window) +{ + g_return_if_fail(UNITY_IS_ROOT_ACCESSIBLE(self)); + g_return_if_fail(window != NULL); + + self->priv->active_window = window; + check_active_window(self); +} + +nux::BaseWindow* +search_for_launcher_window(UnityRootAccessible* self) +{ + GSList*iter = NULL; + nux::Object* nux_object = NULL; + nux::BaseWindow* bwindow = NULL; + NuxObjectAccessible* accessible = NULL; + gboolean found = FALSE; + + for (iter = self->priv->window_list; iter != NULL; iter = g_slist_next(iter)) + { + accessible = NUX_OBJECT_ACCESSIBLE(iter->data); + + nux_object = nux_object_accessible_get_object(accessible); + bwindow = dynamic_cast<nux::BaseWindow*>(nux_object); + + if ((bwindow!= NULL) && (g_strcmp0(bwindow->GetWindowName().c_str(), "LauncherWindow") == 0)) + { + found = TRUE; + break; + } + } + + if (found) + return bwindow; + else + return NULL; +} + +static void +ubus_launcher_register_interest_cb(unity::glib::Variant const& variant, + UnityRootAccessible* self) +{ + //launcher window is the same during all the life of Unity + if (self->priv->launcher_window == NULL) + self->priv->launcher_window = search_for_launcher_window(self); + + //launcher window became the active window + set_active_window(self, self->priv->launcher_window); +} + + +static void +wc_change_visibility_window_cb(nux::BaseWindow* window, + UnityRootAccessible* self, + gboolean visible) +{ + if (visible) + { + add_window(self, window); + //for the dash and quicklist + set_active_window(self, window); + } + else + { + AtkObject* accessible = NULL; + + accessible = unity_a11y_get_accessible(window); + nux_base_window_accessible_check_active(NUX_BASE_WINDOW_ACCESSIBLE(accessible), + NULL); + remove_window(self, window); + } +} + +static void +register_interesting_messages(UnityRootAccessible* self) +{ + static unity::UBusManager ubus_manager; + + ubus_manager.RegisterInterest(UBUS_LAUNCHER_START_KEY_NAV, + sigc::bind(sigc::ptr_fun(ubus_launcher_register_interest_cb), + self)); + + ubus_manager.RegisterInterest(UBUS_LAUNCHER_START_KEY_SWITCHER, + sigc::bind(sigc::ptr_fun(ubus_launcher_register_interest_cb), + self)); + + nux::GetWindowCompositor().sigVisibleViewWindow. + connect(sigc::bind(sigc::ptr_fun(wc_change_visibility_window_cb), self, TRUE)); + + nux::GetWindowCompositor().sigHiddenViewWindow. + connect(sigc::bind(sigc::ptr_fun(wc_change_visibility_window_cb), self, FALSE)); +} diff --git a/a11y/unity-root-accessible.h b/a11y/unity-root-accessible.h new file mode 100644 index 000000000..4e843e1df --- /dev/null +++ b/a11y/unity-root-accessible.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_ROOT_ACCESSIBLE_H +#define UNITY_ROOT_ACCESSIBLE_H + +#include <atk/atk.h> + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> + +G_BEGIN_DECLS + +#define UNITY_TYPE_ROOT_ACCESSIBLE (unity_root_accessible_get_type ()) +#define UNITY_ROOT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_ROOT_ACCESSIBLE, UnityRootAccessible)) +#define UNITY_ROOT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_ROOT_ACCESSIBLE, UnityRootAccessibleClass)) +#define UNITY_IS_ROOT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_ROOT_ACCESSIBLE)) +#define UNITY_IS_ROOT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_ROOT_ACCESSIBLE)) +#define UNITY_ROOT_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_ROOT_ACCESSIBLE, UnityRootAccessibleClass)) + +typedef struct _UnityRootAccessible UnityRootAccessible; +typedef struct _UnityRootAccessibleClass UnityRootAccessibleClass; +typedef struct _UnityRootAccessiblePrivate UnityRootAccessiblePrivate; + +struct _UnityRootAccessible +{ + AtkObject parent; + + /* < private > */ + UnityRootAccessiblePrivate* priv; +}; + +struct _UnityRootAccessibleClass +{ + AtkObjectClass parent_class; +}; + +GType unity_root_accessible_get_type(void); +AtkObject* unity_root_accessible_new(void); + +G_END_DECLS + +#endif /* __UNITY_ROOT_ACCESSIBLE_H__ */ diff --git a/a11y/unity-rvgrid-accessible.cpp b/a11y/unity-rvgrid-accessible.cpp new file mode 100644 index 000000000..e17f15e2a --- /dev/null +++ b/a11y/unity-rvgrid-accessible.cpp @@ -0,0 +1,394 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-rvgrid-accessible + * @Title: UnityRvgridAccessible + * @short_description: Implementation of the ATK interfaces for #ResultViewGrid + * @see_also: Rvgrid + * + * #UnityRvgridAccessible implements the required ATK interfaces for + * #Rvgrid, ie: exposing the different RvgridIcon on the model as + * #child of the object. + * + */ + +#include <glib/gi18n.h> + +#include "unity-rvgrid-accessible.h" +#include "unity-result-accessible.h" +#include "unity-places-group-accessible.h" + +#include "unitya11y.h" +#include "ResultViewGrid.h" +#include "PlacesGroup.h" + +using namespace unity::dash; + +/* GObject */ +static void unity_rvgrid_accessible_class_init(UnityRvgridAccessibleClass* klass); +static void unity_rvgrid_accessible_init(UnityRvgridAccessible* self); +static void unity_rvgrid_accessible_finalize(GObject* object); + +/* AtkObject.h */ +static void unity_rvgrid_accessible_initialize(AtkObject* accessible, + gpointer data); +static AtkStateSet* unity_rvgrid_accessible_ref_state_set(AtkObject* obj); +static gint unity_rvgrid_accessible_get_n_children(AtkObject* obj); +static AtkObject* unity_rvgrid_accessible_ref_child(AtkObject* obj, + gint i); + +/* AtkSelection */ +static void atk_selection_interface_init(AtkSelectionIface* iface); +static AtkObject* unity_rvgrid_accessible_ref_selection(AtkSelection* selection, + gint i); +static gint unity_rvgrid_accessible_get_selection_count(AtkSelection* selection); +static gboolean unity_rvgrid_accessible_is_child_selected(AtkSelection* selection, + gint i); + +/* private */ + +G_DEFINE_TYPE_WITH_CODE(UnityRvgridAccessible, unity_rvgrid_accessible, NUX_TYPE_VIEW_ACCESSIBLE, + G_IMPLEMENT_INTERFACE(ATK_TYPE_SELECTION, atk_selection_interface_init)) + +#define UNITY_RVGRID_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_RVGRID_ACCESSIBLE, \ + UnityRvgridAccessiblePrivate)) + +struct _UnityRvgridAccessiblePrivate +{ + sigc::connection on_selection_change_connection; + + /* dummy selected result object */ + UnityResultAccessible* result; + gboolean has_selection; + gboolean focused; +}; + + +static void +unity_rvgrid_accessible_class_init(UnityRvgridAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* GObject */ + gobject_class->finalize = unity_rvgrid_accessible_finalize; + + /* AtkObject */ + atk_class->get_n_children = unity_rvgrid_accessible_get_n_children; + atk_class->ref_child = unity_rvgrid_accessible_ref_child; + atk_class->initialize = unity_rvgrid_accessible_initialize; + atk_class->ref_state_set = unity_rvgrid_accessible_ref_state_set; + + g_type_class_add_private(gobject_class, sizeof(UnityRvgridAccessiblePrivate)); +} + +static void +unity_rvgrid_accessible_init(UnityRvgridAccessible* self) +{ + UnityRvgridAccessiblePrivate* priv = + UNITY_RVGRID_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; +} + +static void +unity_rvgrid_accessible_finalize(GObject* object) +{ + UnityRvgridAccessible* self = UNITY_RVGRID_ACCESSIBLE(object); + + self->priv->on_selection_change_connection.disconnect(); + + if (self->priv->result != NULL) + { + g_object_unref(self->priv->result); + self->priv->result = NULL; + } + + self->priv->on_selection_change_connection.disconnect(); + + G_OBJECT_CLASS(unity_rvgrid_accessible_parent_class)->finalize(object); +} + +AtkObject* +unity_rvgrid_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<ResultViewGrid*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_RVGRID_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +check_selection(UnityRvgridAccessible* self) +{ + AtkObject* child = NULL; + gint index = 0; + nux::Object* object = NULL; + ResultViewGrid* rvgrid = NULL; + std::string name; + + /* we don't notify until the grid is focused */ + if (self->priv->focused == FALSE) + return; + + object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + if (!object) /* state is defunct */ + return; + + rvgrid = static_cast<ResultViewGrid*>(object); + index = rvgrid->GetSelectedIndex(); + + if (index >= 0) + { + Result result(*rvgrid->GetIteratorAtRow(index)); + name = result.name; + + child = ATK_OBJECT(self->priv->result); + self->priv->has_selection = TRUE; + atk_object_set_name(child, name.c_str()); + } + else + { + child = NULL; + self->priv->has_selection = FALSE; + } + + g_signal_emit_by_name(self, "active-descendant-changed", child); + g_signal_emit_by_name(self, "selection-changed"); +} + +static void +on_selection_change_cb(UnityRvgridAccessible* self) +{ + check_selection(self); +} + +static void +search_for_label(UnityRvgridAccessible* self) +{ + AtkObject* label_accessible = NULL; + nux::Object* nux_object = NULL; + unity::dash::PlacesGroup* group = NULL; + AtkObject* iter = NULL; + unity::StaticCairoText* label = NULL; + + /* Search for the places group */ + for (iter = atk_object_get_parent(ATK_OBJECT(self)); iter != NULL; + iter = atk_object_get_parent(iter)) + { + if (UNITY_IS_PLACES_GROUP_ACCESSIBLE(iter)) + break; + } + if (iter == NULL) + return; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(iter)); + group = dynamic_cast<unity::dash::PlacesGroup*>(nux_object); + + if (group == NULL) + return; + + label = group->GetLabel(); + + label_accessible = unity_a11y_get_accessible(label); + + if (label_accessible == NULL) + return; + + /* FIXME: I had a froze using relations, require further + investigation, meanwhile setting directly the name can do the + work*/ + atk_object_set_name(ATK_OBJECT(self), atk_object_get_name(label_accessible)); +} + +static gboolean +check_selection_on_idle(gpointer data) +{ + check_selection(UNITY_RVGRID_ACCESSIBLE(data)); + + return FALSE; +} + +static void +on_focus_event_cb(AtkObject* object, + gboolean in, + gpointer data) +{ + UnityRvgridAccessible* self = NULL; + + g_return_if_fail(UNITY_IS_RVGRID_ACCESSIBLE(data)); + + self = UNITY_RVGRID_ACCESSIBLE(data); + self->priv->focused = in; + + /* we check the selection stuff again, to report the selection + change now */ + g_idle_add(check_selection_on_idle, self); +} + +static void +unity_rvgrid_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + UnityRvgridAccessible* self = NULL; + ResultViewGrid* rvgrid = NULL; + nux::Object* nux_object = NULL; + + ATK_OBJECT_CLASS(unity_rvgrid_accessible_parent_class)->initialize(accessible, data); + + atk_object_set_role(accessible, ATK_ROLE_TOOL_BAR); + + self = UNITY_RVGRID_ACCESSIBLE(accessible); + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + + rvgrid = dynamic_cast<ResultViewGrid*>(nux_object); + + if (rvgrid == NULL) + return; + + self->priv->on_selection_change_connection = + rvgrid->selection_change.connect(sigc::bind(sigc::ptr_fun(on_selection_change_cb), self)); + + g_signal_connect(self, "focus-event", + G_CALLBACK(on_focus_event_cb), self); + + self->priv->result = UNITY_RESULT_ACCESSIBLE(unity_result_accessible_new()); + atk_object_set_parent(ATK_OBJECT(self->priv->result), ATK_OBJECT(self)); + + search_for_label(self); +} + +static gint +unity_rvgrid_accessible_get_n_children(AtkObject* obj) +{ + g_return_val_if_fail(UNITY_IS_RVGRID_ACCESSIBLE(obj), 0); + + /* we have the state MANAGES_DESCENDANT, clients should not ask for + the children, and just taking care of the relevant signals. So we + just don't expose the children */ + return 0; +} + +static AtkObject* +unity_rvgrid_accessible_ref_child(AtkObject* obj, + gint i) +{ + g_return_val_if_fail(UNITY_IS_RVGRID_ACCESSIBLE(obj), NULL); + + /* we have the state MANAGES_DESCENDANT, clients should not ask for + the children, and just taking care of the relevant signals. So we + just don't expose the children */ + return NULL; +} + +static AtkStateSet* +unity_rvgrid_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_RVGRID_ACCESSIBLE(obj), NULL); + + state_set = ATK_OBJECT_CLASS(unity_rvgrid_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + + if (nux_object == NULL) /* defunct */ + return state_set; + + atk_state_set_add_state(state_set, ATK_STATE_MANAGES_DESCENDANTS); + + return state_set; +} + + +/* AtkSelection */ +static void +atk_selection_interface_init(AtkSelectionIface* iface) +{ + iface->ref_selection = unity_rvgrid_accessible_ref_selection; + iface->get_selection_count = unity_rvgrid_accessible_get_selection_count; + iface->is_child_selected = unity_rvgrid_accessible_is_child_selected; + + /* NOTE: for the moment we don't provide the implementation for the + "interactable" methods, it is, the methods that allow to change + the selected icon. The Rvgrid doesn't provide that API, and + right now we are focusing on a normal user input.*/ + /* iface->add_selection = unity_rvgrid_accessible_add_selection; */ + /* iface->clear_selection = unity_rvgrid_accessible_clear_selection; */ + /* iface->remove_selection = unity_rvgrid_accessible_remove_selection; */ + + /* This method will never be implemented, as select all the rvgrid + icons makes no sense */ + /* iface->select_all = unity_rvgrid_accessible_select_all_selection; */ +} + +static AtkObject* +unity_rvgrid_accessible_ref_selection(AtkSelection* selection, + gint i) +{ + UnityRvgridAccessible* self = NULL; + + g_return_val_if_fail(UNITY_IS_RVGRID_ACCESSIBLE(selection), NULL); + + self = UNITY_RVGRID_ACCESSIBLE(selection); + + if (self->priv->has_selection) + return ATK_OBJECT(g_object_ref(self->priv->result)); + else + return NULL; +} + +static gint +unity_rvgrid_accessible_get_selection_count(AtkSelection* selection) +{ + UnityRvgridAccessible* self = NULL; + + g_return_val_if_fail(UNITY_IS_RVGRID_ACCESSIBLE(selection), 0); + + self = UNITY_RVGRID_ACCESSIBLE(selection); + + if (self->priv->has_selection) + return 0; + else + return 1; +} + +static gboolean +unity_rvgrid_accessible_is_child_selected(AtkSelection* selection, + gint i) +{ + UnityRvgridAccessible* self = NULL; + + g_return_val_if_fail(UNITY_IS_RVGRID_ACCESSIBLE(selection), FALSE); + + self = UNITY_RVGRID_ACCESSIBLE(selection); + + if (self->priv->has_selection && i == 0) + return TRUE; + else + return FALSE; +} diff --git a/a11y/unity-rvgrid-accessible.h b/a11y/unity-rvgrid-accessible.h new file mode 100644 index 000000000..bd9cc0fb0 --- /dev/null +++ b/a11y/unity-rvgrid-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_RVGRID_ACCESSIBLE_H +#define UNITY_RVGRID_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_RVGRID_ACCESSIBLE (unity_rvgrid_accessible_get_type ()) +#define UNITY_RVGRID_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_RVGRID_ACCESSIBLE, UnityRvgridAccessible)) +#define UNITY_RVGRID_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_RVGRID_ACCESSIBLE, UnityRvgridAccessibleClass)) +#define UNITY_IS_RVGRID_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_RVGRID_ACCESSIBLE)) +#define UNITY_IS_RVGRID_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_RVGRID_ACCESSIBLE)) +#define UNITY_RVGRID_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_RVGRID_ACCESSIBLE, UnityRvgridAccessibleClass)) + +typedef struct _UnityRvgridAccessible UnityRvgridAccessible; +typedef struct _UnityRvgridAccessibleClass UnityRvgridAccessibleClass; +typedef struct _UnityRvgridAccessiblePrivate UnityRvgridAccessiblePrivate; + +struct _UnityRvgridAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnityRvgridAccessiblePrivate* priv; +}; + +struct _UnityRvgridAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_rvgrid_accessible_get_type(void); +AtkObject* unity_rvgrid_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_RVGRID_ACCESSIBLE_H__ */ diff --git a/a11y/unity-scope-bar-icon-accessible.cpp b/a11y/unity-scope-bar-icon-accessible.cpp new file mode 100644 index 000000000..997e9364d --- /dev/null +++ b/a11y/unity-scope-bar-icon-accessible.cpp @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Luke Yelavich <luke.yelavich@canonical.com> + */ + +/** + * SECTION:unity-scope_bar_icon-accessible + * @Title: UnityScopeBarIconAccessible + * @short_description: Implementation of the ATK interfaces for #ScopeBarIcon + * @see_also: ScopeBarIcon + * + * #UnityScopeBarIconAccessible implements the required ATK interfaces for + * #ScopeBarIcon, mainly exposing the text as his name, as this + * #object is mainly used as a label + * + */ + +#include <glib/gi18n.h> + +#include "unity-scope-bar-icon-accessible.h" + +#include "unitya11y.h" +#include "ScopeBarIcon.h" + +using namespace unity::dash; + +/* GObject */ +static void unity_scope_bar_icon_accessible_class_init(UnityScopeBarIconAccessibleClass* klass); +static void unity_scope_bar_icon_accessible_init(UnityScopeBarIconAccessible* self); +static void unity_scope_bar_icon_accessible_dispose(GObject* object); + +/* AtkObject.h */ +static void unity_scope_bar_icon_accessible_initialize(AtkObject* accessible, + gpointer data); +static const gchar* unity_scope_bar_icon_accessible_get_name(AtkObject* obj); +static void on_focus_changed_cb(nux::Area* area, + bool has_focus, + nux::KeyNavDirection direction, + AtkObject* accessible); +static void on_active_changed_cb(bool is_active, + AtkObject* accessible); + +G_DEFINE_TYPE(UnityScopeBarIconAccessible, unity_scope_bar_icon_accessible, NUX_TYPE_VIEW_ACCESSIBLE); + +#define UNITY_SCOPE_BAR_ICON_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_SCOPE_BAR_ICON_ACCESSIBLE, \ + UnityScopeBarIconAccessiblePrivate)) + +struct _UnityScopeBarIconAccessiblePrivate +{ + gchar* name; +}; + +static void +unity_scope_bar_icon_accessible_class_init(UnityScopeBarIconAccessibleClass* klass) +{ + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->dispose = unity_scope_bar_icon_accessible_dispose; + + /* AtkObject */ + atk_class->get_name = unity_scope_bar_icon_accessible_get_name; + atk_class->initialize = unity_scope_bar_icon_accessible_initialize; + + g_type_class_add_private(gobject_class, sizeof(UnityScopeBarIconAccessiblePrivate)); +} + +static void +unity_scope_bar_icon_accessible_init(UnityScopeBarIconAccessible* self) +{ + UnityScopeBarIconAccessiblePrivate* priv = + UNITY_SCOPE_BAR_ICON_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; + self->priv->name = NULL; +} + +static void +unity_scope_bar_icon_accessible_dispose(GObject* object) +{ + UnityScopeBarIconAccessible* self = UNITY_SCOPE_BAR_ICON_ACCESSIBLE(object); + + if (self->priv->name != NULL) + { + g_free(self->priv->name); + self->priv->name = NULL; + } + + G_OBJECT_CLASS(unity_scope_bar_icon_accessible_parent_class)->dispose(object); +} + +AtkObject* +unity_scope_bar_icon_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<ScopeBarIcon*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_SCOPE_BAR_ICON_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +unity_scope_bar_icon_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + ScopeBarIcon* icon = NULL; + + ATK_OBJECT_CLASS(unity_scope_bar_icon_accessible_parent_class)->initialize(accessible, data); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + icon = dynamic_cast<ScopeBarIcon*>(nux_object); + + if (icon == NULL) + return; + + icon->key_nav_focus_change.connect(sigc::bind(sigc::ptr_fun(on_focus_changed_cb), accessible)); + + icon->active.changed.connect(sigc::bind(sigc::ptr_fun(on_active_changed_cb), accessible)); + + atk_object_set_role(accessible, ATK_ROLE_PUSH_BUTTON); +} + +static const gchar* +unity_scope_bar_icon_accessible_get_name(AtkObject* obj) +{ + g_return_val_if_fail(UNITY_IS_SCOPE_BAR_ICON_ACCESSIBLE(obj), NULL); + UnityScopeBarIconAccessible* self = UNITY_SCOPE_BAR_ICON_ACCESSIBLE(obj); + + if (self->priv->name) + { + g_free(self->priv->name); + self->priv->name = NULL; + } + + self->priv->name = g_strdup(ATK_OBJECT_CLASS(unity_scope_bar_icon_accessible_parent_class)->get_name(obj)); + if (self->priv->name == NULL) + { + ScopeBarIcon* icon = NULL; + + icon = dynamic_cast<ScopeBarIcon*>(nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj))); + if (icon != NULL) + { + if (icon->active()) + self->priv->name = g_strdup_printf(_("%s: selected"), icon->name().c_str()); + else + self->priv->name = g_strdup(icon->name().c_str()); + } + } + + return self->priv->name; +} + +static void +on_focus_changed_cb(nux::Area* area, + bool has_focus, + nux::KeyNavDirection direction, + AtkObject* accessible) +{ + g_return_if_fail(UNITY_IS_SCOPE_BAR_ICON_ACCESSIBLE(accessible)); + + g_signal_emit_by_name(accessible, "focus-event", has_focus); +} + +static void +on_active_changed_cb(bool is_active, + AtkObject* accessible) +{ + g_return_if_fail(UNITY_IS_SCOPE_BAR_ICON_ACCESSIBLE(accessible)); + + g_object_notify(G_OBJECT(accessible), "accessible-name"); +} diff --git a/a11y/unity-scope-bar-icon-accessible.h b/a11y/unity-scope-bar-icon-accessible.h new file mode 100644 index 000000000..6fa67f160 --- /dev/null +++ b/a11y/unity-scope-bar-icon-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Luke Yelavich <luke.yelavich@canonical.com> + */ + +#ifndef UNITY_SCOPE_BAR_ICON_ACCESSIBLE_H +#define UNITY_SCOPE_BAR_ICON_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_SCOPE_BAR_ICON_ACCESSIBLE (unity_scope_bar_icon_accessible_get_type ()) +#define UNITY_SCOPE_BAR_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_SCOPE_BAR_ICON_ACCESSIBLE, UnityScopeBarIconAccessible)) +#define UNITY_SCOPE_BAR_ICON_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_SCOPE_BAR_ICON_ACCESSIBLE, UnityScopeBarIconAccessibleClass)) +#define UNITY_IS_SCOPE_BAR_ICON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_SCOPE_BAR_ICON_ACCESSIBLE)) +#define UNITY_IS_SCOPE_BAR_ICON_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_SCOPE_BAR_ICON_ACCESSIBLE)) +#define UNITY_SCOPE_BAR_ICON_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_SCOPE_BAR_ICON_ACCESSIBLE, UnityScopeBarIconAccessibleClass)) + +typedef struct _UnityScopeBarIconAccessible UnityScopeBarIconAccessible; +typedef struct _UnityScopeBarIconAccessibleClass UnityScopeBarIconAccessibleClass; +typedef struct _UnityScopeBarIconAccessiblePrivate UnityScopeBarIconAccessiblePrivate; + +struct _UnityScopeBarIconAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnityScopeBarIconAccessiblePrivate* priv; +}; + +struct _UnityScopeBarIconAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_scope_bar_icon_accessible_get_type(void); +AtkObject* unity_scope_bar_icon_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_SCOPE_BAR_ICON_ACCESSIBLE_H__ */ diff --git a/a11y/unity-sctext-accessible.cpp b/a11y/unity-sctext-accessible.cpp new file mode 100644 index 000000000..b1f043215 --- /dev/null +++ b/a11y/unity-sctext-accessible.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-sctext-accessible + * @Title: UnitySctextAccessible + * @short_description: Implementation of the ATK interfaces for #StaticCairoText + * @see_also: StaticCairoText + * + * #UnitySctextAccessible implements the required ATK interfaces for + * #StaticCairoText, mainly exposing the text as his name, as this + * #object is mainly used as a label + * + */ + +#include <glib/gi18n.h> +#include <pango/pango.h> +#include <pango/pangocairo.h> + +#include "unity-sctext-accessible.h" + +#include "unitya11y.h" +#include "StaticCairoText.h" + +/* GObject */ +static void unity_sctext_accessible_class_init(UnitySctextAccessibleClass* klass); +static void unity_sctext_accessible_init(UnitySctextAccessible* self); + +/* AtkObject.h */ +static void unity_sctext_accessible_initialize(AtkObject* accessible, + gpointer data); +static const gchar* unity_sctext_accessible_get_name(AtkObject* obj); + +G_DEFINE_TYPE(UnitySctextAccessible, unity_sctext_accessible, NUX_TYPE_VIEW_ACCESSIBLE); + + +#define UNITY_SCTEXT_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_SCTEXT_ACCESSIBLE, \ + UnitySctextAccessiblePrivate)) + +struct _UnitySctextAccessiblePrivate +{ + gchar* stripped_name; +}; + + +static void +unity_sctext_accessible_class_init(UnitySctextAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* AtkObject */ + atk_class->get_name = unity_sctext_accessible_get_name; + atk_class->initialize = unity_sctext_accessible_initialize; + + g_type_class_add_private(gobject_class, sizeof(UnitySctextAccessiblePrivate)); +} + +static void +unity_sctext_accessible_init(UnitySctextAccessible* self) +{ + UnitySctextAccessiblePrivate* priv = + UNITY_SCTEXT_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; + priv->stripped_name = NULL; +} + +AtkObject* +unity_sctext_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<unity::StaticCairoText*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_SCTEXT_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +on_label_text_change_cb(unity::StaticCairoText* label, UnitySctextAccessible* self) +{ + g_object_notify(G_OBJECT(self), "accessible-name"); +} + +static void +unity_sctext_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + unity::StaticCairoText* label = NULL; + + ATK_OBJECT_CLASS(unity_sctext_accessible_parent_class)->initialize(accessible, data); + + atk_object_set_role(accessible, ATK_ROLE_LABEL); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + label = dynamic_cast<unity::StaticCairoText*>(nux_object); + + if (label == NULL) /* status defunct */ + return; + + label->sigTextChanged.connect(sigc::bind(sigc::ptr_fun(on_label_text_change_cb), + UNITY_SCTEXT_ACCESSIBLE(accessible))); +} + +static const gchar* +unity_sctext_accessible_get_name(AtkObject* obj) +{ + const gchar* name = NULL; + UnitySctextAccessible* self = NULL; + + g_return_val_if_fail(UNITY_IS_SCTEXT_ACCESSIBLE(obj), NULL); + self = UNITY_SCTEXT_ACCESSIBLE(obj); + + name = ATK_OBJECT_CLASS(unity_sctext_accessible_parent_class)->get_name(obj); + if (name == NULL) + { + unity::StaticCairoText* text = NULL; + + if (self->priv->stripped_name != NULL) + { + g_free(self->priv->stripped_name); + self->priv->stripped_name = NULL; + } + + text = dynamic_cast<unity::StaticCairoText*>(nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj))); + if (text != NULL) + { + name = text->GetText().c_str(); + pango_parse_markup(name, -1, 0, NULL, + &self->priv->stripped_name, + NULL, NULL); + name = self->priv->stripped_name; + } + } + + return name; +} diff --git a/a11y/unity-sctext-accessible.h b/a11y/unity-sctext-accessible.h new file mode 100644 index 000000000..2c1dd22c8 --- /dev/null +++ b/a11y/unity-sctext-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_SCTEXT_ACCESSIBLE_H +#define UNITY_SCTEXT_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_SCTEXT_ACCESSIBLE (unity_sctext_accessible_get_type ()) +#define UNITY_SCTEXT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_SCTEXT_ACCESSIBLE, UnitySctextAccessible)) +#define UNITY_SCTEXT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_SCTEXT_ACCESSIBLE, UnitySctextAccessibleClass)) +#define UNITY_IS_SCTEXT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_SCTEXT_ACCESSIBLE)) +#define UNITY_IS_SCTEXT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_SCTEXT_ACCESSIBLE)) +#define UNITY_SCTEXT_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_SCTEXT_ACCESSIBLE, UnitySctextAccessibleClass)) + +typedef struct _UnitySctextAccessible UnitySctextAccessible; +typedef struct _UnitySctextAccessibleClass UnitySctextAccessibleClass; +typedef struct _UnitySctextAccessiblePrivate UnitySctextAccessiblePrivate; + +struct _UnitySctextAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnitySctextAccessiblePrivate* priv; +}; + +struct _UnitySctextAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_sctext_accessible_get_type(void); +AtkObject* unity_sctext_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_SCTEXT_ACCESSIBLE_H__ */ diff --git a/a11y/unity-search-bar-accessible.cpp b/a11y/unity-search-bar-accessible.cpp new file mode 100644 index 000000000..4c59cdc81 --- /dev/null +++ b/a11y/unity-search-bar-accessible.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-search_bar-accessible + * @Title: UnitySearchBarAccessible + * @short_description: Implementation of the ATK interfaces for #SearchBar + * @see_also: SearchBar at SearchBar.h + * + * #UnitySearchBarAccessible implements the required ATK interfaces for + * #SearchBar, ie: exposing the different SearchBarIcon on the model as + * #child of the object. + * + */ + +#include <glib/gi18n.h> + +#include "unity-search-bar-accessible.h" + +#include "unitya11y.h" +#include "SearchBar.h" + +using namespace unity; + +/* GObject */ +static void unity_search_bar_accessible_class_init(UnitySearchBarAccessibleClass* klass); +static void unity_search_bar_accessible_init(UnitySearchBarAccessible* self); +static void unity_search_bar_accessible_finalize(GObject* object); + +/* AtkObject.h */ +static void unity_search_bar_accessible_initialize(AtkObject* accessible, + gpointer data); + +G_DEFINE_TYPE(UnitySearchBarAccessible, unity_search_bar_accessible, NUX_TYPE_VIEW_ACCESSIBLE) + +#define UNITY_SEARCH_BAR_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_SEARCH_BAR_ACCESSIBLE, \ + UnitySearchBarAccessiblePrivate)) + +struct _UnitySearchBarAccessiblePrivate +{ + +}; + + +static void +unity_search_bar_accessible_class_init(UnitySearchBarAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->finalize = unity_search_bar_accessible_finalize; + + /* AtkObject */ + atk_class->initialize = unity_search_bar_accessible_initialize; + + g_type_class_add_private(gobject_class, sizeof(UnitySearchBarAccessiblePrivate)); +} + +static void +unity_search_bar_accessible_init(UnitySearchBarAccessible* self) +{ + UnitySearchBarAccessiblePrivate* priv = + UNITY_SEARCH_BAR_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; +} + +static void +unity_search_bar_accessible_finalize(GObject* object) +{ + G_OBJECT_CLASS(unity_search_bar_accessible_parent_class)->finalize(object); +} + +AtkObject* +unity_search_bar_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<SearchBar*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_SEARCH_BAR_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +on_search_hint_change_cb(std::string const& s, UnitySearchBarAccessible* self) +{ + SearchBar* search_bar = NULL; + nux::TextEntry* text_entry = NULL; + nux::Object* nux_object = NULL; + + g_return_if_fail(UNITY_IS_SEARCH_BAR_ACCESSIBLE(self)); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + search_bar = dynamic_cast<SearchBar*>(nux_object); + + if (search_bar == NULL) /* state defunct */ + return; + + text_entry = search_bar->text_entry(); + + if (text_entry != NULL) + { + AtkObject* text_entry_accessible = NULL; + text_entry_accessible = unity_a11y_get_accessible(text_entry); + atk_object_set_name(text_entry_accessible, s.c_str()); + } +} + + +static void +unity_search_bar_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + SearchBar* search_bar = NULL; + // nux::TextEntry* text_entry = NULL; + + ATK_OBJECT_CLASS(unity_search_bar_accessible_parent_class)->initialize(accessible, data); + + accessible->role = ATK_ROLE_PANEL; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + search_bar = dynamic_cast<SearchBar*>(nux_object); + + if (search_bar == NULL) + return; + + search_bar->search_hint.changed.connect(sigc::bind(sigc::ptr_fun(on_search_hint_change_cb), + UNITY_SEARCH_BAR_ACCESSIBLE(accessible))); +} diff --git a/a11y/unity-search-bar-accessible.h b/a11y/unity-search-bar-accessible.h new file mode 100644 index 000000000..94664b77e --- /dev/null +++ b/a11y/unity-search-bar-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_SEARCH_BAR_ACCESSIBLE_H +#define UNITY_SEARCH_BAR_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_SEARCH_BAR_ACCESSIBLE (unity_search_bar_accessible_get_type ()) +#define UNITY_SEARCH_BAR_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_SEARCH_BAR_ACCESSIBLE, UnitySearchBarAccessible)) +#define UNITY_SEARCH_BAR_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_SEARCH_BAR_ACCESSIBLE, UnitySearchBarAccessibleClass)) +#define UNITY_IS_SEARCH_BAR_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_SEARCH_BAR_ACCESSIBLE)) +#define UNITY_IS_SEARCH_BAR_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_SEARCH_BAR_ACCESSIBLE)) +#define UNITY_SEARCH_BAR_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_SEARCH_BAR_ACCESSIBLE, UnitySearchBarAccessibleClass)) + +typedef struct _UnitySearchBarAccessible UnitySearchBarAccessible; +typedef struct _UnitySearchBarAccessibleClass UnitySearchBarAccessibleClass; +typedef struct _UnitySearchBarAccessiblePrivate UnitySearchBarAccessiblePrivate; + +struct _UnitySearchBarAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnitySearchBarAccessiblePrivate* priv; +}; + +struct _UnitySearchBarAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_search_bar_accessible_get_type(void); +AtkObject* unity_search_bar_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_SEARCH_BAR_ACCESSIBLE_H__ */ diff --git a/a11y/unity-session-button-accessible.cpp b/a11y/unity-session-button-accessible.cpp new file mode 100644 index 000000000..65653ef73 --- /dev/null +++ b/a11y/unity-session-button-accessible.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Luke Yelavich <luke.yelavich@canonical.com> + */ + +/** + * SECTION:unity-session_button_accessible + * @Title: UnitySessionButtonAccessible + * @short_description: Implementation of the ATK interfaces for #unity::session::Button + * + * #UnitySessionButtonAccessible implements the required ATK interfaces of + * unity::Button, exposing the common elements on each basic individual + * element (position, extents, etc) + * + */ + +#include "unity-session-button-accessible.h" +#include "SessionButton.h" + +#include "unitya11y.h" + +using namespace unity::session; + +/* GObject */ +static void unity_session_button_accessible_class_init(UnitySessionButtonAccessibleClass* klass); +static void unity_session_button_accessible_init(UnitySessionButtonAccessible* session_button_accessible); +static void unity_session_button_accessible_dispose(GObject* object); +static void unity_session_button_accessible_finalize(GObject* object); + + +/* AtkObject.h */ +static void unity_session_button_accessible_initialize(AtkObject* accessible, + gpointer data); +static AtkStateSet* unity_session_button_accessible_ref_state_set(AtkObject* obj); +static const gchar* unity_session_button_accessible_get_name(AtkObject* obj); + + +/* AtkAction */ +static void atk_action_interface_init(AtkActionIface *iface); +static gboolean unity_session_button_accessible_do_action(AtkAction *action, + gint i); +static gint unity_session_button_accessible_get_n_actions(AtkAction *action); +static const gchar* unity_session_button_accessible_get_name(AtkAction *action, + gint i); + +/* private/utility methods*/ +static void on_focus_change_cb(bool const& value, UnitySessionButtonAccessible* accessible); + +G_DEFINE_TYPE_WITH_CODE(UnitySessionButtonAccessible, + unity_session_button_accessible, + NUX_TYPE_OBJECT_ACCESSIBLE, + G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION, + atk_action_interface_init)) + +#define UNITY_SESSION_BUTTON_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_SESSION_BUTTON_ACCESSIBLE, \ + UnitySessionButtonAccessiblePrivate)) + +struct _UnitySessionButtonAccessiblePrivate +{ + gchar *name; +}; + +static void +unity_session_button_accessible_class_init(UnitySessionButtonAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + gobject_class->dispose = unity_session_button_accessible_dispose; + gobject_class->finalize = unity_session_button_accessible_finalize; + + /* AtkObject */ + atk_class->initialize = unity_session_button_accessible_initialize; + atk_class->get_name = unity_session_button_accessible_get_name; + atk_class->ref_state_set = unity_session_button_accessible_ref_state_set; + + g_type_class_add_private(gobject_class, sizeof(UnitySessionButtonAccessiblePrivate)); +} + +static void +unity_session_button_accessible_init(UnitySessionButtonAccessible* session_button_accessible) +{ + UnitySessionButtonAccessiblePrivate *priv = + UNITY_SESSION_BUTTON_ACCESSIBLE_GET_PRIVATE(session_button_accessible); + + session_button_accessible->priv = priv; + session_button_accessible->priv->name = NULL; +} + +static void +unity_session_button_accessible_dispose(GObject* object) +{ + UnitySessionButtonAccessible *self = UNITY_SESSION_BUTTON_ACCESSIBLE(object); + + if (self->priv->name != NULL) { + g_free(self->priv->name); + self->priv->name = NULL; + } + + G_OBJECT_CLASS(unity_session_button_accessible_parent_class)->dispose(object); +} + +static void +unity_session_button_accessible_finalize(GObject* object) +{ + G_OBJECT_CLASS(unity_session_button_accessible_parent_class)->finalize(object); +} + +AtkObject* +unity_session_button_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<Button*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_SESSION_BUTTON_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +/* AtkObject.h */ +static void +unity_session_button_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + UnitySessionButtonAccessible* self = NULL; + nux::Object* nux_object = NULL; + Button* button = NULL; + + ATK_OBJECT_CLASS(unity_session_button_accessible_parent_class)->initialize(accessible, data); + self = UNITY_SESSION_BUTTON_ACCESSIBLE(accessible); + + accessible->role = ATK_ROLE_PUSH_BUTTON; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + + if (nux_object == NULL) /* defunct */ + return; + + button = static_cast<Button*>(nux_object); + button->highlighted.changed.connect(sigc::bind(sigc::ptr_fun(on_focus_change_cb), + UNITY_SESSION_BUTTON_ACCESSIBLE(self))); +} + +static const gchar* +unity_session_button_accessible_get_name(AtkObject* obj) +{ + g_return_val_if_fail(UNITY_IS_SESSION_BUTTON_ACCESSIBLE(obj), NULL); + + UnitySessionButtonAccessible *self = UNITY_SESSION_BUTTON_ACCESSIBLE(obj); + + if (self->priv->name) + { + g_free(self->priv->name); + self->priv->name = NULL; + } + + self->priv->name = g_strdup(ATK_OBJECT_CLASS(unity_session_button_accessible_parent_class)->get_name(obj)); + if (self->priv->name == NULL) + { + Button* button = NULL; + + button = dynamic_cast<Button*>(nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj))); + + if (button == NULL) /* State is defunct */ + self->priv->name = NULL; + else + self->priv->name = g_strdup(button->label().c_str()); + } + + return self->priv->name; +} + +static AtkStateSet* +unity_session_button_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + nux::Object* nux_object = NULL; + Button* button = NULL; + + g_return_val_if_fail(UNITY_IS_SESSION_BUTTON_ACCESSIBLE(obj), NULL); + + state_set = ATK_OBJECT_CLASS(unity_session_button_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + + if (nux_object == NULL) /* defunct */ + return state_set; + + button = dynamic_cast<Button*>(nux_object); + + atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); + atk_state_set_add_state(state_set, ATK_STATE_ENABLED); + atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE); + atk_state_set_add_state(state_set, ATK_STATE_VISIBLE); + atk_state_set_add_state(state_set, ATK_STATE_SHOWING); + + if (button->highlighted) + { + atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); + atk_state_set_add_state(state_set, ATK_STATE_SELECTED); + atk_state_set_add_state(state_set, ATK_STATE_ACTIVE); + } + + return state_set; +} + +/* private methods */ +static void +on_focus_change_cb(bool const& value, UnitySessionButtonAccessible* accessible) +{ + nux::Object* nux_object = NULL; + Button* button = NULL; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + + if (nux_object == NULL) /* defunct */ + return; + + button = dynamic_cast<Button*>(nux_object); + + atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_FOCUSED, button->highlighted); + atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_SELECTED, button->highlighted); + atk_object_notify_state_change(ATK_OBJECT(accessible), ATK_STATE_ACTIVE, button->highlighted); +} + +/* AtkAction */ +static void +atk_action_interface_init(AtkActionIface *iface) +{ + iface->do_action = unity_session_button_accessible_do_action; + iface->get_n_actions = unity_session_button_accessible_get_n_actions; + iface->get_name = unity_session_button_accessible_get_name; +} + +static gboolean +unity_session_button_accessible_do_action(AtkAction *action, + gint i) +{ + Button* button = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_SESSION_BUTTON_ACCESSIBLE(action), FALSE); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(action)); + if (nux_object == NULL) + return FALSE; + + button = dynamic_cast<Button*>(nux_object); + + button->activated.emit(); + + return TRUE; +} + +static gint +unity_session_button_accessible_get_n_actions(AtkAction *action) +{ + g_return_val_if_fail(UNITY_IS_SESSION_BUTTON_ACCESSIBLE(action), 0); + + return 1; +} + +static const gchar* +unity_session_button_accessible_get_name(AtkAction *action, + gint i) +{ + g_return_val_if_fail(UNITY_IS_SESSION_BUTTON_ACCESSIBLE(action), NULL); + g_return_val_if_fail(i == 0, NULL); + + return "activate"; +} diff --git a/a11y/unity-session-button-accessible.h b/a11y/unity-session-button-accessible.h new file mode 100644 index 000000000..ab3ae0429 --- /dev/null +++ b/a11y/unity-session-button-accessible.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_SESSION_BUTTON_ACCESSIBLE_H +#define UNITY_SESSION_BUTTON_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-object-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_SESSION_BUTTON_ACCESSIBLE (unity_session_button_accessible_get_type ()) +#define UNITY_SESSION_BUTTON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_SESSION_BUTTON_ACCESSIBLE, UnitySessionButtonAccessible)) +#define UNITY_SESSION_BUTTON_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_SESSION_BUTTON_ACCESSIBLE, UnitySessionButtonAccessibleClass)) +#define UNITY_IS_SESSION_BUTTON_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_SESSION_BUTTON_ACCESSIBLE)) +#define UNITY_IS_SESSION_BUTTON_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_SESSION_BUTTON_ACCESSIBLE)) +#define UNITY_SESSION_BUTTON_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_SESSION_BUTTON_ACCESSIBLE, UnitySessionButtonAccessibleClass)) + +typedef struct _UnitySessionButtonAccessible UnitySessionButtonAccessible; +typedef struct _UnitySessionButtonAccessibleClass UnitySessionButtonAccessibleClass; +typedef struct _UnitySessionButtonAccessiblePrivate UnitySessionButtonAccessiblePrivate; + +struct _UnitySessionButtonAccessible +{ + NuxObjectAccessible parent; + + UnitySessionButtonAccessiblePrivate *priv; +}; + +struct _UnitySessionButtonAccessibleClass +{ + NuxObjectAccessibleClass parent_class; +}; + +GType unity_session_button_accessible_get_type(void); +AtkObject* unity_session_button_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_SESSION_BUTTON_ACCESSIBLE_H__ */ diff --git a/a11y/unity-switcher-accessible.cpp b/a11y/unity-switcher-accessible.cpp new file mode 100644 index 000000000..80651bc01 --- /dev/null +++ b/a11y/unity-switcher-accessible.cpp @@ -0,0 +1,410 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +/** + * SECTION:unity-switcher-accessible + * @Title: UnitySwitcherAccessible + * @short_description: Implementation of the ATK interfaces for #SwitcherView + * @see_also: SwitcherView + * + * #UnitySwitcherAccessible implements the required ATK interfaces for + * #SwitcherView, ie: exposing the different AbstractLauncherIcon on the + * #model as child of the object. + * + */ + +#include <glib/gi18n.h> + +#include "unity-switcher-accessible.h" +#include "unity-launcher-icon-accessible.h" + +#include "unitya11y.h" +#include "SwitcherView.h" +#include "SwitcherModel.h" + +using namespace unity::switcher; +using namespace unity::launcher; + +/* GObject */ +static void unity_switcher_accessible_class_init(UnitySwitcherAccessibleClass* klass); +static void unity_switcher_accessible_init(UnitySwitcherAccessible* self); +static void unity_switcher_accessible_finalize(GObject* object); + +/* AtkObject.h */ +static void unity_switcher_accessible_initialize(AtkObject* accessible, + gpointer data); +static gint unity_switcher_accessible_get_n_children(AtkObject* obj); +static AtkObject* unity_switcher_accessible_ref_child(AtkObject* obj, + gint i); +static AtkStateSet* unity_switcher_accessible_ref_state_set(AtkObject* obj); + +/* AtkSelection */ +static void atk_selection_interface_init(AtkSelectionIface* iface); +static AtkObject* unity_switcher_accessible_ref_selection(AtkSelection* selection, + gint i); +static gint unity_switcher_accessible_get_selection_count(AtkSelection* selection); +static gboolean unity_switcher_accessible_is_child_selected(AtkSelection* selection, + gint i); +/* NuxAreaAccessible */ +static gboolean unity_switcher_accessible_check_pending_notification(NuxAreaAccessible* self); + +/* private */ +static void on_selection_changed_cb(AbstractLauncherIcon::Ptr const& icon, + UnitySwitcherAccessible* switcher_accessible); +static void create_children(UnitySwitcherAccessible* self); + + +G_DEFINE_TYPE_WITH_CODE(UnitySwitcherAccessible, unity_switcher_accessible, NUX_TYPE_VIEW_ACCESSIBLE, + G_IMPLEMENT_INTERFACE(ATK_TYPE_SELECTION, atk_selection_interface_init)) + +#define UNITY_SWITCHER_ACCESSIBLE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_SWITCHER_ACCESSIBLE, \ + UnitySwitcherAccessiblePrivate)) + +struct _UnitySwitcherAccessiblePrivate +{ + /* We maintain the children. Although the LauncherIcon are shared + * between the Switcher and Launcher, in order to keep a hierarchy + * coherence, we create a different accessible object */ + GSList* children; + + sigc::connection on_selection_changed_connection; +}; + + +static void +unity_switcher_accessible_class_init(UnitySwitcherAccessibleClass* klass) +{ + GObjectClass* gobject_class = G_OBJECT_CLASS(klass); + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + NuxAreaAccessibleClass* area_class = NUX_AREA_ACCESSIBLE_CLASS(klass); + + gobject_class->finalize = unity_switcher_accessible_finalize; + + /* AtkObject */ + atk_class->get_n_children = unity_switcher_accessible_get_n_children; + atk_class->ref_child = unity_switcher_accessible_ref_child; + atk_class->initialize = unity_switcher_accessible_initialize; + atk_class->ref_state_set = unity_switcher_accessible_ref_state_set; + + /* NuxAreaAccessible */ + area_class->check_pending_notification = unity_switcher_accessible_check_pending_notification; + + g_type_class_add_private(gobject_class, sizeof(UnitySwitcherAccessiblePrivate)); +} + +static void +unity_switcher_accessible_init(UnitySwitcherAccessible* self) +{ + UnitySwitcherAccessiblePrivate* priv = + UNITY_SWITCHER_ACCESSIBLE_GET_PRIVATE(self); + + self->priv = priv; + self->priv->children = NULL; +} + +static void +unity_switcher_accessible_finalize(GObject* object) +{ + UnitySwitcherAccessible* self = UNITY_SWITCHER_ACCESSIBLE(object); + + self->priv->on_selection_changed_connection.disconnect(); + + if (self->priv->children) + { + g_slist_free_full(self->priv->children, g_object_unref); + self->priv->children = NULL; + } + + G_OBJECT_CLASS(unity_switcher_accessible_parent_class)->finalize(object); +} + +AtkObject* +unity_switcher_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<SwitcherView*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_SWITCHER_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + atk_object_set_name(accessible, _("Switcher")); + + return accessible; +} + +/* AtkObject.h */ +static void +unity_switcher_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + SwitcherView* switcher = NULL; + nux::Object* nux_object = NULL; + UnitySwitcherAccessible* self = NULL; + SwitcherModel::Ptr model; + + ATK_OBJECT_CLASS(unity_switcher_accessible_parent_class)->initialize(accessible, data); + + atk_object_set_role(accessible, ATK_ROLE_TOOL_BAR); + + self = UNITY_SWITCHER_ACCESSIBLE(accessible); + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + switcher = dynamic_cast<SwitcherView*>(nux_object); + if (switcher == NULL) + return; + + model = switcher->GetModel(); + + if (model) + { + self->priv->on_selection_changed_connection = + model->selection_changed.connect(sigc::bind(sigc::ptr_fun(on_selection_changed_cb), + self)); + + create_children(self); + } + + /* To force being connected to the window::activate signal */ + nux_area_accessible_parent_window_active(NUX_AREA_ACCESSIBLE(self)); +} + +static gint +unity_switcher_accessible_get_n_children(AtkObject* obj) +{ + nux::Object* object = NULL; + UnitySwitcherAccessible* self = NULL; + + g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(obj), 0); + self = UNITY_SWITCHER_ACCESSIBLE(obj); + + object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + if (!object) /* state is defunct */ + return 0; + + return g_slist_length(self->priv->children); +} + +static AtkObject* +unity_switcher_accessible_ref_child(AtkObject* obj, + gint i) +{ + gint num = 0; + nux::Object* nux_object = NULL; + AtkObject* child_accessible = NULL; + UnitySwitcherAccessible* self = NULL; + + g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(obj), NULL); + num = atk_object_get_n_accessible_children(obj); + g_return_val_if_fail((i < num) && (i >= 0), NULL); + self = UNITY_SWITCHER_ACCESSIBLE(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + if (!nux_object) /* state is defunct */ + return 0; + + child_accessible = ATK_OBJECT(g_slist_nth_data(self->priv->children, i)); + + g_object_ref(child_accessible); + + return child_accessible; +} + +static AtkStateSet* +unity_switcher_accessible_ref_state_set(AtkObject* obj) +{ + AtkStateSet* state_set = NULL; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(obj), NULL); + + state_set = + ATK_OBJECT_CLASS(unity_switcher_accessible_parent_class)->ref_state_set(obj); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)); + + if (nux_object == NULL) /* defunct */ + return state_set; + + /* The Switcher is always focusable */ + atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE); + + /* The Switcher is always focused. Looking SwitcherController code, + * SwitcherView is only created to be presented to the user */ + atk_state_set_add_state(state_set, ATK_STATE_FOCUSED); + + return state_set; +} + +/* AtkSelection */ +static void +atk_selection_interface_init(AtkSelectionIface* iface) +{ + iface->ref_selection = unity_switcher_accessible_ref_selection; + iface->get_selection_count = unity_switcher_accessible_get_selection_count; + iface->is_child_selected = unity_switcher_accessible_is_child_selected; + + /* NOTE: for the moment we don't provide the implementation for the + "interactable" methods, it is, the methods that allow to change + the selected icon. The Switcher doesn't provide that API, and + right now we are focusing on a normal user input.*/ + /* iface->add_selection = unity_switcher_accessible_add_selection; */ + /* iface->clear_selection = unity_switcher_accessible_clear_selection; */ + /* iface->remove_selection = unity_switcher_accessible_remove_selection; */ + + /* This method will never be implemented, as select all the switcher + icons makes no sense */ + /* iface->select_all = unity_switcher_accessible_select_all_selection; */ +} + +static AtkObject* +unity_switcher_accessible_ref_selection(AtkSelection* selection, + gint i) +{ + SwitcherView* switcher = NULL; + SwitcherModel::Ptr switcher_model; + nux::Object* nux_object = NULL; + gint selected_index = 0; + AtkObject* accessible_selected = NULL; + UnitySwitcherAccessible* self = NULL; + + g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(selection), 0); + /* there can be only just item selected */ + g_return_val_if_fail(i == 0, NULL); + self = UNITY_SWITCHER_ACCESSIBLE(selection); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection)); + if (!nux_object) /* state is defunct */ + return 0; + + switcher = static_cast<SwitcherView*>(nux_object); + switcher_model = switcher->GetModel(); + selected_index = switcher_model->SelectionIndex(); + + accessible_selected = ATK_OBJECT(g_slist_nth_data(self->priv->children, + selected_index)); + + if (accessible_selected != NULL) + g_object_ref(accessible_selected); + + return accessible_selected; +} + +static gint +unity_switcher_accessible_get_selection_count(AtkSelection* selection) +{ + SwitcherView* switcher = NULL; + SwitcherModel::Ptr switcher_model; + nux::Object* nux_object = NULL; + + g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(selection), 0); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection)); + if (!nux_object) /* state is defunct */ + return 0; + + switcher = static_cast<SwitcherView*>(nux_object); + switcher_model = switcher->GetModel(); + + if (!switcher_model->Selection()) + return 0; + else + return 1; +} + +static gboolean +unity_switcher_accessible_is_child_selected(AtkSelection* selection, + gint i) +{ + SwitcherView* switcher = NULL; + SwitcherModel::Ptr switcher_model; + SwitcherModel::iterator it; + nux::Object* nux_object = NULL; + gint selected_index = 0; + + g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(selection), FALSE); + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection)); + if (!nux_object) /* state is defunct */ + return 0; + + switcher = static_cast<SwitcherView*>(nux_object); + switcher_model = switcher->GetModel(); + selected_index = switcher_model->SelectionIndex(); + + if (selected_index == i) + return TRUE; + else + return FALSE; +} + +/* NuxAreaAccessible */ +static gboolean +unity_switcher_accessible_check_pending_notification(NuxAreaAccessible* self) +{ + g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(self), FALSE); + + /* Overriding the method: the switcher doesn't get the key focus of + * focus (Focusable) */ + /* From SwitcherController: it shows that the switcher only exists + * to be shown to the user, so if the parent window gets actived, we + * assume that the switcher will be automatically focused + */ + atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_FOCUSED, TRUE); + g_signal_emit_by_name(self, "focus-event", TRUE, NULL); + + return TRUE; +} + +/* private */ +static void +on_selection_changed_cb(AbstractLauncherIcon::Ptr const& icon, + UnitySwitcherAccessible* switcher_accessible) +{ + g_signal_emit_by_name(ATK_OBJECT(switcher_accessible), "selection-changed"); +} + +static void +create_children(UnitySwitcherAccessible* self) +{ + gint index = 0; + nux::Object* nux_object = NULL; + SwitcherView* switcher = NULL; + SwitcherModel::iterator it; + AtkObject* child_accessible = NULL; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self)); + if (!nux_object) /* state is defunct */ + return; + + switcher = static_cast<SwitcherView*>(nux_object); + SwitcherModel::Ptr const& switcher_model = switcher->GetModel(); + + if (!switcher_model) + return; + + for (AbstractLauncherIcon::Ptr const& child : *switcher_model) + { + child_accessible = unity_launcher_icon_accessible_new(child.GetPointer()); + atk_object_set_parent(child_accessible, ATK_OBJECT(self)); + self->priv->children = g_slist_append(self->priv->children, + child_accessible); + unity_launcher_icon_accessible_set_index(UNITY_LAUNCHER_ICON_ACCESSIBLE(child_accessible), + index++); + } +} diff --git a/a11y/unity-switcher-accessible.h b/a11y/unity-switcher-accessible.h new file mode 100644 index 000000000..b79d0683a --- /dev/null +++ b/a11y/unity-switcher-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_SWITCHER_ACCESSIBLE_H +#define UNITY_SWITCHER_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_SWITCHER_ACCESSIBLE (unity_switcher_accessible_get_type ()) +#define UNITY_SWITCHER_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_SWITCHER_ACCESSIBLE, UnitySwitcherAccessible)) +#define UNITY_SWITCHER_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_SWITCHER_ACCESSIBLE, UnitySwitcherAccessibleClass)) +#define UNITY_IS_SWITCHER_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_SWITCHER_ACCESSIBLE)) +#define UNITY_IS_SWITCHER_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_SWITCHER_ACCESSIBLE)) +#define UNITY_SWITCHER_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_SWITCHER_ACCESSIBLE, UnitySwitcherAccessibleClass)) + +typedef struct _UnitySwitcherAccessible UnitySwitcherAccessible; +typedef struct _UnitySwitcherAccessibleClass UnitySwitcherAccessibleClass; +typedef struct _UnitySwitcherAccessiblePrivate UnitySwitcherAccessiblePrivate; + +struct _UnitySwitcherAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnitySwitcherAccessiblePrivate* priv; +}; + +struct _UnitySwitcherAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_switcher_accessible_get_type(void); +AtkObject* unity_switcher_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif /* __UNITY_SWITCHER_ACCESSIBLE_H__ */ diff --git a/a11y/unity-text-input-accessible.cpp b/a11y/unity-text-input-accessible.cpp new file mode 100644 index 000000000..57d1a490a --- /dev/null +++ b/a11y/unity-text-input-accessible.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#include "unity-text-input-accessible.h" + +#include "unitya11y.h" +#include "TextInput.h" + +using namespace unity; + +/* GObject */ +static void unity_text_input_accessible_class_init(UnityTextInputAccessibleClass* klass); +static void unity_text_input_accessible_init(UnityTextInputAccessible* self); +//static void unity_text_input_accessible_finalize(GObject* object); + +/* AtkObject.h */ +static void unity_text_input_accessible_initialize(AtkObject* accessible, + gpointer data); + +G_DEFINE_TYPE(UnityTextInputAccessible, unity_text_input_accessible, NUX_TYPE_VIEW_ACCESSIBLE) + +static void +unity_text_input_accessible_class_init(UnityTextInputAccessibleClass* klass) +{ + AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass); + + /* AtkObject */ + atk_class->initialize = unity_text_input_accessible_initialize; +} + +static void +unity_text_input_accessible_init(UnityTextInputAccessible* self) +{} + +AtkObject* +unity_text_input_accessible_new(nux::Object* object) +{ + AtkObject* accessible = NULL; + + g_return_val_if_fail(dynamic_cast<TextInput*>(object), NULL); + + accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_TEXT_INPUT_ACCESSIBLE, NULL)); + + atk_object_initialize(accessible, object); + + return accessible; +} + +static void +unity_text_input_accessible_initialize(AtkObject* accessible, + gpointer data) +{ + nux::Object* nux_object = NULL; + TextInput* text_input = NULL; + nux::TextEntry* text_entry = NULL; + + ATK_OBJECT_CLASS(unity_text_input_accessible_parent_class)->initialize(accessible, data); + + accessible->role = ATK_ROLE_PANEL; + + nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + text_input = dynamic_cast<TextInput*>(nux_object); + + if (text_input == NULL) + return; + + text_entry = text_input->text_entry(); + + if (text_entry != NULL) + { + AtkObject* text_entry_accessible = NULL; + text_entry_accessible = unity_a11y_get_accessible(text_entry); + atk_object_set_name(text_entry_accessible, text_input->input_hint().c_str()); + } +} diff --git a/a11y/unity-text-input-accessible.h b/a11y/unity-text-input-accessible.h new file mode 100644 index 000000000..c1ab85636 --- /dev/null +++ b/a11y/unity-text-input-accessible.h @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2014 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Andrea Azzarone <andrea.azzarone@canonical.com> + */ + +#ifndef UNITY_TEXT_INPUT_ACCESSIBLE_H +#define UNITY_TEXT_INPUT_ACCESSIBLE_H + +#include <atk/atk.h> + +#include "nux-view-accessible.h" + +G_BEGIN_DECLS + +#define UNITY_TYPE_TEXT_INPUT_ACCESSIBLE (unity_text_input_accessible_get_type ()) +#define UNITY_TEXT_INPUT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_TEXT_INPUT_ACCESSIBLE, UnityTextInputAccessible)) +#define UNITY_TEXT_INPUT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_TEXT_INPUT_ACCESSIBLE, UnityTextInputAccessibleClass)) +#define UNITY_IS_TEXT_INPUT_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_TEXT_INPUT_ACCESSIBLE)) +#define UNITY_IS_TEXT_INPUT_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_TEXT_INPUT_ACCESSIBLE)) +#define UNITY_TEXT_INPUT_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_TEXT_INPUT_ACCESSIBLE, UnityTextInputAccessibleClass)) + +typedef struct _UnityTextInputAccessible UnityTextInputAccessible; +typedef struct _UnityTextInputAccessibleClass UnityTextInputAccessibleClass; +typedef struct _UnityTextInputAccessiblePrivate UnityTextInputAccessiblePrivate; + +struct _UnityTextInputAccessible +{ + NuxViewAccessible parent; + + /*< private >*/ + UnityTextInputAccessiblePrivate* priv; +}; + +struct _UnityTextInputAccessibleClass +{ + NuxViewAccessibleClass parent_class; +}; + +GType unity_text_input_accessible_get_type(void); +AtkObject* unity_text_input_accessible_new(nux::Object* object); + +G_END_DECLS + +#endif diff --git a/a11y/unity-util-accessible.cpp b/a11y/unity-util-accessible.cpp new file mode 100644 index 000000000..b850cd2ea --- /dev/null +++ b/a11y/unity-util-accessible.cpp @@ -0,0 +1,493 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + * Rodrigo Moya <rodrigo.moya@canonical.com> + */ + +#include <gdk/gdk.h> +#include <stdlib.h> +#include <string.h> + +#include "unity-util-accessible.h" +#include "unity-root-accessible.h" + +#include "nux-base-window-accessible.h" + +static void unity_util_accessible_class_init(UnityUtilAccessibleClass* klass); +static void unity_util_accessible_init(UnityUtilAccessible* unity_util_accessible); + +/* atkutil.h */ + +static guint unity_util_accessible_add_global_event_listener(GSignalEmissionHook listener, + const gchar* event_type); +static void unity_util_accessible_remove_global_event_listener(guint remove_listener); +static AtkObject* unity_util_accessible_get_root(void); +static const gchar* unity_util_accessible_get_toolkit_name(void); +static const gchar* unity_util_accessible_get_toolkit_version(void); +static guint unity_util_accessible_add_key_event_listener(AtkKeySnoopFunc listener, + gpointer data); +static void unity_util_accessible_remove_key_event_listener(guint remove_listener); + +typedef struct +{ + guint idx; + gulong hook_id; + guint signal_id; +} UnityUtilListenerInfo; + +typedef struct +{ + AtkKeySnoopFunc func; + gpointer data; + guint key; +} UnityKeyEventListener; + +/* FIXME: move this to a private structure on UnityUtilAccessible? */ +static GHashTable* listener_list = NULL; +static AtkObject* root = NULL; +static GSList* key_listener_list = NULL; +static guint event_inspector_id = 0; +static nux::WindowThread* unity_window_thread = NULL; + +G_DEFINE_TYPE(UnityUtilAccessible, unity_util_accessible, ATK_TYPE_UTIL); + +static void +unity_util_accessible_class_init(UnityUtilAccessibleClass* klass) +{ + AtkUtilClass* atk_class; + gpointer data; + + data = g_type_class_peek(ATK_TYPE_UTIL); + atk_class = ATK_UTIL_CLASS(data); + + atk_class->add_global_event_listener = unity_util_accessible_add_global_event_listener; + atk_class->remove_global_event_listener = unity_util_accessible_remove_global_event_listener; + atk_class->add_key_event_listener = unity_util_accessible_add_key_event_listener; + atk_class->remove_key_event_listener = unity_util_accessible_remove_key_event_listener; + atk_class->get_root = unity_util_accessible_get_root; + atk_class->get_toolkit_name = unity_util_accessible_get_toolkit_name; + atk_class->get_toolkit_version = unity_util_accessible_get_toolkit_version; +} + +static void +unity_util_accessible_init(UnityUtilAccessible* unity_util_accessible) +{ +} + +static AtkObject* +unity_util_accessible_get_root(void) +{ + if (!root) + root = unity_root_accessible_new(); + + return root; +} + +static const gchar* +unity_util_accessible_get_toolkit_name(void) +{ + return "UNITY"; +} + +static const gchar* +unity_util_accessible_get_toolkit_version(void) +{ + /* + * FIXME: + * Version is passed in as a -D flag when this file is + * compiled. + */ + return "0.1"; +} + +static guint +add_listener(GSignalEmissionHook listener, + const gchar* object_type, + const gchar* signal_name, + const gchar* hook_data) +{ + GType type; + guint signal_id; + guint rc = 0; + static guint listener_idx = 1; + + if (!listener_list) + listener_list = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, g_free); + + type = g_type_from_name(object_type); + if (type) + { + signal_id = g_signal_lookup(signal_name, type); + if (signal_id > 0) + { + UnityUtilListenerInfo* listener_info; + + rc = listener_idx; + listener_info = g_new0(UnityUtilListenerInfo, 1); + listener_info->idx = listener_idx; + listener_info->hook_id = g_signal_add_emission_hook(signal_id, 0, listener, + g_strdup(hook_data), + (GDestroyNotify) g_free); + listener_info->signal_id = signal_id; + + g_hash_table_insert(listener_list, &(listener_info->idx), listener_info); + + listener_idx++; + } + else + { + /* Mainly becase some "window::xxx" methods not implemented + on NuxBaseWindowAccessible */ + g_debug("Signal type %s not supported\n", signal_name); + } + } + else + g_warning("Invalid object type %s\n", object_type); + + return rc; +} + +static void +do_window_event_initialization(void) +{ + /* + * Ensure that NuxBaseWindowClass exists + */ + g_type_class_unref(g_type_class_ref(NUX_TYPE_BASE_WINDOW_ACCESSIBLE)); +} + +static guint +unity_util_accessible_add_global_event_listener(GSignalEmissionHook listener, + const gchar* event_type) +{ + gchar** split_string; + guint rc = 0; + + split_string = g_strsplit(event_type, ":", 3); + if (split_string) + { + if (g_str_equal("window", split_string[0])) + { + /* Using NuxBaseWindow as the toplevelwindow */ + static gboolean initialized = FALSE; + + if (initialized == FALSE) + { + do_window_event_initialization(); + initialized = TRUE; + } + + rc = add_listener(listener, "NuxBaseWindowAccessible", split_string [1], event_type); + } + else + { + rc = add_listener(listener, split_string[1], split_string[2], event_type); + } + + g_strfreev(split_string); + } + + return rc; +} + +static void +unity_util_accessible_remove_global_event_listener(guint remove_listener) +{ + if (remove_listener > 0) + { + UnityUtilListenerInfo* listener_info; + + listener_info = (UnityUtilListenerInfo*) g_hash_table_lookup(listener_list, &remove_listener); + if (listener_info != NULL) + { + if (listener_info->hook_id != 0 && listener_info->signal_id != 0) + { + g_signal_remove_emission_hook(listener_info->signal_id, + listener_info->hook_id); + g_hash_table_remove(listener_list, &remove_listener); + } + else + { + g_warning("Invalid listener hook_id %ld or signal_id %d", + listener_info->hook_id, listener_info->signal_id); + } + } + else + g_warning("No listener with the specified ID: %d", remove_listener); + } + else + g_warning("Invalid listener_id: %d", remove_listener); +} + +static guint +translate_nux_modifiers_to_gdk_state(unsigned long nux_modifier) +{ + guint result = 0; + + if (nux_modifier & nux::NUX_STATE_SHIFT) + result |= GDK_SHIFT_MASK; + + if (nux_modifier & nux::NUX_STATE_CAPS_LOCK) + result |= GDK_LOCK_MASK; + + if (nux_modifier & nux::NUX_STATE_CTRL) + result |= GDK_CONTROL_MASK; + + /* From gdk documentation + + GDK_MOD1_MASK : the fourth modifier key (it depends on the + modifier mapping of the X server which key is interpreted as this + modifier, but normally it is the Alt key). + */ + + if (nux_modifier & nux::NUX_STATE_ALT) + result |= GDK_MOD1_MASK; + + /* FIXME: not sure how to translate this ones */ + // if (nux_modifier & NUX_STATE_SCROLLLOCK) + // if (nux_modifier & NUX_STATE_NUMLOCK) + + return result; +} + +static AtkKeyEventStruct* +atk_key_event_from_nux_event_key(nux::Event* event) +{ + AtkKeyEventStruct* atk_event = g_new0(AtkKeyEventStruct, 1); + gunichar key_unichar; + static GdkDisplay* display = gdk_display_get_default(); + static GdkKeymap* keymap = gdk_keymap_get_for_display(display); + GdkKeymapKey* keys = NULL; + gint n_keys = 0; + gboolean success = FALSE; + + switch (event->type) + { + case nux::NUX_KEYDOWN: + atk_event->type = ATK_KEY_EVENT_PRESS; + break; + case nux::NUX_KEYUP: + atk_event->type = ATK_KEY_EVENT_RELEASE; + break; + default: + /* we don't call atk_key_event_from_nux_event_key if the event + is different to keydown or keyup */ + g_assert_not_reached(); + g_free(atk_event); + return NULL; + } + + atk_event->state = translate_nux_modifiers_to_gdk_state(event->key_modifiers); + + atk_event->keyval = event->x11_keysym; + atk_event->keycode = event->x11_keycode; + + /* GDK applies the modifiers to the keyval, and ATK expects that, so + * we need to do this also here, as it is not done on the release */ + + success = gdk_keymap_get_entries_for_keyval(keymap, atk_event->keyval, + &keys, &n_keys); + success &= n_keys > 0; + + if (success) + { + gint group; + guint new_keyval; + gint effective_group; + gint level; + GdkModifierType consumed; + + group = keys [0].group; + + success = gdk_keymap_translate_keyboard_state(keymap, + atk_event->keycode, + (GdkModifierType) atk_event->state, + group, + &new_keyval, + &effective_group, + &level, + &consumed); + if (success) + atk_event->keyval = new_keyval; + } + + atk_event->string = NULL; + if (event->text && event->text[0]) + { + key_unichar = g_utf8_get_char(event->text); + + if (g_unichar_validate(key_unichar) && g_unichar_isgraph(key_unichar)) + { + GString* new_string = NULL; + + new_string = g_string_new(""); + new_string = g_string_insert_unichar(new_string, 0, key_unichar); + atk_event->string = new_string->str; + g_string_free(new_string, FALSE); + } + } + + /* If ->string is still NULL we compute it from the keyval*/ + if (atk_event->string == NULL) + atk_event->string = g_strdup(gdk_keyval_name(atk_event->keyval)); + + /* e_x11_timestamp is zero, see bug LB#735645*/ + atk_event->timestamp = g_get_real_time() / 1000; + +#ifdef DEBUG_ANY_KEY_EVENT + g_debug("[a11y] AtkKeyEvent:\n\t\tsym 0x%x\n\t\tmods %x\n\t\tcode %u\n\t\ttime %lx \n\t\tstring %s\n", + (unsigned int) atk_event->keyval, + (unsigned int) atk_event->state, + (unsigned int) atk_event->keycode, + (unsigned long int) atk_event->timestamp, + atk_event->string); +#endif + + return atk_event; +} + +static int +unity_util_event_inspector(nux::Area* area, + nux::Event* event, + void* data) +{ + GSList* list = NULL; + AtkKeyEventStruct* atk_key_event = NULL; + gint result = 0; + + if ((event->type != nux::NUX_KEYDOWN) && (event->type != nux::NUX_KEYUP)) + return 0; + + atk_key_event = atk_key_event_from_nux_event_key(event); + + for (list = key_listener_list; list; list = list->next) + { + UnityKeyEventListener* listener = (UnityKeyEventListener*) list->data; + + result |= listener->func(atk_key_event, listener->data); + } + + g_free(atk_key_event->string); + g_free(atk_key_event); + + return result; +} + +static guint +unity_util_accessible_add_key_event_listener(AtkKeySnoopFunc listener_func, + gpointer data) +{ + static guint key = 0; + UnityKeyEventListener* listener; + + if (event_inspector_id == 0) + { + if (unity_window_thread == NULL) + return 0; + + event_inspector_id = unity_window_thread->InstallEventInspector(unity_util_event_inspector, NULL); + } + + key++; + + listener = g_slice_new0(UnityKeyEventListener); + listener->func = listener_func; + listener->data = data; + listener->key = key; + + key_listener_list = g_slist_append(key_listener_list, listener); + + return key; +} + +static void +unity_util_accessible_remove_key_event_listener(guint remove_listener) +{ + GSList* l; + + for (l = key_listener_list; l; l = l->next) + { + UnityKeyEventListener* listener = (UnityKeyEventListener*) l->data; + + if (listener->key == remove_listener) + { + g_slice_free(UnityKeyEventListener, listener); + key_listener_list = g_slist_delete_link(key_listener_list, l); + + break; + } + } + + if (key_listener_list == NULL) + { + if (unity_window_thread == NULL) + return; + + unity_window_thread->RemoveEventInspector(event_inspector_id); + event_inspector_id = 0; + } +} + +/* Public */ +void +unity_util_accessible_set_window_thread(nux::WindowThread* wt) +{ + unity_window_thread = wt; +} + +/* + * FIXME: temporal solution + * + * Normally not all the accessible objects on the hierarchy are + * available from the beginning, and they are being created by demand + * due the request on the AT (ie: orca) side + * + * It usually follows a top-down approach. Top objects emits a signal + * of interest, so AT apps get interest on it, and request their + * children. One example is the signal "window::activate". AT receives + * a signal meaning that a top level object is activated, so request + * their children (and gran-children). + * + * Due technical reasons, right now it is hard to find a suitable way + * to emit the signal "activate" on the BaseWindow. That means that + * objects on the bottom of the hierarchy are not created, so Orca + * doesn't react to changes on sections like the Launcher. + * + * So in order to prevent that, we make a manual exploration of the + * hierarchy in order to ensure that those objects are there. + * + * NOTE: this manual exploration is not required with at-spi2, just + * with at-spi. + * + */ +void +explore_children(AtkObject* obj) +{ + gint num = 0; + gint i = 0; + AtkObject* atk_child = NULL; + + g_return_if_fail(ATK_IS_OBJECT(obj)); + + num = atk_object_get_n_accessible_children(obj); + + for (i = 0; i < num; i++) + { + atk_child = atk_object_ref_accessible_child(obj, i); + explore_children(atk_child); + g_object_unref(atk_child); + } +} diff --git a/a11y/unity-util-accessible.h b/a11y/unity-util-accessible.h new file mode 100644 index 000000000..8ed12d037 --- /dev/null +++ b/a11y/unity-util-accessible.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_UTIL_ACCESSIBLE_H +#define UNITY_UTIL_ACCESSIBLE_H + +#include <atk/atk.h> + +#include <Nux/Nux.h> +#include <Nux/BaseWindow.h> + +G_BEGIN_DECLS + +#define UNITY_TYPE_UTIL_ACCESSIBLE (unity_util_accessible_get_type ()) +#define UNITY_UTIL_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), UNITY_TYPE_UTIL_ACCESSIBLE, UnityUtilAccessible)) +#define UNITY_UTIL_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), UNITY_TYPE_UTIL_ACCESSIBLE, UnityUtilAccessibleClass)) +#define UNITY_IS_UTIL_ACCESSIBLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), UNITY_TYPE_UTIL_ACCESSIBLE)) +#define UNITY_IS_UTIL_ACCESSIBLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), UNITY_TYPE_UTIL_ACCESSIBLE)) +#define UNITY_UTIL_ACCESSIBLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), UNITY_TYPE_UTIL_ACCESSIBLE, UnityUtilAccessibleClass)) + +typedef struct _UnityUtilAccessible UnityUtilAccessible; +typedef struct _UnityUtilAccessibleClass UnityUtilAccessibleClass; +typedef struct _UnityUtilAccessiblePrivate UnityUtilAccessiblePrivate; + +struct _UnityUtilAccessible +{ + AtkUtil parent; + + /* < private > */ + UnityUtilAccessiblePrivate* priv; +}; + +struct _UnityUtilAccessibleClass +{ + AtkUtilClass parent_class; +}; + +GType unity_util_accessible_get_type(void); + +void unity_util_accessible_set_window_thread(nux::WindowThread* wt); +void explore_children(AtkObject* obj); + +G_END_DECLS + +#endif /* UNITY_UTIL_ACCESSIBLE_H */ diff --git a/a11y/unitya11y.cpp b/a11y/unitya11y.cpp new file mode 100644 index 000000000..bcd670f5a --- /dev/null +++ b/a11y/unitya11y.cpp @@ -0,0 +1,318 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#include <glib.h> +#include <gio/gio.h> +#include <gmodule.h> +#include <stdio.h> +#include <atk-bridge.h> + +#include "unitya11y.h" +#include "unitya11ytests.h" +#include "unity-util-accessible.h" + +/* nux accessible objects */ +#include "nux-view-accessible.h" +#include "nux-base-window-accessible.h" +#include "nux-layout-accessible.h" +#include "nux-text-entry-accessible.h" + +/* unity accessible objects */ +#include "Launcher.h" +#include "LauncherIcon.h" +#include "SimpleLauncherIcon.h" +#include "PanelView.h" +#include "DashView.h" +#include "PlacesGroup.h" +#include "ExpanderView.h" +#include "QuicklistView.h" +#include "QuicklistMenuItem.h" +#include "SwitcherView.h" +#include "TextInput.h" +#include "SessionButton.h" +#include "FilterBasicButton.h" +#include "unity-launcher-accessible.h" +#include "unity-launcher-icon-accessible.h" +#include "unity-panel-view-accessible.h" +#include "unity-dash-view-accessible.h" +#include "unity-scope-bar-icon-accessible.h" +#include "unity-search-bar-accessible.h" +#include "unity-sctext-accessible.h" +#include "unity-rvgrid-accessible.h" +#include "unity-places-group-accessible.h" +#include "unity-expander-view-accessible.h" +#include "unity-quicklist-accessible.h" +#include "unity-quicklist-menu-item-accessible.h" +#include "unity-switcher-accessible.h" +#include "unity-text-input-accessible.h" +#include "unity-session-button-accessible.h" +#include "unity-filter-basic-button-accessible.h" + +using namespace unity; +using namespace unity::dash; +using namespace unity::launcher; +using namespace unity::panel; +using namespace unity::session; + +static GHashTable* accessible_table = NULL; +/* FIXME: remove accessible objects when not required anymore */ + +static gboolean a11y_initialized = FALSE; + +static void +unity_a11y_restore_environment(void) +{ + g_unsetenv("NO_AT_BRIDGE"); + g_unsetenv("NO_GAIL"); +} + +static void +load_unity_atk_util(nux::WindowThread* wt) +{ + unity_util_accessible_set_window_thread(wt); + g_type_class_unref(g_type_class_ref(UNITY_TYPE_UTIL_ACCESSIBLE)); +} + +/* + * In order to avoid the atk-bridge loading and the GAIL + * initialization during the gtk_init, it is required to set some + * environment vars. + * + */ +void +unity_a11y_preset_environment(void) +{ + g_setenv("NO_AT_BRIDGE", "1", TRUE); + g_setenv("NO_GAIL", "1", TRUE); +} + +/* + * Initializes the accessibility (ATK) support on Unity + * + */ +void +unity_a11y_init(nux::WindowThread* wt) +{ + if (a11y_initialized) + return; + + unity_a11y_restore_environment(); + load_unity_atk_util(wt); + atk_bridge_adaptor_init(NULL, NULL); + atk_get_root(); + + a11y_initialized = TRUE; + +// NOTE: we run the unit tests manually while developing by +// uncommenting this. Take a look at the explanation in the +// unitya11ytests.h header for more information + +// unity_run_a11y_unit_tests (); +} + +/* + * Finalize the issues related with accessibility. + * + * It mainly cleans the resources related with accessibility + */ +void +unity_a11y_finalize(void) +{ + if (accessible_table != NULL) + { + g_hash_table_unref(accessible_table); + accessible_table = NULL; + } + a11y_initialized = FALSE; +} + + +/* + * Creates the accessible object for a nux::Area object + * + * Method factory, equivalent to + * atk_object_factory_creeate_accessible, but required because + * AtkObjectFactory gives only support for GObject classes. + * + * FIXME: this should be a temporal method. The best way to implement + * that would be add a ->get_accessible method on the nux::View + * subclasses itself. + * + * WARNING: as a reason the previous comment is true. Take into + * account that you should be careful with the order in which you add + * those defines. The order will be from more specific classes to more + * abstracted classes. + * + */ + +static AtkObject* +unity_a11y_create_accessible(nux::Object* object) +{ + /* UNITY classes*/ + if (object->Type().IsDerivedFromType(Launcher::StaticObjectType)) + return unity_launcher_accessible_new(object); + + if (object->Type().IsDerivedFromType(LauncherIcon::StaticObjectType)) + return unity_launcher_icon_accessible_new(object); + + if (object->Type().IsDerivedFromType(PanelView::StaticObjectType)) + return unity_panel_view_accessible_new(object); + + if (object->Type().IsDerivedFromType(DashView::StaticObjectType)) + return unity_dash_view_accessible_new(object); + + if (object->Type().IsDerivedFromType(ScopeBarIcon::StaticObjectType)) + return unity_scope_bar_icon_accessible_new(object); + + if (object->Type().IsDerivedFromType(PlacesGroup::StaticObjectType)) + return unity_places_group_accessible_new(object); + + if (object->Type().IsDerivedFromType(ExpanderView::StaticObjectType)) + return unity_expander_view_accessible_new(object); + + if (object->Type().IsDerivedFromType(FilterBasicButton::StaticObjectType)) + return unity_filter_basic_button_accessible_new(object); + + if (object->Type().IsDerivedFromType(QuicklistView::StaticObjectType)) + return unity_quicklist_accessible_new(object); + + if (object->Type().IsDerivedFromType(QuicklistMenuItem::StaticObjectType)) + return unity_quicklist_menu_item_accessible_new(object); + + if (object->Type().IsDerivedFromType(StaticCairoText::StaticObjectType)) + return unity_sctext_accessible_new(object); + + if (object->Type().IsDerivedFromType(unity::dash::ResultViewGrid::StaticObjectType)) + return unity_rvgrid_accessible_new(object); + + if (object->Type().IsDerivedFromType(unity::SearchBar::StaticObjectType)) + return unity_search_bar_accessible_new(object); + + if (object->Type().IsDerivedFromType(unity::TextInput::StaticObjectType)) + return unity_text_input_accessible_new(object); + + if (object->Type().IsDerivedFromType(unity::switcher::SwitcherView::StaticObjectType)) + return unity_switcher_accessible_new(object); + + if (object->Type().IsDerivedFromType(Button::StaticObjectType)) + return unity_session_button_accessible_new(object); + + /* NUX classes */ + if (object->Type().IsDerivedFromType(nux::TextEntry::StaticObjectType)) + return nux_text_entry_accessible_new(object); + + if (object->Type().IsDerivedFromType(nux::BaseWindow::StaticObjectType)) + return nux_base_window_accessible_new(object); + + if (object->Type().IsDerivedFromType(nux::View::StaticObjectType)) + return nux_view_accessible_new(object); + + if (object->Type().IsDerivedFromType(nux::Layout::StaticObjectType)) + return nux_layout_accessible_new(object); + + if (object->Type().IsDerivedFromType(nux::Area::StaticObjectType)) + return nux_area_accessible_new(object); + + return nux_object_accessible_new(object); +} + +static void +on_object_destroy_cb(nux::Object* base_object, + AtkObject* accessible_object) +{ + /* NOTE: the pair key:value (base_object:accessible_object) could be + already removed on on_accessible_destroy_cb. That just means that + g_hash_table_remove would return FALSE. We don't add a + debug/warning message to avoid being too verbose */ + + g_hash_table_remove(accessible_table, base_object); +} + +static void +on_accessible_destroy_cb(gpointer data, + GObject* where_the_object_was) +{ + /* NOTE: the pair key:value (base_object:accessible_object) could be + already removed on on_object_destroy_cb. That just means that + g_hash_table_remove would return FALSE. We don't add a + debug/warning message to avoid being too verbose */ + + g_hash_table_remove(accessible_table, data); +} + +/* + * Returns the accessible object of a nux::View object + * + * This method tries to: + * * Check if area already has a accessibility object + * * If this is the case, return that + * * If not, create it and return the object + * + * FIXME: this should be a temporal method. The best way to implement + * that would be add a ->get_accessible method on the nux::View + * subclasses itself. + * + */ +AtkObject* +unity_a11y_get_accessible(nux::Object* object) +{ + AtkObject* accessible_object = NULL; + + g_return_val_if_fail(object != NULL, NULL); + + if (accessible_table == NULL) + { + accessible_table = g_hash_table_new(g_direct_hash, g_direct_equal); + } + + accessible_object = ATK_OBJECT(g_hash_table_lookup(accessible_table, object)); + if (accessible_object == NULL) + { + accessible_object = unity_a11y_create_accessible(object); + + g_hash_table_insert(accessible_table, object, accessible_object); + + /* there are two reasons the object should be removed from the + * table: base object destroyed or accessible object + * destroyed + */ + g_object_weak_ref(G_OBJECT(accessible_object), + on_accessible_destroy_cb, + object); + + object->OnDestroyed.connect(sigc::bind(sigc::ptr_fun(on_object_destroy_cb), + accessible_object)); + } + + return accessible_object; +} + +/* + * Returns if the accessibility support is properly initialized + */ +gboolean unity_a11y_initialized(void) +{ + return a11y_initialized; +} + +/* Returns the accessible_table. Just for unit testing purposes, you + should not require to use it */ +GHashTable* _unity_a11y_get_accessible_table() +{ + return accessible_table; +} diff --git a/a11y/unitya11y.h b/a11y/unitya11y.h new file mode 100644 index 000000000..37b81e515 --- /dev/null +++ b/a11y/unitya11y.h @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_A11Y_H +#define UNITY_A11Y_H + +#include <atk/atk.h> + +#include <Nux/Nux.h> +#include <Nux/WindowThread.h> +#include <NuxCore/Object.h> + +void unity_a11y_preset_environment(void); +void unity_a11y_init(nux::WindowThread* wt); +void unity_a11y_finalize(void); + +AtkObject* unity_a11y_get_accessible(nux::Object* object); + +gboolean unity_a11y_initialized(void); + +/* For unit test purposes */ + +GHashTable* _unity_a11y_get_accessible_table(); + +#endif /* UNITY_A11Y_H */ diff --git a/a11y/unitya11ytests.cpp b/a11y/unitya11ytests.cpp new file mode 100644 index 000000000..efc7968ca --- /dev/null +++ b/a11y/unitya11ytests.cpp @@ -0,0 +1,333 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#include "unitya11ytests.h" + +#include <glib.h> + +#include "unitya11y.h" +#include "unity-util-accessible.h" + +/* nux accessible objects */ +#include "nux-view-accessible.h" +#include "nux-base-window-accessible.h" +#include "nux-layout-accessible.h" + +/* unity accessible objects */ +#include <Nux/Button.h> + +#include "Launcher.h" +#include "LauncherIcon.h" +#include "SimpleLauncherIcon.h" +#include "PanelView.h" +#include "DashView.h" +#include "unity-launcher-accessible.h" +#include "unity-launcher-icon-accessible.h" +#include "unity-panel-view-accessible.h" + +using unity::launcher::Launcher; +using unity::launcher::LauncherIcon; +using unity::launcher::SimpleLauncherIcon; + +/* + * This unit test checks if the destroy management is working: + * + * - If the state of a accessibility object is properly updated after + * the object's destruction + * + */ +static gboolean +a11y_unit_test_destroy_management(void) +{ + unity::QuicklistView* quicklist = NULL; + AtkObject* accessible = NULL; + nux::Object* base_object = NULL; + AtkStateSet* state_set = NULL; + + quicklist = new unity::QuicklistView(); + quicklist->SinkReference(); + accessible = unity_a11y_get_accessible(quicklist); + + base_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + if (base_object != quicklist) + { + g_debug("[a11y] destroy management unit test: base object" + " different to the original one"); + return FALSE; + } + + if (quicklist->UnReference() == false) + { + g_debug("[a11y] destroy management unit test: base object not destroyed"); + return FALSE; + } + + base_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible)); + if (base_object != NULL) + { + g_debug("[a11y] destroy management unit test: base object" + " not NULL after base object destruction"); + return FALSE; + } + + state_set = atk_object_ref_state_set(accessible); + if (!atk_state_set_contains_state(state_set, ATK_STATE_DEFUNCT)) + { + g_debug("[a11y] destroy management unit test: accessible object" + " doesn't include DEFUNCT state"); + return FALSE; + } + + g_object_unref(state_set); + g_object_unref(accessible); + + return TRUE; +} + +/** + * This unit test checks if the hash table destroy management is working: + * + * - If the hash table removes properly the accessible object once it + * is destroyed. + */ +static gboolean +a11y_unit_test_hash_table_destroy_management(void) +{ + unity::QuicklistView* quicklist = NULL; + nux::Layout* layout = NULL; + AtkObject* accessible = NULL; + guint prev_hash_size = 0; + guint hash_size = 0; + + /* test the hash table management with the accessible destroy */ + + prev_hash_size = g_hash_table_size(_unity_a11y_get_accessible_table()); + + layout = new nux::Layout(); + layout->SinkReference(); + accessible = unity_a11y_get_accessible(layout); + + if (accessible == NULL) + { + g_debug("[a11y] hash table destroy management unit test: error creating" + " the accessible object (accessible == NULL)"); + return FALSE; + } + + hash_size = g_hash_table_size(_unity_a11y_get_accessible_table()); + + if ((hash_size - prev_hash_size) != 1) + { + g_debug("[a11y] hash table destroy management unit test: accessible object" + " not added to the hash table after his creation"); + return FALSE; + } + + prev_hash_size = g_hash_table_size(_unity_a11y_get_accessible_table()); + + g_object_unref(accessible); + + hash_size = g_hash_table_size(_unity_a11y_get_accessible_table()); + + if ((prev_hash_size - hash_size) != 1) + { + g_debug("[a11y] hash table destroy management unit test: accessible object" + " not removed from the hash table after his destruction"); + return FALSE; + } + + layout->UnReference(); + + /* Test the hash table management after the object destroy */ + + prev_hash_size = g_hash_table_size(_unity_a11y_get_accessible_table()); + + quicklist = new unity::QuicklistView(); + quicklist->SinkReference(); + accessible = unity_a11y_get_accessible(quicklist); + + if (accessible == NULL) + { + g_debug("[a11y] hash table destroy management unit test: error creating" + " the accessible object (accessible == NULL)"); + return FALSE; + } + + hash_size = g_hash_table_size(_unity_a11y_get_accessible_table()); + + if ((hash_size - prev_hash_size) != 1) + { + g_debug("[a11y] hash table destroy management unit test: accessible object" + " not added to the hash table after his creation"); + return FALSE; + } + + prev_hash_size = g_hash_table_size(_unity_a11y_get_accessible_table()); + + if (quicklist->UnReference() == false) + { + g_debug("[a11y] hash table destroy management unit test: base object not destroyed"); + return FALSE; + } + + hash_size = g_hash_table_size(_unity_a11y_get_accessible_table()); + + if ((prev_hash_size - hash_size) != 1) + { + g_debug("[a11y] hash table destroy management unit test: accessible object" + " not removed from the hash table after base object destruction"); + return FALSE; + } + + return TRUE; +} + +/** + * This unit test checks if the launcher connection process works + */ +static gboolean +a11y_unit_test_launcher_connection(void) +{ + Launcher* launcher = NULL; + unity::MockableBaseWindow* window = NULL; + AtkObject* launcher_accessible = NULL; + LauncherIcon* launcher_icon = NULL; + AtkObject* launcher_icon_accessible = NULL; + + window = new unity::MockableBaseWindow(TEXT("")); + launcher = new Launcher(window, NULL); + launcher->SinkReference(); + launcher_accessible = unity_a11y_get_accessible(launcher); + + if (!UNITY_IS_LAUNCHER_ACCESSIBLE(launcher_accessible)) + { + g_debug("[a11y] wrong launcher accessible type"); + return FALSE; + } + else + { + g_debug("[a11y] Launcher accessible created correctly"); + } + + launcher_icon = new SimpleLauncherIcon(unity::launcher::AbstractLauncherIcon::IconType::NONE); + launcher_icon->SinkReference(); + launcher_icon_accessible = unity_a11y_get_accessible(launcher_icon); + + if (!UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(launcher_icon_accessible)) + { + g_debug("[a11y] wrong launcher icon accessible type"); + return FALSE; + } + else + { + g_debug("[a11y] LauncherIcon accessible created correctly"); + } + + launcher->UnReference(); + launcher_icon->UnReference(); + + return TRUE; +} + +/** + * This unit test checks if the launcher connection process works + */ +static gboolean +a11y_unit_test_children_addition(void) +{ + nux::View* view[3]; + AtkObject* view_accessible[3]; + nux::Layout* layout[2]; + AtkObject* layout_accessible[2]; + gint i = 0; + + /* Test setting a layout on a view */ + view[0] = new nux::Button("Test"); + view[0]->SinkReference(); + view_accessible[0] = unity_a11y_get_accessible(view[0]); + + for (i = 0; i < 2; i++) + { + layout[i] = new nux::Layout(); + layout[i]->SinkReference(); + layout_accessible[i] = unity_a11y_get_accessible(layout[i]); + } + + view[0]->SetLayout(layout[0]); + view[0]->SetLayout(layout[0]); + + view[0]->UnReference(); + g_object_unref(view_accessible[0]); + + for (i = 0; i < 2; i++) + { + layout[i]->UnReference(); + g_object_unref(layout_accessible[i]); + } + + /* Test adding a view on a layout */ + layout[0] = new nux::Layout(); + layout[0]->SinkReference(); + layout_accessible[0] = unity_a11y_get_accessible(layout[0]); + + for (i = 0; i < 3; i ++) + { + view[i] = new nux::Button("Test"); + view[i]->SinkReference(); + view_accessible[i] = unity_a11y_get_accessible(view[i]); + + layout[0]->AddView(view[i]); + } + + /* when this is removed it should be notified the removal with index 1*/ + layout[0]->RemoveChildObject(view[1]); + layout[0]->UnReference(); + for (i = 0; i < 3; i++) + { + view[i]->UnReference(); + g_object_unref(view_accessible [i]); + } + + return TRUE; +} + +/* public */ + +void +unity_run_a11y_unit_tests(void) +{ + if (a11y_unit_test_destroy_management()) + g_debug("[a11y] destroy management unit test: SUCCESS"); + else + g_debug("[a11y] destroy management unit test: FAIL"); + + if (a11y_unit_test_hash_table_destroy_management()) + g_debug("[a11y] hash table destroy management unit test: SUCCESS"); + else + g_debug("[a11y] hash table destroy management unit test: FAIL"); + + if (a11y_unit_test_launcher_connection()) + g_debug("[a11y] launcher connection: SUCCESS"); + else + g_debug("[a11y] launcher connection: FAIL"); + + if (a11y_unit_test_children_addition()) + g_debug("[a11y] children addition: SUCCESS"); + else + g_debug("[a11y] children addition: FAIL"); +} diff --git a/a11y/unitya11ytests.h b/a11y/unitya11ytests.h new file mode 100644 index 000000000..cfb3631b3 --- /dev/null +++ b/a11y/unitya11ytests.h @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * Authored by: Alejandro Piñeiro Iglesias <apinheiro@igalia.com> + */ + +#ifndef UNITY_A11Y_TESTS_H +#define UNITY_A11Y_TESTS_H + +/* For the moment we can't add the a11y tests to the current unity + tests, as it would require to include the Launcher, that right now + include symbols only available to a compiz plugin (so not available + for a standalone app. + + So right now this tests are executed by hand during the developing + of the accessibility support, but not executed as a standalone test. + + When the Launcher thing became solved (as planned), this tests + would be moved/adapted to the unity test system */ + +void unity_run_a11y_unit_tests(void); + +#endif /* UNITY_A11Y_H */ |
