Back to index

unity  6.0.0
unity-switcher-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 
00031 #include <glib/gi18n.h>
00032 
00033 #include "unity-switcher-accessible.h"
00034 #include "unity-launcher-icon-accessible.h"
00035 
00036 #include "unitya11y.h"
00037 #include "SwitcherView.h"
00038 #include "SwitcherModel.h"
00039 
00040 using namespace unity::switcher;
00041 using namespace unity::launcher;
00042 
00043 /* GObject */
00044 static void unity_switcher_accessible_class_init(UnitySwitcherAccessibleClass* klass);
00045 static void unity_switcher_accessible_init(UnitySwitcherAccessible* self);
00046 static void unity_switcher_accessible_finalize(GObject* object);
00047 
00048 /* AtkObject.h */
00049 static void       unity_switcher_accessible_initialize(AtkObject* accessible,
00050                                                        gpointer   data);
00051 static gint       unity_switcher_accessible_get_n_children(AtkObject* obj);
00052 static AtkObject* unity_switcher_accessible_ref_child(AtkObject* obj,
00053                                                       gint i);
00054 static AtkStateSet* unity_switcher_accessible_ref_state_set(AtkObject* obj);
00055 
00056 /* AtkSelection */
00057 static void       atk_selection_interface_init(AtkSelectionIface* iface);
00058 static AtkObject* unity_switcher_accessible_ref_selection(AtkSelection* selection,
00059                                                           gint i);
00060 static gint       unity_switcher_accessible_get_selection_count(AtkSelection* selection);
00061 static gboolean   unity_switcher_accessible_is_child_selected(AtkSelection* selection,
00062                                                               gint i);
00063 /* NuxAreaAccessible */
00064 static gboolean   unity_switcher_accessible_check_pending_notification(NuxAreaAccessible* self);
00065 
00066 /* private */
00067 static void       on_selection_changed_cb(AbstractLauncherIcon::Ptr icon,
00068                                           UnitySwitcherAccessible* switcher_accessible);
00069 static void       create_children(UnitySwitcherAccessible* self);
00070 
00071 
00072 G_DEFINE_TYPE_WITH_CODE(UnitySwitcherAccessible, unity_switcher_accessible,  NUX_TYPE_VIEW_ACCESSIBLE,
00073                         G_IMPLEMENT_INTERFACE(ATK_TYPE_SELECTION, atk_selection_interface_init))
00074 
00075 #define UNITY_SWITCHER_ACCESSIBLE_GET_PRIVATE(obj)                      \
00076   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_SWITCHER_ACCESSIBLE,  \
00077                                 UnitySwitcherAccessiblePrivate))
00078 
00079 struct _UnitySwitcherAccessiblePrivate
00080 {
00081   /* We maintain the children. Although the LauncherIcon are shared
00082    * between the Switcher and Launcher, in order to keep a hierarchy
00083    * coherence, we create a different accessible object  */
00084   GSList* children;
00085 
00086   sigc::connection on_selection_changed_connection;
00087 };
00088 
00089 
00090 static void
00091 unity_switcher_accessible_class_init(UnitySwitcherAccessibleClass* klass)
00092 {
00093   GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
00094   AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass);
00095   NuxAreaAccessibleClass* area_class = NUX_AREA_ACCESSIBLE_CLASS(klass);
00096 
00097   gobject_class->finalize = unity_switcher_accessible_finalize;
00098 
00099   /* AtkObject */
00100   atk_class->get_n_children = unity_switcher_accessible_get_n_children;
00101   atk_class->ref_child = unity_switcher_accessible_ref_child;
00102   atk_class->initialize = unity_switcher_accessible_initialize;
00103   atk_class->ref_state_set = unity_switcher_accessible_ref_state_set;
00104 
00105   /* NuxAreaAccessible */
00106   area_class->check_pending_notification = unity_switcher_accessible_check_pending_notification;
00107 
00108   g_type_class_add_private(gobject_class, sizeof(UnitySwitcherAccessiblePrivate));
00109 }
00110 
00111 static void
00112 unity_switcher_accessible_init(UnitySwitcherAccessible* self)
00113 {
00114   UnitySwitcherAccessiblePrivate* priv =
00115     UNITY_SWITCHER_ACCESSIBLE_GET_PRIVATE(self);
00116 
00117   self->priv = priv;
00118   self->priv->children = NULL;
00119 }
00120 
00121 static void
00122 unity_switcher_accessible_finalize(GObject* object)
00123 {
00124   UnitySwitcherAccessible* self = UNITY_SWITCHER_ACCESSIBLE(object);
00125 
00126   self->priv->on_selection_changed_connection.disconnect();
00127 
00128   if (self->priv->children)
00129   {
00130     g_slist_free_full(self->priv->children, g_object_unref);
00131     self->priv->children = NULL;
00132   }
00133 
00134   G_OBJECT_CLASS(unity_switcher_accessible_parent_class)->finalize(object);
00135 }
00136 
00137 AtkObject*
00138 unity_switcher_accessible_new(nux::Object* object)
00139 {
00140   AtkObject* accessible = NULL;
00141 
00142   g_return_val_if_fail(dynamic_cast<SwitcherView*>(object), NULL);
00143 
00144   accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_SWITCHER_ACCESSIBLE, NULL));
00145 
00146   atk_object_initialize(accessible, object);
00147   atk_object_set_name(accessible, _("Switcher"));
00148 
00149   return accessible;
00150 }
00151 
00152 /* AtkObject.h */
00153 static void
00154 unity_switcher_accessible_initialize(AtkObject* accessible,
00155                                      gpointer data)
00156 {
00157   SwitcherView* switcher = NULL;
00158   nux::Object* nux_object = NULL;
00159   UnitySwitcherAccessible* self = NULL;
00160   SwitcherModel::Ptr model;
00161 
00162   ATK_OBJECT_CLASS(unity_switcher_accessible_parent_class)->initialize(accessible, data);
00163 
00164   atk_object_set_role(accessible, ATK_ROLE_TOOL_BAR);
00165 
00166   self = UNITY_SWITCHER_ACCESSIBLE(accessible);
00167   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(accessible));
00168   switcher = dynamic_cast<SwitcherView*>(nux_object);
00169   if (switcher == NULL)
00170     return;
00171 
00172   model = switcher->GetModel();
00173 
00174   if (model)
00175   {
00176     self->priv->on_selection_changed_connection  =
00177       model->selection_changed.connect(sigc::bind(sigc::ptr_fun(on_selection_changed_cb),
00178                                                   self));
00179 
00180     create_children(self);
00181   }
00182 
00183   /* To force being connected to the window::activate signal */
00184   nux_area_accessible_parent_window_active(NUX_AREA_ACCESSIBLE(self));
00185 }
00186 
00187 static gint
00188 unity_switcher_accessible_get_n_children(AtkObject* obj)
00189 {
00190   nux::Object* object = NULL;
00191   UnitySwitcherAccessible* self = NULL;
00192 
00193   g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(obj), 0);
00194   self = UNITY_SWITCHER_ACCESSIBLE(obj);
00195 
00196   object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj));
00197   if (!object) /* state is defunct */
00198     return 0;
00199 
00200   return g_slist_length(self->priv->children);
00201 }
00202 
00203 static AtkObject*
00204 unity_switcher_accessible_ref_child(AtkObject* obj,
00205                                     gint i)
00206 {
00207   gint num = 0;
00208   nux::Object* nux_object = NULL;
00209   AtkObject* child_accessible = NULL;
00210   UnitySwitcherAccessible* self = NULL;
00211 
00212   g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(obj), NULL);
00213   num = atk_object_get_n_accessible_children(obj);
00214   g_return_val_if_fail((i < num) && (i >= 0), NULL);
00215   self = UNITY_SWITCHER_ACCESSIBLE(obj);
00216 
00217   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj));
00218   if (!nux_object) /* state is defunct */
00219     return 0;
00220 
00221   child_accessible = ATK_OBJECT(g_slist_nth_data(self->priv->children, i));
00222 
00223   g_object_ref(child_accessible);
00224 
00225   return child_accessible;
00226 }
00227 
00228 static AtkStateSet*
00229 unity_switcher_accessible_ref_state_set(AtkObject* obj)
00230 {
00231   AtkStateSet* state_set = NULL;
00232   nux::Object* nux_object = NULL;
00233 
00234   g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(obj), NULL);
00235 
00236   state_set =
00237     ATK_OBJECT_CLASS(unity_switcher_accessible_parent_class)->ref_state_set(obj);
00238 
00239   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj));
00240 
00241   if (nux_object == NULL) /* defunct */
00242     return state_set;
00243 
00244   /* The Switcher is always focusable */
00245   atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE);
00246 
00247   /* The Switcher is always focused. Looking SwitcherController code,
00248    * SwitcherView is only created to be presented to the user */
00249   atk_state_set_add_state(state_set, ATK_STATE_FOCUSED);
00250 
00251   return state_set;
00252 }
00253 
00254 /* AtkSelection */
00255 static void
00256 atk_selection_interface_init(AtkSelectionIface* iface)
00257 {
00258   iface->ref_selection = unity_switcher_accessible_ref_selection;
00259   iface->get_selection_count = unity_switcher_accessible_get_selection_count;
00260   iface->is_child_selected = unity_switcher_accessible_is_child_selected;
00261 
00262   /* NOTE: for the moment we don't provide the implementation for the
00263      "interactable" methods, it is, the methods that allow to change
00264      the selected icon. The Switcher doesn't provide that API, and
00265      right now  we are focusing on a normal user input.*/
00266   /* iface->add_selection = unity_switcher_accessible_add_selection; */
00267   /* iface->clear_selection = unity_switcher_accessible_clear_selection; */
00268   /* iface->remove_selection = unity_switcher_accessible_remove_selection; */
00269 
00270   /* This method will never be implemented, as select all the switcher
00271      icons makes no sense */
00272   /* iface->select_all = unity_switcher_accessible_select_all_selection; */
00273 }
00274 
00275 static AtkObject*
00276 unity_switcher_accessible_ref_selection(AtkSelection* selection,
00277                                         gint i)
00278 {
00279   SwitcherView* switcher = NULL;
00280   SwitcherModel::Ptr switcher_model;
00281   nux::Object* nux_object = NULL;
00282   gint selected_index = 0;
00283   AtkObject* accessible_selected = NULL;
00284   UnitySwitcherAccessible* self = NULL;
00285 
00286   g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(selection), 0);
00287   /* there can be only just item selected */
00288   g_return_val_if_fail(i == 0, NULL);
00289   self = UNITY_SWITCHER_ACCESSIBLE(selection);
00290 
00291   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection));
00292   if (!nux_object) /* state is defunct */
00293     return 0;
00294 
00295   switcher = dynamic_cast<SwitcherView*>(nux_object);
00296 
00297   switcher_model = switcher->GetModel();
00298   selected_index = switcher_model->SelectionIndex();
00299 
00300   accessible_selected = ATK_OBJECT(g_slist_nth_data(self->priv->children,
00301                                                     selected_index));
00302 
00303   if (accessible_selected != NULL)
00304     g_object_ref(accessible_selected);
00305 
00306   return accessible_selected;
00307 }
00308 
00309 static gint
00310 unity_switcher_accessible_get_selection_count(AtkSelection* selection)
00311 {
00312   SwitcherView* switcher = NULL;
00313   SwitcherModel::Ptr switcher_model;
00314   AbstractLauncherIcon::Ptr selected_icon;
00315   nux::Object* nux_object = NULL;
00316 
00317   g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(selection), 0);
00318 
00319   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection));
00320   if (!nux_object) /* state is defunct */
00321     return 0;
00322 
00323   switcher = dynamic_cast<SwitcherView*>(nux_object);
00324   switcher_model = switcher->GetModel();
00325 
00326   selected_icon = switcher_model->Selection();
00327 
00328   if (!selected_icon)
00329     return 0;
00330   else
00331     return 1;
00332 }
00333 
00334 static gboolean
00335 unity_switcher_accessible_is_child_selected(AtkSelection* selection,
00336                                             gint i)
00337 {
00338   SwitcherView* switcher = NULL;
00339   SwitcherModel::Ptr switcher_model;
00340   SwitcherModel::iterator it;
00341   nux::Object* nux_object = NULL;
00342   gint selected_index = 0;
00343 
00344   g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(selection), FALSE);
00345 
00346   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(selection));
00347   if (!nux_object) /* state is defunct */
00348     return 0;
00349 
00350   switcher = dynamic_cast<SwitcherView*>(nux_object);
00351   switcher_model = switcher->GetModel();
00352   selected_index = switcher_model->SelectionIndex();
00353 
00354   if (selected_index == i)
00355     return TRUE;
00356   else
00357     return FALSE;
00358 }
00359 
00360 /* NuxAreaAccessible */
00361 static gboolean
00362 unity_switcher_accessible_check_pending_notification(NuxAreaAccessible* self)
00363 {
00364   g_return_val_if_fail(UNITY_IS_SWITCHER_ACCESSIBLE(self), FALSE);
00365 
00366   /* Overriding the method: the switcher doesn't get the key focus of
00367    * focus (Focusable) */
00368   /* From SwitcherController: it shows that the switcher only exists
00369    * to be shown to the user, so if the parent window gets actived, we
00370    * assume that the switcher will be automatically focused
00371    */
00372   atk_object_notify_state_change(ATK_OBJECT(self), ATK_STATE_FOCUSED, TRUE);
00373   g_signal_emit_by_name(self, "focus-event", TRUE, NULL);
00374 
00375   return TRUE;
00376 }
00377 
00378 /* private */
00379 static void
00380 on_selection_changed_cb(AbstractLauncherIcon::Ptr icon,
00381                         UnitySwitcherAccessible* switcher_accessible)
00382 {
00383   g_signal_emit_by_name(ATK_OBJECT(switcher_accessible), "selection-changed");
00384 }
00385 
00386 static void
00387 create_children(UnitySwitcherAccessible* self)
00388 {
00389   gint index = 0;
00390   nux::Object* nux_object = NULL;
00391   SwitcherView* switcher = NULL;
00392   SwitcherModel::Ptr switcher_model;
00393   SwitcherModel::iterator it;
00394   AbstractLauncherIcon::Ptr child;
00395   AtkObject* child_accessible = NULL;
00396 
00397   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(self));
00398   if (!nux_object) /* state is defunct */
00399     return;
00400 
00401   switcher = dynamic_cast<SwitcherView*>(nux_object);
00402   switcher_model = switcher->GetModel();
00403 
00404   if (switcher_model == NULL)
00405     return;
00406 
00407   for (it = switcher_model->begin(); it != switcher_model->end(); it++)
00408   {
00409     child = *it;
00410     child_accessible = unity_launcher_icon_accessible_new(child.GetPointer());
00411     atk_object_set_parent(child_accessible, ATK_OBJECT(self));
00412     self->priv->children = g_slist_append(self->priv->children,
00413                                           child_accessible);
00414     unity_launcher_icon_accessible_set_index(UNITY_LAUNCHER_ICON_ACCESSIBLE(child_accessible),
00415                                              index++);
00416   }
00417 }