a11y: Redo notebook page management

Previously, the code tried to track the indexes of the pages and keep
them up to date in a list and tracking the index in the
GtkNotebookPage. Now, we store the widget we are tracking in the
GailNotebookPage and keep a hash table of widget=>GailNotebookPage in the
GailNotebook. This frees us from the burden of tracking page changes.
This commit is contained in:
Benjamin Otte 2011-06-29 15:23:06 +02:00 committed by Matthias Clasen
parent 9cf9abd5b0
commit 790d8e324b
4 changed files with 37 additions and 177 deletions

View File

@ -43,20 +43,9 @@ static AtkObject* gail_notebook_ref_selection (AtkSelection *selection
static gint gail_notebook_get_selection_count (AtkSelection *selection); static gint gail_notebook_get_selection_count (AtkSelection *selection);
static gboolean gail_notebook_is_child_selected (AtkSelection *selection, static gboolean gail_notebook_is_child_selected (AtkSelection *selection,
gint i); gint i);
static AtkObject* find_child_in_list (GList *list,
gint index);
static void check_cache (GailNotebook *gail_notebook,
GtkNotebook *notebook);
static void reset_cache (GailNotebook *gail_notebook,
gint index);
static void create_notebook_page_accessible (GailNotebook *gail_notebook, static void create_notebook_page_accessible (GailNotebook *gail_notebook,
GtkNotebook *notebook, GtkNotebook *notebook,
gint index, GtkWidget *child);
gboolean insert_before,
GList *list);
static void gail_notebook_child_parent_set (GtkWidget *widget,
GtkWidget *old_parent,
gpointer data);
static gboolean gail_notebook_focus_cb (GtkWidget *widget, static gboolean gail_notebook_focus_cb (GtkWidget *widget,
GtkDirectionType type); GtkDirectionType type);
static gboolean gail_notebook_check_focus_tab (gpointer data); static gboolean gail_notebook_check_focus_tab (gpointer data);
@ -91,10 +80,12 @@ gail_notebook_class_init (GailNotebookClass *klass)
static void static void
gail_notebook_init (GailNotebook *notebook) gail_notebook_init (GailNotebook *notebook)
{ {
notebook->page_cache = NULL; notebook->pages = g_hash_table_new_full (g_direct_hash,
g_direct_equal,
NULL,
g_object_unref);
notebook->selected_page = -1; notebook->selected_page = -1;
notebook->focus_tab_page = -1; notebook->focus_tab_page = -1;
notebook->remove_index = -1;
notebook->idle_focus_id = 0; notebook->idle_focus_id = 0;
} }
@ -115,15 +106,13 @@ gail_notebook_ref_child (AtkObject *obj,
return NULL; return NULL;
gail_notebook = GAIL_NOTEBOOK (obj); gail_notebook = GAIL_NOTEBOOK (obj);
gtk_notebook = GTK_NOTEBOOK (widget); gtk_notebook = GTK_NOTEBOOK (widget);
if (gail_notebook->page_count < gtk_notebook_get_n_pages (gtk_notebook)) accessible = g_hash_table_lookup (gail_notebook->pages,
check_cache (gail_notebook, gtk_notebook); gtk_notebook_get_nth_page (gtk_notebook, i));
/* can return NULL when i >= n_children */
accessible = find_child_in_list (gail_notebook->page_cache, i); if (accessible)
if (accessible != NULL)
g_object_ref (accessible); g_object_ref (accessible);
return accessible; return accessible;
@ -140,8 +129,7 @@ gail_notebook_page_added (GtkNotebook *gtk_notebook,
atk_obj = gtk_widget_get_accessible (GTK_WIDGET (gtk_notebook)); atk_obj = gtk_widget_get_accessible (GTK_WIDGET (gtk_notebook));
notebook = GAIL_NOTEBOOK (atk_obj); notebook = GAIL_NOTEBOOK (atk_obj);
create_notebook_page_accessible (notebook, gtk_notebook, page_num, FALSE, NULL); create_notebook_page_accessible (notebook, gtk_notebook, child);
notebook->page_count++;
} }
static void static void
@ -152,24 +140,18 @@ gail_notebook_page_removed (GtkNotebook *notebook,
{ {
GailNotebook *gail_notebook; GailNotebook *gail_notebook;
AtkObject *obj; AtkObject *obj;
gint index;
gail_notebook = GAIL_NOTEBOOK (gtk_widget_get_accessible (GTK_WIDGET (notebook))); gail_notebook = GAIL_NOTEBOOK (gtk_widget_get_accessible (GTK_WIDGET (notebook)));
index = gail_notebook->remove_index;
gail_notebook->remove_index = -1;
obj = find_child_in_list (gail_notebook->page_cache, index); obj = g_hash_table_lookup (gail_notebook->pages, widget);
g_return_if_fail (obj); g_return_if_fail (obj);
gail_notebook->page_cache = g_list_remove (gail_notebook->page_cache, obj);
gail_notebook->page_count -= 1;
reset_cache (gail_notebook, index);
g_signal_emit_by_name (gail_notebook, g_signal_emit_by_name (gail_notebook,
"children_changed::remove", "children_changed::remove",
page_num, page_num,
obj, obj,
NULL); NULL);
gail_notebook_page_invalidate (GAIL_NOTEBOOK_PAGE (obj)); gail_notebook_page_invalidate (GAIL_NOTEBOOK_PAGE (obj));
g_object_unref (obj); g_hash_table_remove (gail_notebook->pages, widget);
} }
static void static void
@ -186,9 +168,10 @@ gail_notebook_real_initialize (AtkObject *obj,
gtk_notebook = GTK_NOTEBOOK (data); gtk_notebook = GTK_NOTEBOOK (data);
for (i = 0; i < gtk_notebook_get_n_pages (gtk_notebook); i++) for (i = 0; i < gtk_notebook_get_n_pages (gtk_notebook); i++)
{ {
create_notebook_page_accessible (notebook, gtk_notebook, i, FALSE, NULL); create_notebook_page_accessible (notebook,
gtk_notebook,
gtk_notebook_get_nth_page (gtk_notebook, i));
} }
notebook->page_count = i;
notebook->selected_page = gtk_notebook_get_current_page (gtk_notebook); notebook->selected_page = gtk_notebook_get_current_page (gtk_notebook);
g_signal_connect (gtk_notebook, g_signal_connect (gtk_notebook,
@ -231,8 +214,6 @@ gail_notebook_real_notify_gtk (GObject *obj,
gail_notebook = GAIL_NOTEBOOK (atk_obj); gail_notebook = GAIL_NOTEBOOK (atk_obj);
gtk_notebook = GTK_NOTEBOOK (widget); gtk_notebook = GTK_NOTEBOOK (widget);
if (gail_notebook->page_count < gtk_notebook_get_n_pages (gtk_notebook))
check_cache (gail_notebook, gtk_notebook);
/* /*
* Notify SELECTED state change for old and new page * Notify SELECTED state change for old and new page
*/ */
@ -290,22 +271,8 @@ static void
gail_notebook_finalize (GObject *object) gail_notebook_finalize (GObject *object)
{ {
GailNotebook *notebook = GAIL_NOTEBOOK (object); GailNotebook *notebook = GAIL_NOTEBOOK (object);
GList *list;
/* g_hash_table_destroy (notebook->pages);
* Get rid of the GailNotebookPage objects which we have cached.
*/
list = notebook->page_cache;
if (list != NULL)
{
while (list)
{
g_object_unref (list->data);
list = list->next;
}
}
g_list_free (notebook->page_cache);
if (notebook->idle_focus_id) if (notebook->idle_focus_id)
g_source_remove (notebook->idle_focus_id); g_source_remove (notebook->idle_focus_id);
@ -428,103 +395,17 @@ gail_notebook_is_child_selected (AtkSelection *selection,
return FALSE; return FALSE;
} }
static AtkObject*
find_child_in_list (GList *list,
gint index)
{
AtkObject *obj = NULL;
while (list)
{
if (GAIL_NOTEBOOK_PAGE (list->data)->index == index)
{
obj = ATK_OBJECT (list->data);
break;
}
list = list->next;
}
return obj;
}
static void
check_cache (GailNotebook *gail_notebook,
GtkNotebook *notebook)
{
GList *gtk_list;
GList *gail_list;
gint i;
gtk_list = gtk_container_get_children (GTK_CONTAINER (notebook));
gail_list = gail_notebook->page_cache;
i = 0;
while (gtk_list)
{
if (!gail_list)
{
create_notebook_page_accessible (gail_notebook, notebook, i, FALSE, NULL);
}
else if (GAIL_NOTEBOOK_PAGE (gail_list->data)->page != gtk_list->data)
{
create_notebook_page_accessible (gail_notebook, notebook, i, TRUE, gail_list);
}
else
{
gail_list = gail_list->next;
}
i++;
gtk_list = gtk_list->next;
}
g_list_free (gtk_list);
gail_notebook->page_count = i;
}
static void
reset_cache (GailNotebook *gail_notebook,
gint index)
{
GList *l;
for (l = gail_notebook->page_cache; l; l = l->next)
{
if (GAIL_NOTEBOOK_PAGE (l->data)->index > index)
GAIL_NOTEBOOK_PAGE (l->data)->index -= 1;
}
}
static void static void
create_notebook_page_accessible (GailNotebook *gail_notebook, create_notebook_page_accessible (GailNotebook *gail_notebook,
GtkNotebook *notebook, GtkNotebook *notebook,
gint index, GtkWidget *child)
gboolean insert_before,
GList *list)
{ {
AtkObject *obj; AtkObject *obj;
obj = gail_notebook_page_new (notebook, index); obj = gail_notebook_page_new (notebook, child);
g_object_ref (obj); g_hash_table_insert (gail_notebook->pages,
if (insert_before) child,
gail_notebook->page_cache = g_list_insert_before (gail_notebook->page_cache, list, obj); obj);
else
gail_notebook->page_cache = g_list_append (gail_notebook->page_cache, obj);
g_signal_connect (gtk_notebook_get_nth_page (notebook, index),
"parent_set",
G_CALLBACK (gail_notebook_child_parent_set),
obj);
}
static void
gail_notebook_child_parent_set (GtkWidget *widget,
GtkWidget *old_parent,
gpointer data)
{
GailNotebook *gail_notebook;
if (!old_parent)
return;
gail_notebook = GAIL_NOTEBOOK (gtk_widget_get_accessible (old_parent));
gail_notebook->remove_index = GAIL_NOTEBOOK_PAGE (data)->index;
} }
static gboolean static gboolean

View File

@ -44,13 +44,10 @@ struct _GailNotebook
* If the page is found in the list then a new page does not * If the page is found in the list then a new page does not
* need to be created * need to be created
*/ */
GList* page_cache; GHashTable * pages;
gint selected_page; gint selected_page;
gint focus_tab_page; gint focus_tab_page;
gint page_count;
guint idle_focus_id; guint idle_focus_id;
gint remove_index;
}; };
GType gail_notebook_get_type (void); GType gail_notebook_get_type (void);

View File

@ -156,7 +156,11 @@ notify_child_added (gpointer data)
{ {
atk_parent = gtk_widget_get_accessible (GTK_WIDGET (page->notebook)); atk_parent = gtk_widget_get_accessible (GTK_WIDGET (page->notebook));
atk_object_set_parent (atk_object, atk_parent); atk_object_set_parent (atk_object, atk_parent);
g_signal_emit_by_name (atk_parent, "children_changed::add", page->index, atk_object, NULL); g_signal_emit_by_name (atk_parent,
"children_changed::add",
gtk_notebook_page_num (page->notebook, page->child),
atk_object,
NULL);
} }
return FALSE; return FALSE;
@ -164,30 +168,20 @@ notify_child_added (gpointer data)
AtkObject* AtkObject*
gail_notebook_page_new (GtkNotebook *notebook, gail_notebook_page_new (GtkNotebook *notebook,
gint pagenum) GtkWidget *child)
{ {
GObject *object; GObject *object;
AtkObject *atk_object; AtkObject *atk_object;
GailNotebookPage *page; GailNotebookPage *page;
GtkWidget *child;
GtkWidget *label; GtkWidget *label;
GtkWidget *widget_page;
g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL); g_return_val_if_fail (GTK_IS_NOTEBOOK (notebook), NULL);
child = gtk_notebook_get_nth_page (notebook, pagenum);
if (!child)
return NULL;
object = g_object_new (GAIL_TYPE_NOTEBOOK_PAGE, NULL); object = g_object_new (GAIL_TYPE_NOTEBOOK_PAGE, NULL);
g_return_val_if_fail (object != NULL, NULL);
page = GAIL_NOTEBOOK_PAGE (object); page = GAIL_NOTEBOOK_PAGE (object);
page->notebook = notebook; page->notebook = notebook;
page->index = pagenum; page->child = child;
widget_page = gtk_notebook_get_nth_page (notebook, pagenum);
page->page = widget_page;
page->textutil = NULL; page->textutil = NULL;
atk_object = ATK_OBJECT (page); atk_object = ATK_OBJECT (page);
@ -223,6 +217,7 @@ gail_notebook_page_invalidate (GailNotebookPage *page)
TRUE); TRUE);
atk_object_set_parent (ATK_OBJECT (page), NULL); atk_object_set_parent (ATK_OBJECT (page), NULL);
page->notebook = NULL; page->notebook = NULL;
page->child = NULL;
} }
static void static void
@ -349,7 +344,6 @@ static AtkObject*
gail_notebook_page_ref_child (AtkObject *accessible, gail_notebook_page_ref_child (AtkObject *accessible,
gint i) gint i)
{ {
GtkWidget *child;
AtkObject *child_obj; AtkObject *child_obj;
GailNotebookPage *page = NULL; GailNotebookPage *page = NULL;
@ -361,11 +355,7 @@ gail_notebook_page_ref_child (AtkObject *accessible,
if (!page->notebook) if (!page->notebook)
return NULL; return NULL;
child = gtk_notebook_get_nth_page (page->notebook, page->index); child_obj = gtk_widget_get_accessible (page->child);
if (!GTK_IS_WIDGET (child))
return NULL;
child_obj = gtk_widget_get_accessible (child);
g_object_ref (child_obj); g_object_ref (child_obj);
return child_obj; return child_obj;
} }
@ -375,10 +365,11 @@ gail_notebook_page_get_index_in_parent (AtkObject *accessible)
{ {
GailNotebookPage *page; GailNotebookPage *page;
g_return_val_if_fail (GAIL_IS_NOTEBOOK_PAGE (accessible), -1);
page = GAIL_NOTEBOOK_PAGE (accessible); page = GAIL_NOTEBOOK_PAGE (accessible);
if (!page->notebook || !page->child)
return -1;
return page->index; return gtk_notebook_page_num (page->notebook, page->child);
} }
static AtkStateSet* static AtkStateSet*
@ -794,11 +785,7 @@ get_label_from_notebook_page (GailNotebookPage *page)
if (!gtk_notebook_get_show_tabs (notebook)) if (!gtk_notebook_get_show_tabs (notebook))
return NULL; return NULL;
child = gtk_notebook_get_nth_page (notebook, page->index); child = gtk_notebook_get_tab_label (notebook, page->child);
if (child == NULL) return NULL;
g_return_val_if_fail (GTK_IS_WIDGET (child), NULL);
child = gtk_notebook_get_tab_label (notebook, child);
if (GTK_IS_LABEL (child)) if (GTK_IS_LABEL (child))
return child; return child;

View File

@ -40,13 +40,8 @@ struct _GailNotebookPage
AtkObject parent; AtkObject parent;
GtkNotebook *notebook; GtkNotebook *notebook;
#ifndef GTK_DISABLE_DEPRECATED
GtkNotebookPage *page;
#else
gpointer page;
#endif
gint index; GtkWidget *child;
guint notify_child_added_id; guint notify_child_added_id;
GailTextUtil *textutil; GailTextUtil *textutil;
@ -59,7 +54,7 @@ struct _GailNotebookPageClass
AtkObjectClass parent_class; AtkObjectClass parent_class;
}; };
AtkObject *gail_notebook_page_new(GtkNotebook *notebook, gint pagenum); AtkObject *gail_notebook_page_new(GtkNotebook *notebook, GtkWidget *child);
void gail_notebook_page_invalidate (GailNotebookPage *page); void gail_notebook_page_invalidate (GailNotebookPage *page);