Back to index

unity  6.0.0
unity-root-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 
00029 #include "unity-root-accessible.h"
00030 #include "nux-base-window-accessible.h"
00031 #include "unitya11y.h"
00032 
00033 #include "UBusWrapper.h"
00034 #include "UBusMessages.h"
00035 
00036 /* GObject */
00037 static void unity_root_accessible_class_init(UnityRootAccessibleClass* klass);
00038 static void unity_root_accessible_init(UnityRootAccessible* root);
00039 static void unity_root_accessible_finalize(GObject* object);
00040 
00041 /* AtkObject.h */
00042 static void       unity_root_accessible_initialize(AtkObject* accessible,
00043                                                    gpointer   data);
00044 static gint       unity_root_accessible_get_n_children(AtkObject* obj);
00045 static AtkObject* unity_root_accessible_ref_child(AtkObject* obj,
00046                                                   gint i);
00047 static AtkObject* unity_root_accessible_get_parent(AtkObject* obj);
00048 /* private */
00049 static void       explore_children(AtkObject* obj);
00050 static void       check_active_window(UnityRootAccessible* self);
00051 static void       register_interesting_messages(UnityRootAccessible* self);
00052 static void       add_window(UnityRootAccessible* self,
00053                              nux::BaseWindow* window);
00054 static void       remove_window(UnityRootAccessible* self,
00055                                 nux::BaseWindow* window);
00056 
00057 #define UNITY_ROOT_ACCESSIBLE_GET_PRIVATE(obj)                          \
00058   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), UNITY_TYPE_ROOT_ACCESSIBLE, UnityRootAccessiblePrivate))
00059 
00060 G_DEFINE_TYPE(UnityRootAccessible, unity_root_accessible,  ATK_TYPE_OBJECT)
00061 
00062 struct _UnityRootAccessiblePrivate
00063 {
00064   /* we save on window_list the accessible object for the windows
00065      registered */
00066   GSList* window_list;
00067   nux::BaseWindow* active_window;
00068   nux::BaseWindow* launcher_window;
00069 };
00070 
00071 static void
00072 unity_root_accessible_class_init(UnityRootAccessibleClass* klass)
00073 {
00074   GObjectClass* gobject_class = G_OBJECT_CLASS(klass);
00075   AtkObjectClass* atk_class = ATK_OBJECT_CLASS(klass);
00076 
00077   gobject_class->finalize = unity_root_accessible_finalize;
00078 
00079   /* AtkObject */
00080   atk_class->get_n_children = unity_root_accessible_get_n_children;
00081   atk_class->ref_child = unity_root_accessible_ref_child;
00082   atk_class->get_parent = unity_root_accessible_get_parent;
00083   atk_class->initialize = unity_root_accessible_initialize;
00084 
00085   g_type_class_add_private(gobject_class, sizeof(UnityRootAccessiblePrivate));
00086 }
00087 
00088 static void
00089 unity_root_accessible_init(UnityRootAccessible*      root)
00090 {
00091   root->priv = UNITY_ROOT_ACCESSIBLE_GET_PRIVATE(root);
00092 
00093   root->priv->window_list = NULL;
00094   root->priv->active_window = NULL;
00095   root->priv->launcher_window = NULL;
00096 }
00097 
00098 AtkObject*
00099 unity_root_accessible_new(void)
00100 {
00101   AtkObject* accessible = NULL;
00102 
00103   accessible = ATK_OBJECT(g_object_new(UNITY_TYPE_ROOT_ACCESSIBLE, NULL));
00104 
00105   atk_object_initialize(accessible, NULL);
00106 
00107   return accessible;
00108 }
00109 
00110 static void
00111 unity_root_accessible_finalize(GObject* object)
00112 {
00113   UnityRootAccessible* root = UNITY_ROOT_ACCESSIBLE(object);
00114 
00115   g_return_if_fail(UNITY_IS_ROOT_ACCESSIBLE(object));
00116 
00117   if (root->priv->window_list)
00118   {
00119     g_slist_free_full(root->priv->window_list, g_object_unref);
00120     root->priv->window_list = NULL;
00121   }
00122 
00123   G_OBJECT_CLASS(unity_root_accessible_parent_class)->finalize(object);
00124 }
00125 
00126 /* AtkObject.h */
00127 static void
00128 unity_root_accessible_initialize(AtkObject* accessible,
00129                                  gpointer data)
00130 {
00131   accessible->role = ATK_ROLE_APPLICATION;
00132 
00133   // FIXME: compiz doesn't set the program name using g_set_prgname,
00134   // and AFAIK, there isn't a way to get it. Requires further investigation.
00135   // accessible->name = g_get_prgname();
00136   atk_object_set_name(accessible, "unity");
00137   atk_object_set_parent(accessible, NULL);
00138 
00139   register_interesting_messages(UNITY_ROOT_ACCESSIBLE(accessible));
00140 
00141   ATK_OBJECT_CLASS(unity_root_accessible_parent_class)->initialize(accessible, data);
00142 }
00143 
00144 static gint
00145 unity_root_accessible_get_n_children(AtkObject* obj)
00146 {
00147   UnityRootAccessible* root = UNITY_ROOT_ACCESSIBLE(obj);
00148 
00149   return g_slist_length(root->priv->window_list);
00150 }
00151 
00152 static AtkObject*
00153 unity_root_accessible_ref_child(AtkObject* obj,
00154                                 gint i)
00155 {
00156   UnityRootAccessible* root = NULL;
00157   gint num = 0;
00158   AtkObject* item = NULL;
00159 
00160   root = UNITY_ROOT_ACCESSIBLE(obj);
00161   num = atk_object_get_n_accessible_children(obj);
00162   g_return_val_if_fail((i < num) && (i >= 0), NULL);
00163 
00164   item = ATK_OBJECT(g_slist_nth_data(root->priv->window_list, i));
00165 
00166   if (!item)
00167     return NULL;
00168 
00169   g_object_ref(item);
00170 
00171   return item;
00172 }
00173 
00174 static AtkObject*
00175 unity_root_accessible_get_parent(AtkObject* obj)
00176 {
00177   return NULL;
00178 }
00179 
00180 
00181 /* private */
00182 /*
00183  * FIXME: temporal solution
00184  *
00185  * Normally not all the accessible objects on the hierarchy are
00186  * available from the beginning, and they are being created by demand
00187  * due the request on the AT (ie: orca) side
00188  *
00189  * It usually follows a top-down approach. Top objects emits a signal
00190  * of interest, so AT apps get interest on it, and request their
00191  * children. One example is the signal "window::activate". AT receives
00192  * a signal meaning that a top level object is activated, so request
00193  * their children (and gran-children).
00194  *
00195  * Due technical reasons, right now it is hard to find a suitable way
00196  * to emit the signal "activate" on the BaseWindow. That means that
00197  * objects on the bottom of the hierarchy are not created, so Orca
00198  * doesn't react to changes on sections like the Launcher.
00199  *
00200  * So in order to prevent that, we make a manual exploration of the
00201  * hierarchy in order to ensure that those objects are there.
00202  *
00203  * NOTE: this manual exploration is not required with at-spi2, just
00204  * with at-spi.
00205  *
00206  */
00207 static void
00208 explore_children(AtkObject* obj)
00209 {
00210   gint num = 0;
00211   gint i = 0;
00212   AtkObject* atk_child = NULL;
00213 
00214   g_return_if_fail(ATK_IS_OBJECT(obj));
00215 
00216   num = atk_object_get_n_accessible_children(obj);
00217 
00218   for (i = 0; i < num; i++)
00219   {
00220     atk_child = atk_object_ref_accessible_child(obj, i);
00221     explore_children(atk_child);
00222     g_object_unref(atk_child);
00223   }
00224 }
00225 
00226 /*
00227  * Call all the children (NuxBaseWindowAccessible) to check if they
00228  * are in the proper active or deactive status.
00229  */
00230 static void
00231 check_active_window(UnityRootAccessible* self)
00232 {
00233   GSList* iter = NULL;
00234   NuxBaseWindowAccessible* window = NULL;
00235 
00236   for (iter = self->priv->window_list; iter != NULL; iter = g_slist_next(iter))
00237   {
00238     window = NUX_BASE_WINDOW_ACCESSIBLE(iter->data);
00239     nux_base_window_accessible_check_active(window, self->priv->active_window);
00240   }
00241 }
00242 
00243 /*
00244  * It adds a window to the internal window_list managed by the Root object
00245  *
00246  * Checks if the object is already present. Adds a reference to the
00247  * accessible object of the window.
00248  */
00249 static void
00250 add_window(UnityRootAccessible* self,
00251            nux::BaseWindow* window)
00252 {
00253   AtkObject* window_accessible = NULL;
00254   gint index = 0;
00255 
00256   g_return_if_fail(UNITY_IS_ROOT_ACCESSIBLE(self));
00257 
00258   window_accessible =
00259     unity_a11y_get_accessible(window);
00260 
00261   /* FIXME: temporal */
00262   atk_object_set_name (window_accessible, window->GetWindowName().GetTCharPtr());
00263 
00264   if (g_slist_find(self->priv->window_list, window_accessible))
00265     return;
00266 
00267   self->priv->window_list =
00268     g_slist_append(self->priv->window_list, window_accessible);
00269   g_object_ref(window_accessible);
00270 
00271   index = g_slist_index(self->priv->window_list, window_accessible);
00272 
00273   explore_children(window_accessible);
00274 
00275   g_signal_emit_by_name(self, "children-changed::add",
00276                         index, window_accessible, NULL);
00277 }
00278 
00279 
00280 /*
00281  * It removes the window to the internal window_list managed by the
00282  * Root object
00283  *
00284  * Checks if the object is already present. Removes a reference to the
00285  * accessible object of the window.
00286  */
00287 static void
00288 remove_window(UnityRootAccessible* self,
00289               nux::BaseWindow* window)
00290 {
00291   AtkObject* window_accessible = NULL;
00292   gint index = 0;
00293 
00294   g_return_if_fail(UNITY_IS_ROOT_ACCESSIBLE(self));
00295 
00296   window_accessible =
00297     unity_a11y_get_accessible(window);
00298 
00299   return;
00300   
00301   if (!g_slist_find(self->priv->window_list, window_accessible))
00302     return;
00303 
00304   index = g_slist_index(self->priv->window_list, window_accessible);
00305 
00306   self->priv->window_list =
00307     g_slist_remove(self->priv->window_list, window_accessible);
00308   g_object_unref(window_accessible);
00309 
00310   g_signal_emit_by_name(self, "children-changed::remove",
00311                         index, window_accessible, NULL);
00312 }
00313 
00314 static void
00315 set_active_window(UnityRootAccessible* self,
00316                   nux::BaseWindow* window)
00317 {
00318   g_return_if_fail(UNITY_IS_ROOT_ACCESSIBLE(self));
00319   g_return_if_fail(window != NULL);
00320 
00321   self->priv->active_window = window;
00322   check_active_window(self);
00323 }
00324 
00325 nux::BaseWindow*
00326 search_for_launcher_window(UnityRootAccessible* self)
00327 {
00328   GSList*iter = NULL;
00329   nux::Object* nux_object = NULL;
00330   nux::BaseWindow* bwindow = NULL;
00331   NuxObjectAccessible* accessible = NULL;
00332   gboolean found = FALSE;
00333 
00334   for (iter = self->priv->window_list; iter != NULL; iter = g_slist_next(iter))
00335   {
00336     accessible = NUX_OBJECT_ACCESSIBLE(iter->data);
00337 
00338     nux_object = nux_object_accessible_get_object(accessible);
00339     bwindow = dynamic_cast<nux::BaseWindow*>(nux_object);
00340 
00341     if ((bwindow!= NULL) && (g_strcmp0(bwindow->GetWindowName().GetTCharPtr(), "LauncherWindow") == 0))
00342     {
00343       found = TRUE;
00344       break;
00345     }
00346   }
00347 
00348   if (found)
00349     return bwindow;
00350   else
00351     return NULL;
00352 }
00353 
00354 static void
00355 ubus_launcher_register_interest_cb(GVariant* variant,
00356                                    UnityRootAccessible* self)
00357 {
00358   //launcher window is the same during all the life of Unity
00359   if (self->priv->launcher_window == NULL)
00360     self->priv->launcher_window = search_for_launcher_window(self);
00361 
00362   //launcher window became the active window
00363   set_active_window(self, self->priv->launcher_window);
00364 }
00365 
00366 
00367 static void
00368 wc_change_visibility_window_cb(nux::BaseWindow* window,
00369                                UnityRootAccessible* self,
00370                                gboolean visible)
00371 {
00372   if (visible)
00373   {
00374     add_window(self, window);
00375     //for the dash and quicklist
00376     set_active_window(self, window);
00377   }
00378   else
00379   {
00380     AtkObject* accessible = NULL;
00381 
00382     accessible = unity_a11y_get_accessible(window);
00383     nux_base_window_accessible_check_active(NUX_BASE_WINDOW_ACCESSIBLE(accessible),
00384                                             NULL);
00385     remove_window(self, window);
00386   }
00387 }
00388 
00389 static void
00390 register_interesting_messages(UnityRootAccessible* self)
00391 {
00392   static unity::UBusManager ubus_manager;
00393 
00394   ubus_manager.RegisterInterest(UBUS_LAUNCHER_START_KEY_NAV,
00395                                 sigc::bind(sigc::ptr_fun(ubus_launcher_register_interest_cb),
00396                                 self));
00397 
00398   ubus_manager.RegisterInterest(UBUS_LAUNCHER_START_KEY_SWTICHER,
00399                                 sigc::bind(sigc::ptr_fun(ubus_launcher_register_interest_cb),
00400                                 self));
00401 
00402   nux::GetWindowCompositor().sigVisibleViewWindow.
00403   connect(sigc::bind(sigc::ptr_fun(wc_change_visibility_window_cb), self, TRUE));
00404 
00405   nux::GetWindowCompositor().sigHiddenViewWindow.
00406   connect(sigc::bind(sigc::ptr_fun(wc_change_visibility_window_cb), self, FALSE));
00407 }