Back to index

unity  6.0.0
panel-indicator-accessible.c
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: Rodrigo Moya <rodrigo.moya@canonical.com>
00017  */
00018 
00019 #include <glib/gi18n.h>
00020 #include "panel-indicator-accessible.h"
00021 #include "panel-indicator-entry-accessible.h"
00022 #include "panel-service.h"
00023 
00024 /* AtkObject methods */
00025 static void         pia_component_interface_init              (AtkComponentIface *iface);
00026 
00027 static void         panel_indicator_accessible_initialize     (AtkObject *accessible, gpointer data);
00028 static gint         panel_indicator_accessible_get_n_children (AtkObject *accessible);
00029 static AtkObject   *panel_indicator_accessible_ref_child      (AtkObject *accessible, gint i);
00030 static AtkStateSet *panel_indicator_accessible_ref_state_set  (AtkObject *accessible);
00031 
00032 struct _PanelIndicatorAccessiblePrivate
00033 {
00034   IndicatorObject *indicator;
00035   PanelService *service;
00036   GSList *a11y_children;
00037   gint x;
00038   gint y;
00039   gint width;
00040   gint height;
00041 };
00042 
00043 G_DEFINE_TYPE_WITH_CODE(PanelIndicatorAccessible,
00044                      panel_indicator_accessible,
00045                      ATK_TYPE_OBJECT,
00046                      G_IMPLEMENT_INTERFACE (ATK_TYPE_COMPONENT, pia_component_interface_init))
00047 
00048 #define GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), PANEL_TYPE_INDICATOR_ACCESSIBLE, PanelIndicatorAccessiblePrivate))
00049 
00050 /* Indicator callbacks */
00051 
00052 static void
00053 on_indicator_entry_added (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data)
00054 {
00055   AtkObject *accessible;
00056   PanelIndicatorAccessible *pia = PANEL_INDICATOR_ACCESSIBLE (user_data);
00057 
00058   accessible = panel_indicator_entry_accessible_new (entry);
00059   if (accessible != NULL)
00060     {
00061       atk_object_set_parent (accessible, ATK_OBJECT (pia));
00062       pia->priv->a11y_children = g_slist_append (pia->priv->a11y_children, accessible);
00063       g_signal_emit_by_name (ATK_OBJECT (pia), "children-changed::add",
00064                           g_slist_length (pia->priv->a11y_children) - 1,
00065                           accessible);
00066     }
00067 }
00068 
00069 static void
00070 on_indicator_entry_removed (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data)
00071 {
00072   GSList *l;
00073   guint count = 0;
00074   PanelIndicatorAccessible *pia = PANEL_INDICATOR_ACCESSIBLE (user_data);
00075   gboolean found = FALSE;
00076   AtkObject *accessible = NULL;
00077 
00078   for (l = pia->priv->a11y_children; l != NULL; l = g_slist_next (l))
00079     {
00080       accessible = ATK_OBJECT (l->data);
00081 
00082       if (entry == panel_indicator_entry_accessible_get_entry (PANEL_INDICATOR_ENTRY_ACCESSIBLE (accessible)))
00083         {
00084           found = TRUE;
00085           break;
00086        }
00087       else
00088         count++;
00089     }
00090 
00091 
00092   if (found)
00093     {
00094       pia->priv->a11y_children = g_slist_remove (pia->priv->a11y_children, accessible);
00095       g_signal_emit_by_name (ATK_OBJECT (pia), "children-changed::remove",
00096                              count, accessible);
00097 
00098       g_object_unref (accessible);
00099     }
00100 }
00101 
00102 static void
00103 on_accessible_desc_updated (IndicatorObject *io, IndicatorObjectEntry *entry, gpointer user_data)
00104 {
00105   GSList *l;
00106   PanelIndicatorAccessible *pia = PANEL_INDICATOR_ACCESSIBLE (user_data);
00107   gboolean found = FALSE;
00108   AtkObject *entry_accessible = NULL;
00109   AtkObject *widget_accessible = NULL;
00110 
00111   for (l = pia->priv->a11y_children; l != NULL; l = l->next)
00112     {
00113       entry_accessible = ATK_OBJECT (l->data);
00114 
00115       if (entry == panel_indicator_entry_accessible_get_entry (PANEL_INDICATOR_ENTRY_ACCESSIBLE (entry_accessible)))
00116         {
00117           found = TRUE;
00118           break;
00119         }
00120     }
00121 
00122   if (!found)
00123     return;
00124 
00125   if (GTK_IS_LABEL (entry->label))
00126     {
00127       widget_accessible = gtk_widget_get_accessible (GTK_WIDGET (entry->label));
00128     }
00129   else if (GTK_IS_IMAGE (entry->image))
00130     {
00131       widget_accessible = gtk_widget_get_accessible (GTK_WIDGET (entry->image));
00132     }
00133   else
00134     {
00135       g_warning ("a11y: Current entry is not a label or a image.");
00136     }
00137 
00138   if (ATK_IS_OBJECT (widget_accessible))
00139     {
00140       gchar *name = (gchar*) atk_object_get_name (widget_accessible);
00141       gchar *description = (gchar*) entry->accessible_desc;
00142 
00143       if (name == NULL)
00144         name = "";
00145 
00146       if (description == NULL)
00147         description = "";
00148 
00149       atk_object_set_name (entry_accessible, name);
00150       atk_object_set_description (entry_accessible, description);
00151     }
00152 }
00153 
00154 static void
00155 on_geometries_changed_cb (PanelService *service,
00156                        IndicatorObject *object,
00157                        IndicatorObjectEntry *entry,
00158                        gint x,
00159                        gint y,
00160                        gint width,
00161                        gint height,
00162                        gpointer user_data)
00163 {
00164   PanelIndicatorAccessible *pia;
00165   AtkRectangle rect;
00166   GSList *l;
00167   gboolean minimum_set = FALSE;
00168 
00169   pia = PANEL_INDICATOR_ACCESSIBLE (user_data);
00170 
00171   g_return_if_fail (PANEL_IS_INDICATOR_ACCESSIBLE (pia));
00172 
00173   if (object != pia->priv->indicator)
00174     return;
00175 
00176   /* Iterate over all children to get width and height */
00177   pia->priv->width = pia->priv->height = 0;
00178 
00179   for (l = pia->priv->a11y_children; l != NULL; l = l->next)
00180     {
00181       gint e_x, e_y, e_width, e_height;
00182       AtkObject *accessible = ATK_OBJECT (l->data);
00183 
00184       atk_component_get_extents (ATK_COMPONENT (accessible), &e_x, &e_y, &e_width, &e_height, ATK_XY_SCREEN);
00185       if (minimum_set)
00186         {
00187           if (e_x < pia->priv->x)
00188             pia->priv->x = e_x;
00189           if (e_y < pia->priv->y)
00190             pia->priv->y = e_y;
00191        }
00192       else
00193         {
00194          pia->priv->x = e_x;
00195          pia->priv->y = e_y;
00196          minimum_set = TRUE;
00197        }
00198 
00199       pia->priv->width += e_width;
00200       if (e_height > pia->priv->height)
00201        pia->priv->height = e_height;
00202     }
00203 
00204   /* Notify ATK objects of change of coordinates */
00205   rect.x = pia->priv->x;
00206   rect.y = pia->priv->y;
00207   rect.width = pia->priv->width;
00208   rect.height = pia->priv->height;
00209   g_signal_emit_by_name (ATK_COMPONENT (pia), "bounds-changed", &rect);
00210 }
00211 
00212 static void
00213 panel_indicator_accessible_finalize (GObject *object)
00214 {
00215   PanelIndicatorAccessible *pia = PANEL_INDICATOR_ACCESSIBLE (object);
00216 
00217   if (pia->priv != NULL)
00218     {
00219       if (pia->priv->indicator != NULL)
00220         {
00221           g_signal_handlers_disconnect_by_func (pia->priv->indicator, on_indicator_entry_added, pia);
00222           g_signal_handlers_disconnect_by_func (pia->priv->indicator, on_indicator_entry_removed, pia);
00223           g_signal_handlers_disconnect_by_func (pia->priv->indicator, on_accessible_desc_updated, pia);
00224 
00225           g_object_unref (G_OBJECT (pia->priv->indicator));
00226         }
00227 
00228       if (pia->priv->a11y_children != NULL)
00229         {
00230           g_slist_free_full(pia->priv->a11y_children, g_object_unref);
00231           pia->priv->a11y_children = NULL;
00232        }
00233 
00234       g_signal_handlers_disconnect_by_func (pia->priv->service, on_geometries_changed_cb, pia);
00235     }
00236 
00237   G_OBJECT_CLASS (panel_indicator_accessible_parent_class)->finalize (object);
00238 }
00239 
00240 static void
00241 panel_indicator_accessible_class_init (PanelIndicatorAccessibleClass *klass)
00242 {
00243   GObjectClass *object_class;
00244   AtkObjectClass *atk_class;
00245 
00246   /* GObject */
00247   object_class = G_OBJECT_CLASS (klass);
00248   object_class->finalize = panel_indicator_accessible_finalize;
00249 
00250   /* AtkObject */
00251   atk_class = ATK_OBJECT_CLASS (klass);
00252   atk_class->initialize = panel_indicator_accessible_initialize;
00253   atk_class->get_n_children = panel_indicator_accessible_get_n_children;
00254   atk_class->ref_child = panel_indicator_accessible_ref_child;
00255   atk_class->ref_state_set = panel_indicator_accessible_ref_state_set;
00256 
00257   g_type_class_add_private (object_class, sizeof (PanelIndicatorAccessiblePrivate));
00258 }
00259 
00260 static void
00261 panel_indicator_accessible_init (PanelIndicatorAccessible *pia)
00262 {
00263   pia->priv = GET_PRIVATE (pia);
00264   pia->priv->a11y_children = NULL;
00265   pia->priv->x = pia->priv->y = pia->priv->width = pia->priv->height = 0;
00266 
00267   /* Set up signals for listening to service changes */
00268   pia->priv->service = panel_service_get_default ();
00269   g_signal_connect (pia->priv->service, "geometries-changed",
00270                   G_CALLBACK (on_geometries_changed_cb), pia);
00271 }
00272 
00273 AtkObject *
00274 panel_indicator_accessible_new (IndicatorObject *indicator)
00275 {
00276   PanelIndicatorAccessible *pia;
00277 
00278   pia = g_object_new (PANEL_TYPE_INDICATOR_ACCESSIBLE, NULL);
00279   atk_object_initialize (ATK_OBJECT (pia), indicator);
00280 
00281   return ATK_OBJECT (pia);
00282 }
00283 
00284 /* Implementation of AtkObject methods */
00285 
00286 static void
00287 panel_indicator_accessible_get_extents (AtkComponent *component,
00288                                    gint *x,
00289                                    gint *y,
00290                                    gint *width,
00291                                    gint *height,
00292                                    AtkCoordType coord_type)
00293 {
00294   PanelIndicatorAccessible *pia;
00295 
00296   g_return_if_fail (PANEL_IS_INDICATOR_ACCESSIBLE (component));
00297 
00298   pia = PANEL_INDICATOR_ACCESSIBLE (component);
00299 
00300   /* We ignore AtkCoordType for now, as the panel is always at the top left
00301      corner and so relative and absolute coordinates are the same */
00302   *x = pia->priv->x;
00303   *y = pia->priv->y;
00304   *width = pia->priv->width;
00305   *height = pia->priv->height;
00306 }
00307 
00308 static void
00309 pia_component_interface_init (AtkComponentIface *iface)
00310 {
00311   g_return_if_fail (iface != NULL);
00312 
00313   iface->get_extents = panel_indicator_accessible_get_extents;
00314 }
00315 
00316 static void
00317 panel_indicator_accessible_initialize (AtkObject *accessible, gpointer data)
00318 {
00319   PanelIndicatorAccessible *pia;
00320   GList *entries, *l;
00321 
00322   g_return_if_fail (PANEL_IS_INDICATOR_ACCESSIBLE (accessible));
00323 
00324   ATK_OBJECT_CLASS (panel_indicator_accessible_parent_class)->initialize (accessible, data);
00325 
00326   pia = PANEL_INDICATOR_ACCESSIBLE (accessible);
00327   atk_object_set_role (accessible, ATK_ROLE_PANEL);
00328 
00329   /* Setup the indicator object */
00330   pia->priv->indicator = g_object_ref (data);
00331   g_signal_connect (G_OBJECT (pia->priv->indicator), "entry-added",
00332                     G_CALLBACK (on_indicator_entry_added), pia);
00333   g_signal_connect (G_OBJECT (pia->priv->indicator), "entry-removed",
00334                     G_CALLBACK (on_indicator_entry_removed), pia);
00335   g_signal_connect (G_OBJECT (pia->priv->indicator), "accessible_desc_update",
00336                     G_CALLBACK (on_accessible_desc_updated), pia);
00337 
00338   /* Retrieve all entries and create their accessible objects */
00339   entries = indicator_object_get_entries (pia->priv->indicator);
00340   for (l = entries; l != NULL; l = l->next)
00341     {
00342       AtkObject *child;
00343       IndicatorObjectEntry *entry = (IndicatorObjectEntry *) l->data;
00344 
00345       child = panel_indicator_entry_accessible_new (entry);
00346       atk_object_set_parent (child, accessible);
00347       pia->priv->a11y_children = g_slist_append (pia->priv->a11y_children, child);
00348     }
00349 
00350   g_list_free (entries);
00351 }
00352 
00353 static gint
00354 panel_indicator_accessible_get_n_children (AtkObject *accessible)
00355 {
00356   PanelIndicatorAccessible *pia = PANEL_INDICATOR_ACCESSIBLE (accessible);
00357 
00358   g_return_val_if_fail (PANEL_IS_INDICATOR_ACCESSIBLE (pia), 0);
00359 
00360   return g_slist_length (pia->priv->a11y_children);
00361 }
00362 
00363 static AtkObject *
00364 panel_indicator_accessible_ref_child (AtkObject *accessible, gint i)
00365 {
00366   PanelIndicatorAccessible *pia = PANEL_INDICATOR_ACCESSIBLE (accessible);
00367 
00368   g_return_val_if_fail (PANEL_IS_INDICATOR_ACCESSIBLE (pia), NULL);
00369 
00370   return g_object_ref (g_slist_nth_data (pia->priv->a11y_children, i));
00371 }
00372 
00373 static AtkStateSet *
00374 panel_indicator_accessible_ref_state_set (AtkObject *accessible)
00375 {
00376   AtkStateSet *state_set;
00377 
00378   g_return_val_if_fail (PANEL_IS_INDICATOR_ACCESSIBLE (accessible), NULL);
00379 
00380   /* Retrieve state_set from parent_class */
00381   state_set = ATK_OBJECT_CLASS (panel_indicator_accessible_parent_class)->ref_state_set (accessible);
00382 
00383   atk_state_set_add_state (state_set, ATK_STATE_VISIBLE);
00384 
00385   return state_set;
00386 }