Back to index

unity  6.0.0
unity-launcher-icon-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 
00044 #include "unity-launcher-icon-accessible.h"
00045 #include "unity-launcher-accessible.h"
00046 #include "Launcher.h"
00047 #include "LauncherIcon.h"
00048 
00049 #include "unitya11y.h"
00050 
00051 using namespace unity::launcher;
00052 
00053 /* GObject */
00054 static void unity_launcher_icon_accessible_class_init(UnityLauncherIconAccessibleClass* klass);
00055 static void unity_launcher_icon_accessible_init(UnityLauncherIconAccessible* launcher_icon_accessible);
00056 static void unity_launcher_icon_accessible_dispose(GObject* object);
00057 
00058 
00059 /* AtkObject.h */
00060 static void          unity_launcher_icon_accessible_initialize(AtkObject* accessible,
00061                                                                gpointer   data);
00062 static AtkStateSet*  unity_launcher_icon_accessible_ref_state_set(AtkObject* obj);
00063 static const gchar* unity_launcher_icon_accessible_get_name(AtkObject* obj);
00064 // static AtkObject*    unity_launcher_icon_accessible_get_parent(AtkObject* obj);
00065 static gint          unity_launcher_icon_accessible_get_index_in_parent(AtkObject* obj);
00066 
00067 /* AtkComponent.h */
00068 static void     atk_component_interface_init(AtkComponentIface* iface);
00069 static guint    unity_launcher_icon_accessible_add_focus_handler(AtkComponent* component,
00070                                                                  AtkFocusHandler handler);
00071 static void     unity_launcher_icon_accessible_remove_focus_handler(AtkComponent* component,
00072                                                                     guint handler_id);
00073 static void     unity_launcher_icon_accessible_focus_handler(AtkObject* accessible,
00074                                                              gboolean focus_in);
00075 
00076 /* AtkAction */
00077 static void         atk_action_interface_init(AtkActionIface *iface);
00078 static gboolean     unity_launcher_icon_accessible_do_action(AtkAction *action,
00079                                                               gint i);
00080 static gint         unity_launcher_icon_accessible_get_n_actions(AtkAction *action);
00081 static const gchar* unity_launcher_icon_accessible_get_name(AtkAction *action,
00082                                                             gint i);
00083 
00084 /* private/utility methods*/
00085 static void check_selected(UnityLauncherIconAccessible* self);
00086 static void on_parent_selection_change_cb(AtkSelection* selection,
00087                                           gpointer data);
00088 static void on_parent_focus_event_cb(AtkObject* object,
00089                                      gboolean in,
00090                                      gpointer data);
00091 
00092 G_DEFINE_TYPE_WITH_CODE(UnityLauncherIconAccessible,
00093                         unity_launcher_icon_accessible,
00094                         NUX_TYPE_OBJECT_ACCESSIBLE,
00095                         G_IMPLEMENT_INTERFACE(ATK_TYPE_COMPONENT,
00096                                               atk_component_interface_init)
00097                         G_IMPLEMENT_INTERFACE(ATK_TYPE_ACTION,
00098                                               atk_action_interface_init))
00099 
00100 #define UNITY_LAUNCHER_ICON_ACCESSIBLE_GET_PRIVATE(obj) \
00101   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_LAUNCHER_ICON_ACCESSIBLE, \
00102                                 UnityLauncherIconAccessiblePrivate))
00103 
00104 struct _UnityLauncherIconAccessiblePrivate
00105 {
00106   /* Cached values (used to avoid extra notifications) */
00107   gboolean selected;
00108   gboolean parent_focused;
00109   gboolean index_in_parent;
00110 
00111   guint on_parent_change_id;
00112   guint on_parent_selection_change_id;
00113   guint on_parent_focus_event_id;
00114 };
00115 
00116 static void
00117 unity_launcher_icon_accessible_class_init(UnityLauncherIconAccessibleClass* klass)
00118 {
00119   GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
00120   AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass);
00121 
00122   gobject_class->dispose = unity_launcher_icon_accessible_dispose;
00123 
00124   /* AtkObject */
00125   atk_class->initialize = unity_launcher_icon_accessible_initialize;
00126   atk_class->get_name = unity_launcher_icon_accessible_get_name;
00127   atk_class->ref_state_set = unity_launcher_icon_accessible_ref_state_set;
00128   // atk_class->get_parent = unity_launcher_icon_accessible_get_parent;
00129   atk_class->get_index_in_parent = unity_launcher_icon_accessible_get_index_in_parent;
00130 
00131   g_type_class_add_private(gobject_class, sizeof(UnityLauncherIconAccessiblePrivate));
00132 }
00133 
00134 static void
00135 unity_launcher_icon_accessible_init(UnityLauncherIconAccessible* launcher_icon_accessible)
00136 {
00137   UnityLauncherIconAccessiblePrivate* priv =
00138     UNITY_LAUNCHER_ICON_ACCESSIBLE_GET_PRIVATE(launcher_icon_accessible);
00139 
00140   launcher_icon_accessible->priv = priv;
00141 }
00142 
00143 static void
00144 unity_launcher_icon_accessible_dispose(GObject* object)
00145 {
00146   UnityLauncherIconAccessible* self = UNITY_LAUNCHER_ICON_ACCESSIBLE(object);
00147   AtkObject* parent = NULL;
00148 
00149   parent = atk_object_get_parent(ATK_OBJECT(object));
00150 
00151   if (parent != NULL)
00152   {
00153     if (self->priv->on_parent_selection_change_id != 0)
00154       g_signal_handler_disconnect(parent, self->priv->on_parent_selection_change_id);
00155 
00156     if (self->priv->on_parent_focus_event_id != 0)
00157       g_signal_handler_disconnect(parent, self->priv->on_parent_focus_event_id);
00158   }
00159 
00160   if (self->priv->on_parent_change_id != 0)
00161     g_signal_handler_disconnect(object, self->priv->on_parent_change_id);
00162 
00163   G_OBJECT_CLASS(unity_launcher_icon_accessible_parent_class)->dispose(object);
00164 }
00165 
00166 
00167 AtkObject*
00168 unity_launcher_icon_accessible_new(nux::Object* object)
00169 {
00170   AtkObject* accessible = NULL;
00171 
00172   g_return_val_if_fail(dynamic_cast<LauncherIcon*>(object), NULL);
00173 
00174   accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_LAUNCHER_ICON_ACCESSIBLE, NULL));
00175 
00176   atk_object_initialize(accessible, object);
00177 
00178   return accessible;
00179 }
00180 
00181 /* AtkObject.h */
00182 static void
00183 on_parent_change_cb(gchar* property,
00184                     GValue* value,
00185                     gpointer data)
00186 {
00187   AtkObject* parent = NULL;
00188   UnityLauncherIconAccessible* self = NULL;
00189   AtkStateSet* state_set = NULL;
00190 
00191   g_return_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(data));
00192 
00193   self = UNITY_LAUNCHER_ICON_ACCESSIBLE(data);
00194   parent = atk_object_get_parent(ATK_OBJECT(data));
00195 
00196   if (parent == NULL)
00197     return;
00198 
00199   self->priv->on_parent_selection_change_id =
00200     g_signal_connect(parent, "selection-changed",
00201                      G_CALLBACK(on_parent_selection_change_cb), self);
00202 
00203   self->priv->on_parent_focus_event_id =
00204     g_signal_connect(parent, "focus-event",
00205                      G_CALLBACK(on_parent_focus_event_cb), self);
00206 
00207   state_set = atk_object_ref_state_set(parent);
00208   if (atk_state_set_contains_state(state_set, ATK_STATE_FOCUSED))
00209   {
00210     self->priv->parent_focused = TRUE;
00211   }
00212   g_object_unref(state_set);
00213 }
00214 
00215 static void
00216 unity_launcher_icon_accessible_initialize(AtkObject* accessible,
00217                                           gpointer data)
00218 {
00219   UnityLauncherIconAccessible* self = NULL;
00220 
00221   ATK_OBJECT_CLASS(unity_launcher_icon_accessible_parent_class)->initialize(accessible, data);
00222   self = UNITY_LAUNCHER_ICON_ACCESSIBLE(accessible);
00223 
00224   accessible->role = ATK_ROLE_PUSH_BUTTON;
00225 
00226   atk_component_add_focus_handler(ATK_COMPONENT(accessible),
00227                                   unity_launcher_icon_accessible_focus_handler);
00228 
00229   /* we could do that by redefining ->set_parent */
00230   self->priv->on_parent_change_id =
00231     g_signal_connect(accessible, "notify::accessible-parent",
00232                      G_CALLBACK(on_parent_change_cb), self);
00233 }
00234 
00235 
00236 static const gchar*
00237 unity_launcher_icon_accessible_get_name(AtkObject* obj)
00238 {
00239   const gchar* name;
00240 
00241   g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(obj), NULL);
00242 
00243   name = ATK_OBJECT_CLASS(unity_launcher_icon_accessible_parent_class)->get_name(obj);
00244   if (name == NULL)
00245   {
00246     LauncherIcon* icon = NULL;
00247 
00248     icon = dynamic_cast<LauncherIcon*>(nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj)));
00249 
00250     if (icon == NULL) /* State is defunct */
00251       name = NULL;
00252     else
00253       name = icon->tooltip_text().c_str();
00254   }
00255 
00256   return name;
00257 }
00258 
00259 static AtkStateSet*
00260 unity_launcher_icon_accessible_ref_state_set(AtkObject* obj)
00261 {
00262   AtkStateSet* state_set = NULL;
00263   UnityLauncherIconAccessible* self = NULL;
00264   nux::Object* nux_object = NULL;
00265   LauncherIcon* icon = NULL;
00266 
00267   g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(obj), NULL);
00268   self = UNITY_LAUNCHER_ICON_ACCESSIBLE(obj);
00269 
00270   state_set = ATK_OBJECT_CLASS(unity_launcher_icon_accessible_parent_class)->ref_state_set(obj);
00271 
00272   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(obj));
00273 
00274   if (nux_object == NULL) /* defunct */
00275     return state_set;
00276 
00277   /* by default */
00278   atk_state_set_add_state(state_set, ATK_STATE_FOCUSABLE);
00279   atk_state_set_add_state(state_set, ATK_STATE_ENABLED);
00280   atk_state_set_add_state(state_set, ATK_STATE_SENSITIVE);
00281 
00282   icon = dynamic_cast<LauncherIcon*>(nux_object);
00283 
00284   if (icon->GetQuirk(LauncherIcon::QUIRK_VISIBLE))
00285   {
00286     atk_state_set_add_state(state_set, ATK_STATE_VISIBLE);
00287     atk_state_set_add_state(state_set, ATK_STATE_SHOWING);
00288   }
00289 
00290   if (self->priv->selected)
00291   {
00292     atk_state_set_add_state(state_set, ATK_STATE_FOCUSED);
00293     atk_state_set_add_state(state_set, ATK_STATE_SELECTED);
00294     atk_state_set_add_state(state_set, ATK_STATE_ACTIVE);
00295   }
00296 
00297   return state_set;
00298 }
00299 
00300 /* private methods */
00301 
00302 /*
00303  * Checks if the current item is selected, and notify a selection
00304  * change if the selection has changed
00305  */
00306 static void
00307 check_selected(UnityLauncherIconAccessible* self)
00308 {
00309   AtkObject* parent = NULL;
00310   gboolean found = FALSE;
00311 
00312   parent = atk_object_get_parent(ATK_OBJECT(self));
00313   if  (parent == NULL)
00314     return;
00315 
00316   found = atk_selection_is_child_selected(ATK_SELECTION(parent),
00317                                           self->priv->index_in_parent);
00318 
00319   if ((found) && (self->priv->parent_focused == FALSE))
00320     return;
00321 
00322   if (found != self->priv->selected)
00323   {
00324     gboolean return_val = FALSE;
00325 
00326     self->priv->selected = found;
00327     atk_object_notify_state_change(ATK_OBJECT(self),
00328                                    ATK_STATE_SELECTED,
00329                                    found);
00330     atk_object_notify_state_change(ATK_OBJECT(self),
00331                                    ATK_STATE_ACTIVE,
00332                                    found);
00333 
00334     g_signal_emit_by_name(self, "focus-event", self->priv->selected, &return_val);
00335     atk_focus_tracker_notify(ATK_OBJECT(self));
00336   }
00337 }
00338 
00339 static void
00340 on_parent_selection_change_cb(AtkSelection* selection,
00341                               gpointer data)
00342 {
00343   g_return_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(data));
00344 
00345   check_selected(UNITY_LAUNCHER_ICON_ACCESSIBLE(data));
00346 }
00347 
00348 
00349 static void
00350 on_parent_focus_event_cb(AtkObject* object,
00351                          gboolean in,
00352                          gpointer data)
00353 {
00354   UnityLauncherIconAccessible* self = NULL;
00355 
00356   g_return_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(data));
00357 
00358   self = UNITY_LAUNCHER_ICON_ACCESSIBLE(data);
00359   self->priv->parent_focused = in;
00360 
00361   /* we check the selection stuff again, to report the focus change
00362      now */
00363   check_selected(self);
00364 }
00365 
00366 /* AtkComponent.h */
00367 
00368 static void
00369 atk_component_interface_init(AtkComponentIface* iface)
00370 {
00371   g_return_if_fail(iface != NULL);
00372 
00373   /* focus management */
00374   iface->add_focus_handler    = unity_launcher_icon_accessible_add_focus_handler;
00375   iface->remove_focus_handler = unity_launcher_icon_accessible_remove_focus_handler;
00376 
00377   /* FIXME: still missing the size and position methods. Remember that
00378    * this is not a nux::Area, and probably we would require to poke
00379    * the Launcher to get those positions
00380    */
00381 }
00382 
00383 /*
00384  * comment C&P from cally-actor:
00385  *
00386  * "These methods are basically taken from gail, as I don't see any
00387  * reason to modify it. It makes me wonder why it is really required
00388  * to be implemented in the toolkit"
00389  */
00390 
00391 static guint
00392 unity_launcher_icon_accessible_add_focus_handler(AtkComponent* component,
00393                                                  AtkFocusHandler handler)
00394 {
00395   GSignalMatchType match_type;
00396   gulong ret;
00397   guint signal_id;
00398 
00399   g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(component), 0);
00400 
00401   match_type = (GSignalMatchType)(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC);
00402   signal_id = g_signal_lookup("focus-event", ATK_TYPE_OBJECT);
00403 
00404   ret = g_signal_handler_find(component, match_type, signal_id, 0, NULL,
00405                               (gpointer) handler, NULL);
00406   if (!ret)
00407   {
00408     return g_signal_connect_closure_by_id(component,
00409                                           signal_id, 0,
00410                                           g_cclosure_new(G_CALLBACK(handler), NULL,
00411                                                          (GClosureNotify) NULL),
00412                                           FALSE);
00413   }
00414   else
00415     return 0;
00416 }
00417 
00418 static void
00419 unity_launcher_icon_accessible_remove_focus_handler(AtkComponent* component,
00420                                                     guint handler_id)
00421 {
00422   g_return_if_fail(NUX_IS_VIEW_ACCESSIBLE(component));
00423 
00424   g_signal_handler_disconnect(component, handler_id);
00425 }
00426 
00427 static void
00428 unity_launcher_icon_accessible_focus_handler(AtkObject* accessible,
00429                                              gboolean focus_in)
00430 {
00431   g_return_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(accessible));
00432 
00433   atk_object_notify_state_change(accessible, ATK_STATE_FOCUSED, focus_in);
00434 }
00435 
00436 static gint
00437 unity_launcher_icon_accessible_get_index_in_parent(AtkObject* obj)
00438 {
00439   g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(obj), -1);
00440 
00441   return UNITY_LAUNCHER_ICON_ACCESSIBLE(obj)->priv->index_in_parent;
00442 }
00443 
00444 /* AtkAction */
00445 static void
00446 atk_action_interface_init(AtkActionIface *iface)
00447 {
00448   iface->do_action = unity_launcher_icon_accessible_do_action;
00449   iface->get_n_actions = unity_launcher_icon_accessible_get_n_actions;
00450   iface->get_name = unity_launcher_icon_accessible_get_name;
00451 }
00452 
00453 static gboolean
00454 unity_launcher_icon_accessible_do_action(AtkAction *action,
00455                                          gint i)
00456 {
00457   LauncherIcon* icon = NULL;
00458   nux::Object* nux_object = NULL;
00459 
00460   g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(action), FALSE);
00461 
00462   nux_object = nux_object_accessible_get_object(NUX_OBJECT_ACCESSIBLE(action));
00463   if (nux_object == NULL)
00464     return FALSE;
00465 
00466   icon = dynamic_cast<LauncherIcon*>(nux_object);
00467 
00468   icon->Activate(ActionArg(ActionArg::LAUNCHER, 0));
00469 
00470   return TRUE;
00471 }
00472 
00473 static gint
00474 unity_launcher_icon_accessible_get_n_actions(AtkAction *action)
00475 {
00476   g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(action), 0);
00477 
00478   return 1;
00479 }
00480 
00481 static const gchar*
00482 unity_launcher_icon_accessible_get_name(AtkAction *action,
00483                                         gint i)
00484 {
00485   g_return_val_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(action), NULL);
00486   g_return_val_if_fail(i == 0, NULL);
00487 
00488   return "activate";
00489 }
00490 
00491 /* Public */
00492 
00493 void
00494 unity_launcher_icon_accessible_set_index(UnityLauncherIconAccessible* self,
00495                                          gint index)
00496 {
00497   g_return_if_fail(UNITY_IS_LAUNCHER_ICON_ACCESSIBLE(self));
00498 
00499   self->priv->index_in_parent = index;
00500 }