Back to index

unity  6.0.0
nux-view-accessible.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2011 Canonical Ltd
00003  *
00004  * This program is free software: you can redistribute it and/or modify
00005  * it under the terms of the GNU General Public License version 3 as
00006  * published by the Free Software Foundation.
00007  *
00008  * This program is distributed in the hope that it will be useful,
00009  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00010  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011  * GNU General Public License for more details.
00012  *
00013  * You should have received a copy of the GNU General Public License
00014  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00015  *
00016  * Authored by: Alejandro PiƱeiro Iglesias <apinheiro@igalia.com>
00017  */
00018 
00030 #include "nux-view-accessible.h"
00031 #include "unitya11y.h"
00032 #include "nux-base-window-accessible.h"
00033 
00034 #include <Nux/Layout.h>
00035 #include <Nux/Area.h>
00036 
00037 /* GObject */
00038 static void nux_view_accessible_class_init(NuxViewAccessibleClass* klass);
00039 static void nux_view_accessible_init(NuxViewAccessible* view_accessible);
00040 
00041 /* AtkObject.h */
00042 static void         nux_view_accessible_initialize(AtkObject* accessible,
00043                                                    gpointer   data);
00044 static AtkStateSet* nux_view_accessible_ref_state_set(AtkObject* obj);
00045 static gint         nux_view_accessible_get_n_children(AtkObject* obj);
00046 static AtkObject*   nux_view_accessible_ref_child(AtkObject* obj,
00047                                                   gint i);
00048 static AtkStateSet* nux_view_accessible_ref_state_set(AtkObject* obj);
00049 static gint         nux_view_accessible_get_n_children(AtkObject* obj);
00050 static AtkObject*   nux_view_accessible_ref_child(AtkObject* obj,
00051                                                   gint i);
00052 /* NuxAreaAccessible */
00053 static gboolean      nux_view_accessible_check_pending_notification(NuxAreaAccessible* self);
00054 
00055 /* private methods */
00056 static void on_layout_changed_cb(nux::View* view,
00057                                  nux::Layout* layout,
00058                                  AtkObject* accessible,
00059                                  gboolean is_add);
00060 static void on_change_keyboard_receiver_cb(AtkObject* accessible,
00061                                            gboolean focus_in);
00062 
00063 G_DEFINE_TYPE(NuxViewAccessible,
00064               nux_view_accessible,
00065               NUX_TYPE_AREA_ACCESSIBLE)
00066 
00067 #define NUX_VIEW_ACCESSIBLE_GET_PRIVATE(obj) \
00068   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), NUX_TYPE_VIEW_ACCESSIBLE,        \
00069                                 NuxViewAccessiblePrivate))
00070 
00071 struct _NuxViewAccessiblePrivate
00072 {
00073   /* focused using InputArea OnStartKeyboardReceiver and OnStop... signals */
00074   gboolean key_focused;
00075 
00076   /* if the state from key_focused was notified or not */
00077   gboolean pending_notification;
00078 };
00079 
00080 
00081 static void
00082 nux_view_accessible_class_init(NuxViewAccessibleClass* klass)
00083 {
00084   GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
00085   AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass);
00086   NuxAreaAccessibleClass* area_class = NUX_AREA_ACCESSIBLE_CLASS(klass);
00087 
00088   /* AtkObject */
00089   atk_class->initialize = nux_view_accessible_initialize;
00090   atk_class->ref_state_set = nux_view_accessible_ref_state_set;
00091   atk_class->ref_child = nux_view_accessible_ref_child;
00092   atk_class->get_n_children = nux_view_accessible_get_n_children;
00093 
00094   /* NuxAreaAccessible */
00095   area_class->check_pending_notification = nux_view_accessible_check_pending_notification;
00096 
00097   g_type_class_add_private(gobject_class, sizeof(NuxViewAccessiblePrivate));
00098 }
00099 
00100 static void
00101 nux_view_accessible_init(NuxViewAccessible* view_accessible)
00102 {
00103   NuxViewAccessiblePrivate* priv =
00104     NUX_VIEW_ACCESSIBLE_GET_PRIVATE(view_accessible);
00105 
00106   view_accessible->priv = priv;
00107 }
00108 
00109 AtkObject*
00110 nux_view_accessible_new(nux::Object* object)
00111 {
00112   AtkObject* accessible = NULL;
00113 
00114   g_return_val_if_fail(dynamic_cast<nux::View*>(object), NULL);
00115 
00116   accessible = ATK_OBJECT(g_object_new(NUX_TYPE_VIEW_ACCESSIBLE, NULL));
00117 
00118   atk_object_initialize(accessible, object);
00119 
00120   return accessible;
00121 }
00122 
00123 /* AtkObject.h */
00124 static void
00125 nux_view_accessible_initialize(AtkObject* accessible,
00126                                gpointer data)
00127 {
00128   nux::Object* nux_object = NULL;
00129   nux::View* view = NULL;
00130 
00131   ATK_OBJECT_CLASS(nux_view_accessible_parent_class)->initialize(accessible, data);
00132 
00133   accessible->role = ATK_ROLE_UNKNOWN;
00134 
00135   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible));
00136   view = dynamic_cast<nux::View*>(nux_object);
00137 
00138   view->LayoutAdded.connect(sigc::bind(sigc::ptr_fun(on_layout_changed_cb),
00139                                        accessible, TRUE));
00140   view->LayoutRemoved.connect(sigc::bind(sigc::ptr_fun(on_layout_changed_cb),
00141                                          accessible, FALSE));
00142 
00143   /* Some extra focus things as Focusable is not used on Launcher and
00144      some BaseWindow */
00145   view->begin_key_focus.connect(sigc::bind(sigc::ptr_fun(on_change_keyboard_receiver_cb),
00146                                            accessible, TRUE));
00147   view->end_key_focus.connect(sigc::bind(sigc::ptr_fun(on_change_keyboard_receiver_cb),
00148                                          accessible, FALSE));
00149 }
00150 
00151 static AtkStateSet*
00152 nux_view_accessible_ref_state_set(AtkObject* obj)
00153 {
00154   AtkStateSet* state_set = NULL;
00155   nux::Object* nux_object = NULL;
00156   NuxViewAccessible* self = NULL;
00157 
00158   g_return_val_if_fail(NUX_IS_VIEW_ACCESSIBLE(obj), NULL);
00159   self = NUX_VIEW_ACCESSIBLE(obj);
00160 
00161   state_set = ATK_OBJECT_CLASS(nux_view_accessible_parent_class)->ref_state_set(obj);
00162 
00163   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj));
00164 
00165   if (nux_object == NULL) /* defunct */
00166     return state_set;
00167 
00168   /* HasKeyboardFocus is not a reliable here:
00169      see bug https://bugs.launchpad.net/nux/+bug/745049 */
00170   if (self->priv->key_focused)
00171     atk_state_set_add_state(state_set, ATK_STATE_FOCUSED);
00172 
00173   return state_set;
00174 }
00175 
00176 static gint
00177 nux_view_accessible_get_n_children(AtkObject* obj)
00178 {
00179   nux::Object* nux_object = NULL;
00180   nux::View* view = NULL;
00181   nux::Layout* layout = NULL;
00182 
00183   g_return_val_if_fail(NUX_IS_VIEW_ACCESSIBLE(obj), 0);
00184 
00185   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj));
00186   if (nux_object == NULL) /* state is defunct */
00187     return 0;
00188 
00189   view = dynamic_cast<nux::View*>(nux_object);
00190 
00191   layout = view->GetLayout();
00192 
00193   if (layout == NULL)
00194     return 0;
00195   else
00196     return 1;
00197 }
00198 
00199 static AtkObject*
00200 nux_view_accessible_ref_child(AtkObject* obj,
00201                               gint i)
00202 {
00203   nux::Object* nux_object = NULL;
00204   nux::View* view = NULL;
00205   nux::Layout* layout = NULL;
00206   AtkObject* layout_accessible = NULL;
00207   gint num = 0;
00208 
00209   g_return_val_if_fail(NUX_IS_VIEW_ACCESSIBLE(obj), 0);
00210 
00211   num = atk_object_get_n_accessible_children(obj);
00212   g_return_val_if_fail((i < num) && (i >= 0), NULL);
00213 
00214   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj));
00215   if (nux_object == NULL) /* state is defunct */
00216     return 0;
00217 
00218   view = dynamic_cast<nux::View*>(nux_object);
00219 
00220   layout = view->GetLayout();
00221 
00222   layout_accessible = unity_a11y_get_accessible(layout);
00223 
00224   if (layout_accessible != NULL)
00225     g_object_ref(layout_accessible);
00226 
00227   return layout_accessible;
00228 }
00229 
00230 static void
00231 on_layout_changed_cb(nux::View* view,
00232                      nux::Layout* layout,
00233                      AtkObject* accessible,
00234                      gboolean is_add)
00235 {
00236   const gchar* signal_name = NULL;
00237   AtkObject* atk_child = NULL;
00238 
00239   g_return_if_fail(NUX_IS_VIEW_ACCESSIBLE(accessible));
00240 
00241   atk_child = unity_a11y_get_accessible(layout);
00242 
00243   if (is_add)
00244     signal_name = "children-changed::add";
00245   else
00246     signal_name = "children-changed::remove";
00247 
00248   /* index is always 0 as there is always just one layout */
00249   g_signal_emit_by_name(accessible, signal_name, 0, atk_child, NULL);
00250 }
00251 
00252 static void
00253 on_change_keyboard_receiver_cb(AtkObject* accessible,
00254                                gboolean focus_in)
00255 {
00256   NuxViewAccessible* self = NULL;
00257 
00258   g_return_if_fail(NUX_IS_VIEW_ACCESSIBLE(accessible));
00259   self = NUX_VIEW_ACCESSIBLE(accessible);
00260 
00261   if (self->priv->key_focused != focus_in)
00262   {
00263     self->priv->key_focused = focus_in;
00264 
00265     /* we always led the focus notification to
00266        _check_pending_notification, in order to allow the proper
00267        window_activate -> focus_change order */
00268     self->priv->pending_notification = TRUE;
00269   }
00270 }
00271 
00272 static gboolean
00273 nux_view_accessible_check_pending_notification(NuxAreaAccessible* area_accessible)
00274 {
00275   NuxViewAccessible* self = NULL;
00276   nux::Object* nux_object = NULL;
00277 
00278   /* We also call parent implementation, as we are not totally
00279      overriding check_pending_notification, just adding extra
00280      functionality*/
00281   NUX_AREA_ACCESSIBLE_CLASS(nux_view_accessible_parent_class)->check_pending_notification(area_accessible);
00282 
00283   g_return_val_if_fail(NUX_IS_VIEW_ACCESSIBLE(area_accessible), FALSE);
00284   self = NUX_VIEW_ACCESSIBLE(area_accessible);
00285 
00286   if (self->priv->pending_notification == FALSE)
00287     return FALSE;
00288 
00289   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self));
00290   if (nux_object == NULL) /* defunct */
00291     return FALSE;
00292 
00293   g_signal_emit_by_name(self, "focus_event", self->priv->key_focused);
00294   atk_focus_tracker_notify(ATK_OBJECT(self));
00295   self->priv->pending_notification = FALSE;
00296 
00297   return TRUE;
00298 }