]> Pileus Git - ~andy/gtk/blobdiff - gtk/a11y/gtkmenuitemaccessible.c
filechooser: Show FUSE mounted locations in shortcuts
[~andy/gtk] / gtk / a11y / gtkmenuitemaccessible.c
index ddea3528dc208da5a423e63486be2764164e6765..15ef15dbed89d66bb8628254bd73fc8983ff3e4a 100644 (file)
@@ -1,4 +1,4 @@
-/* GAIL - The GNOME Accessibility Implementation Library
+/* GTK+ - accessibility implementations
  * Copyright 2001, 2002, 2003 Sun Microsystems Inc.
  *
  * This library is free software; you can redistribute it and/or
  * Lesser General Public License for more details.
  *
  * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "config.h"
+
+#include <glib/gi18n-lib.h>
 #include <string.h>
 #include <gtk/gtk.h>
 #include "gtkmenuitemaccessible.h"
-#include "gtksubmenuitemaccessible.h"
+#include "gtkwidgetaccessibleprivate.h"
 #include "gtk/gtkmenuitemprivate.h"
 
+struct _GtkMenuItemAccessiblePrivate
+{
+  gchar *text;
+  gboolean selected;
+};
+
 #define KEYBINDING_SEPARATOR ";"
 
 static void menu_item_select   (GtkMenuItem *item);
@@ -31,11 +38,17 @@ static void menu_item_deselect (GtkMenuItem *item);
 static GtkWidget *get_label_from_container   (GtkWidget *container);
 static gchar     *get_text_from_label_widget (GtkWidget *widget);
 
+static gint menu_item_add_gtk    (GtkContainer   *container,
+                                  GtkWidget      *widget);
+static gint menu_item_remove_gtk (GtkContainer   *container,
+                                  GtkWidget      *widget);
 
-static void atk_action_interface_init (AtkActionIface *iface);
+static void atk_action_interface_init    (AtkActionIface *iface);
+static void atk_selection_interface_init (AtkSelectionIface *iface);
 
-G_DEFINE_TYPE_WITH_CODE (GtkMenuItemAccessible, _gtk_menu_item_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
-                         G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init))
+G_DEFINE_TYPE_WITH_CODE (GtkMenuItemAccessible, gtk_menu_item_accessible, GTK_TYPE_CONTAINER_ACCESSIBLE,
+                         G_IMPLEMENT_INTERFACE (ATK_TYPE_ACTION, atk_action_interface_init);
+                         G_IMPLEMENT_INTERFACE (ATK_TYPE_SELECTION, atk_selection_interface_init))
 
 static void
 gtk_menu_item_accessible_initialize (AtkObject *obj,
@@ -43,8 +56,9 @@ gtk_menu_item_accessible_initialize (AtkObject *obj,
 {
   GtkWidget *widget;
   GtkWidget *parent;
+  GtkWidget *menu;
 
-  ATK_OBJECT_CLASS (_gtk_menu_item_accessible_parent_class)->initialize (obj, data);
+  ATK_OBJECT_CLASS (gtk_menu_item_accessible_parent_class)->initialize (obj, data);
 
   g_signal_connect (data, "select", G_CALLBACK (menu_item_select), NULL);
   g_signal_connect (data, "deselect", G_CALLBACK (menu_item_deselect), NULL);
@@ -63,12 +77,16 @@ gtk_menu_item_accessible_initialize (AtkObject *obj,
         atk_object_set_parent (obj, gtk_widget_get_accessible (parent_widget));
     }
 
-  GTK_WIDGET_ACCESSIBLE (obj)->layer = ATK_LAYER_POPUP;
+  _gtk_widget_accessible_set_layer (GTK_WIDGET_ACCESSIBLE (obj), ATK_LAYER_POPUP);
 
-  if (GTK_IS_TEAROFF_MENU_ITEM (data))
-    obj->role = ATK_ROLE_TEAR_OFF_MENU_ITEM;
-  else
-    obj->role = ATK_ROLE_MENU_ITEM;
+  obj->role = ATK_ROLE_MENU_ITEM;
+
+  menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (data));
+  if (menu)
+    {
+      g_signal_connect (menu, "add", G_CALLBACK (menu_item_add_gtk), NULL);
+      g_signal_connect (menu, "remove", G_CALLBACK (menu_item_remove_gtk), NULL);
+    }
 }
 
 static gint
@@ -132,7 +150,11 @@ gtk_menu_item_accessible_ref_state_set (AtkObject *obj)
   AtkObject *menu_item;
   AtkStateSet *state_set, *parent_state_set;
 
-  state_set = ATK_OBJECT_CLASS (_gtk_menu_item_accessible_parent_class)->ref_state_set (obj);
+  state_set = ATK_OBJECT_CLASS (gtk_menu_item_accessible_parent_class)->ref_state_set (obj);
+
+  atk_state_set_add_state (state_set, ATK_STATE_SELECTABLE);
+  if (GTK_MENU_ITEM_ACCESSIBLE (obj)->priv->selected)
+    atk_state_set_add_state (state_set, ATK_STATE_SELECTED);
 
   menu_item = atk_object_get_parent (obj);
 
@@ -163,7 +185,7 @@ gtk_menu_item_accessible_get_role (AtkObject *obj)
       gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget)))
     return ATK_ROLE_MENU;
 
-  return ATK_OBJECT_CLASS (_gtk_menu_item_accessible_parent_class)->get_role (obj);
+  return ATK_OBJECT_CLASS (gtk_menu_item_accessible_parent_class)->get_role (obj);
 }
 
 static const gchar *
@@ -178,17 +200,17 @@ gtk_menu_item_accessible_get_name (AtkObject *obj)
   if (widget == NULL)
     return NULL;
 
-  name = ATK_OBJECT_CLASS (_gtk_menu_item_accessible_parent_class)->get_name (obj);
+  name = ATK_OBJECT_CLASS (gtk_menu_item_accessible_parent_class)->get_name (obj);
   if (name)
     return name;
 
   accessible = GTK_MENU_ITEM_ACCESSIBLE (obj);
   label = get_label_from_container (widget);
 
-  g_free (accessible->text);
-  accessible->text = get_text_from_label_widget (label);
+  g_free (accessible->priv->text);
+  accessible->priv->text = get_text_from_label_widget (label);
 
-  return accessible->text;
+  return accessible->priv->text;
 }
 
 static void
@@ -196,9 +218,9 @@ gtk_menu_item_accessible_finalize (GObject *object)
 {
   GtkMenuItemAccessible *accessible = GTK_MENU_ITEM_ACCESSIBLE (object);
 
-  g_free (accessible->text);
+  g_free (accessible->priv->text);
 
-  G_OBJECT_CLASS (_gtk_menu_item_accessible_parent_class)->finalize (object);
+  G_OBJECT_CLASS (gtk_menu_item_accessible_parent_class)->finalize (object);
 }
 
 static void
@@ -216,11 +238,11 @@ gtk_menu_item_accessible_notify_gtk (GObject    *obj,
       g_signal_emit_by_name (atk_obj, "visible-data-changed");
     }
   else
-    GTK_WIDGET_ACCESSIBLE_CLASS (_gtk_menu_item_accessible_parent_class)->notify_gtk (obj, pspec);
+    GTK_WIDGET_ACCESSIBLE_CLASS (gtk_menu_item_accessible_parent_class)->notify_gtk (obj, pspec);
 }
 
 static void
-_gtk_menu_item_accessible_class_init (GtkMenuItemAccessibleClass *klass)
+gtk_menu_item_accessible_class_init (GtkMenuItemAccessibleClass *klass)
 {
   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
   AtkObjectClass *class = ATK_OBJECT_CLASS (klass);
@@ -236,11 +258,16 @@ _gtk_menu_item_accessible_class_init (GtkMenuItemAccessibleClass *klass)
   class->initialize = gtk_menu_item_accessible_initialize;
   class->get_name = gtk_menu_item_accessible_get_name;
   class->get_role = gtk_menu_item_accessible_get_role;
+
+  g_type_class_add_private (klass, sizeof (GtkMenuItemAccessiblePrivate));
 }
 
 static void
-_gtk_menu_item_accessible_init (GtkMenuItemAccessible *menu_item)
+gtk_menu_item_accessible_init (GtkMenuItemAccessible *menu_item)
 {
+  menu_item->priv = G_TYPE_INSTANCE_GET_PRIVATE (menu_item,
+                                                 GTK_TYPE_MENU_ITEM_ACCESSIBLE,
+                                                 GtkMenuItemAccessiblePrivate);
 }
 
 static GtkWidget *
@@ -396,10 +423,27 @@ static const gchar *
 gtk_menu_item_accessible_action_get_name (AtkAction *action,
                                           gint       i)
 {
-  if (i != 0 || gtk_menu_item_accessible_get_n_actions (action) == 0)
-    return NULL;
+  if (i == 0 && gtk_menu_item_accessible_get_n_actions (action) > 0)
+    return "click";
+  return NULL;
+}
 
-  return "click";
+static const gchar *
+gtk_menu_item_accessible_action_get_localized_name (AtkAction *action,
+                                                    gint       i)
+{
+  if (i == 0 && gtk_menu_item_accessible_get_n_actions (action) > 0)
+    return C_("Action name", "Click");
+  return NULL;
+}
+
+static const gchar *
+gtk_menu_item_accessible_action_get_description (AtkAction *action,
+                                                 gint       i)
+{
+  if (i == 0 && gtk_menu_item_accessible_get_n_actions (action) > 0)
+    return C_("Action description", "Clicks the menuitem");
+  return NULL;
 }
 
 static gboolean
@@ -591,6 +635,8 @@ atk_action_interface_init (AtkActionIface *iface)
   iface->do_action = gtk_menu_item_accessible_do_action;
   iface->get_n_actions = gtk_menu_item_accessible_get_n_actions;
   iface->get_name = gtk_menu_item_accessible_action_get_name;
+  iface->get_localized_name = gtk_menu_item_accessible_action_get_localized_name;
+  iface->get_description = gtk_menu_item_accessible_action_get_description;
   iface->get_keybinding = gtk_menu_item_accessible_get_keybinding;
 }
 
@@ -602,6 +648,7 @@ menu_item_selection (GtkMenuItem  *item,
   gint i;
 
   obj = gtk_widget_get_accessible (GTK_WIDGET (item));
+  GTK_MENU_ITEM_ACCESSIBLE (obj)->priv->selected = selected;
   atk_object_notify_state_change (obj, ATK_STATE_SELECTED, selected);
 
   for (i = 0; i < atk_object_get_n_accessible_children (obj); i++)
@@ -615,6 +662,221 @@ menu_item_selection (GtkMenuItem  *item,
   g_signal_emit_by_name (parent, "selection-changed");
 }
 
+static gboolean
+gtk_menu_item_accessible_add_selection (AtkSelection *selection,
+                                           gint          i)
+{
+  GtkMenuShell *shell;
+  GList *kids;
+  guint length;
+  GtkWidget *widget;
+  GtkWidget *menu;
+  GtkWidget *child;
+
+  widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
+  if (widget == NULL)
+    return FALSE;
+
+  menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  if (menu == NULL)
+    return FALSE;
+
+  shell = GTK_MENU_SHELL (menu);
+  kids = gtk_container_get_children (GTK_CONTAINER (shell));
+  length = g_list_length (kids);
+  if (i < 0 || i > length)
+    {
+      g_list_free (kids);
+      return FALSE;
+    }
+
+  child = g_list_nth_data (kids, i);
+  g_list_free (kids);
+  g_return_val_if_fail (GTK_IS_MENU_ITEM (child), FALSE);
+  gtk_menu_shell_select_item (shell, GTK_WIDGET (child));
+  return TRUE;
+}
+
+static gboolean
+gtk_menu_item_accessible_clear_selection (AtkSelection *selection)
+{
+  GtkWidget *widget;
+  GtkWidget *menu;
+
+  widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
+  if (widget == NULL)
+    return FALSE;
+
+  menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  if (menu == NULL)
+    return FALSE;
+
+  gtk_menu_shell_deselect (GTK_MENU_SHELL (menu));
+
+  return TRUE;
+}
+
+static AtkObject *
+gtk_menu_item_accessible_ref_selection (AtkSelection *selection,
+                                           gint          i)
+{
+  GtkMenuShell *shell;
+  AtkObject *obj;
+  GtkWidget *widget;
+  GtkWidget *menu;
+  GtkWidget *item;
+
+  if (i != 0)
+    return NULL;
+
+  widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
+  if (widget == NULL)
+    return NULL;
+
+  menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  if (menu == NULL)
+    return NULL;
+
+  shell = GTK_MENU_SHELL (menu);
+
+  item = gtk_menu_shell_get_selected_item (shell);
+  if (item != NULL)
+    {
+      obj = gtk_widget_get_accessible (item);
+      g_object_ref (obj);
+      return obj;
+    }
+
+  return NULL;
+}
+
+static gint
+gtk_menu_item_accessible_get_selection_count (AtkSelection *selection)
+{
+  GtkMenuShell *shell;
+  GtkWidget *widget;
+  GtkWidget *menu;
+
+  widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
+  if (widget == NULL)
+    return 0;
+
+  menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  if (menu == NULL)
+    return 0;
+
+  shell = GTK_MENU_SHELL (menu);
+
+  if (gtk_menu_shell_get_selected_item (shell) != NULL)
+    return 1;
+
+  return 0;
+}
+
+static gboolean
+gtk_menu_item_accessible_is_child_selected (AtkSelection *selection,
+                                               gint          i)
+{
+  GtkMenuShell *shell;
+  gint j;
+  GtkWidget *widget;
+  GtkWidget *menu;
+  GtkWidget *item;
+  GList *kids;
+
+  widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
+  if (widget == NULL)
+    return FALSE;
+
+  menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  if (menu == NULL)
+    return FALSE;
+
+  shell = GTK_MENU_SHELL (menu);
+
+  item = gtk_menu_shell_get_selected_item (shell);
+  if (item == NULL)
+    return FALSE;
+
+  kids = gtk_container_get_children (GTK_CONTAINER (shell));
+  j = g_list_index (kids, item);
+  g_list_free (kids);
+
+  return j==i;
+}
+
+static gboolean
+gtk_menu_item_accessible_remove_selection (AtkSelection *selection,
+                                              gint          i)
+{
+  GtkMenuShell *shell;
+  GtkWidget *widget;
+  GtkWidget *menu;
+  GtkWidget *item;
+
+  if (i != 0)
+    return FALSE;
+
+  widget =  gtk_accessible_get_widget (GTK_ACCESSIBLE (selection));
+  if (widget == NULL)
+    return FALSE;
+
+  menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (widget));
+  if (menu == NULL)
+    return FALSE;
+
+  shell = GTK_MENU_SHELL (menu);
+
+  item = gtk_menu_shell_get_selected_item (shell);
+  if (item && gtk_menu_item_get_submenu (GTK_MENU_ITEM (item)))
+    gtk_menu_shell_deselect (shell);
+
+  return TRUE;
+}
+
+static void
+atk_selection_interface_init (AtkSelectionIface *iface)
+{
+  iface->add_selection = gtk_menu_item_accessible_add_selection;
+  iface->clear_selection = gtk_menu_item_accessible_clear_selection;
+  iface->ref_selection = gtk_menu_item_accessible_ref_selection;
+  iface->get_selection_count = gtk_menu_item_accessible_get_selection_count;
+  iface->is_child_selected = gtk_menu_item_accessible_is_child_selected;
+  iface->remove_selection = gtk_menu_item_accessible_remove_selection;
+}
+
+static gint
+menu_item_add_gtk (GtkContainer *container,
+                   GtkWidget    *widget)
+{
+  GtkWidget *parent_widget;
+
+  g_return_val_if_fail (GTK_IS_MENU (container), 1);
+
+  parent_widget = gtk_menu_get_attach_widget (GTK_MENU (container));
+  if (GTK_IS_MENU_ITEM (parent_widget))
+    {
+      GTK_CONTAINER_ACCESSIBLE_CLASS (gtk_menu_item_accessible_parent_class)->add_gtk (container, widget, gtk_widget_get_accessible (parent_widget));
+
+    }
+  return 1;
+}
+
+static gint
+menu_item_remove_gtk (GtkContainer *container,
+                      GtkWidget    *widget)
+{
+  GtkWidget *parent_widget;
+
+  g_return_val_if_fail (GTK_IS_MENU (container), 1);
+
+  parent_widget = gtk_menu_get_attach_widget (GTK_MENU (container));
+  if (GTK_IS_MENU_ITEM (parent_widget))
+    {
+      GTK_CONTAINER_ACCESSIBLE_CLASS (gtk_menu_item_accessible_parent_class)->remove_gtk (container, widget, gtk_widget_get_accessible (parent_widget));
+    }
+  return 1;
+}
 static void
 menu_item_select (GtkMenuItem *item)
 {