|
|
0489c0 |
From d928258bb4f3e21973089183463c4dab11558b73 Mon Sep 17 00:00:00 2001
|
|
|
0489c0 |
From: Milan Crha <mcrha@redhat.com>
|
|
|
0489c0 |
Date: Wed, 18 Sep 2019 14:12:44 +0200
|
|
|
0489c0 |
Subject: I#624 - GalA11yETableItem: Incorrect implementation of
|
|
|
0489c0 |
AtkObjectClass::ref_child()
|
|
|
0489c0 |
|
|
|
0489c0 |
Closes https://gitlab.gnome.org/GNOME/evolution/issues/624
|
|
|
0489c0 |
|
|
|
0489c0 |
diff --git a/src/e-util/gal-a11y-e-table-item.c b/src/e-util/gal-a11y-e-table-item.c
|
|
|
0489c0 |
index cf06fb3f4f..be302ed09d 100644
|
|
|
0489c0 |
--- a/src/e-util/gal-a11y-e-table-item.c
|
|
|
0489c0 |
+++ b/src/e-util/gal-a11y-e-table-item.c
|
|
|
0489c0 |
@@ -61,6 +61,7 @@ struct _GalA11yETableItemPrivate {
|
|
|
0489c0 |
ESelectionModel *selection;
|
|
|
0489c0 |
AtkStateSet *state_set;
|
|
|
0489c0 |
GtkWidget *widget;
|
|
|
0489c0 |
+ GHashTable *a11y_column_headers; /* ETableCol * ~> GalA11yETableColumnHeader * */
|
|
|
0489c0 |
};
|
|
|
0489c0 |
|
|
|
0489c0 |
static gboolean gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y,
|
|
|
0489c0 |
@@ -124,6 +125,11 @@ item_finalized (gpointer user_data,
|
|
|
0489c0 |
if (priv->selection)
|
|
|
0489c0 |
gal_a11y_e_table_item_unref_selection (a11y);
|
|
|
0489c0 |
|
|
|
0489c0 |
+ if (priv->columns) {
|
|
|
0489c0 |
+ free_columns (priv->columns);
|
|
|
0489c0 |
+ priv->columns = NULL;
|
|
|
0489c0 |
+ }
|
|
|
0489c0 |
+
|
|
|
0489c0 |
g_object_unref (a11y);
|
|
|
0489c0 |
}
|
|
|
0489c0 |
|
|
|
0489c0 |
@@ -273,11 +279,60 @@ eti_a11y_reset_focus_object (GalA11yETableItem *a11y,
|
|
|
0489c0 |
g_signal_emit_by_name (a11y, "active-descendant-changed", cell);
|
|
|
0489c0 |
}
|
|
|
0489c0 |
|
|
|
0489c0 |
+static void eti_column_header_a11y_gone (gpointer user_data, GObject *a11y_col_header);
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+static void
|
|
|
0489c0 |
+eti_table_column_gone (gpointer user_data,
|
|
|
0489c0 |
+ GObject *col)
|
|
|
0489c0 |
+{
|
|
|
0489c0 |
+ GalA11yETableItem *a11y = user_data;
|
|
|
0489c0 |
+ GalA11yETableItemPrivate *priv;
|
|
|
0489c0 |
+ GalA11yETableColumnHeader *a11y_col_header;
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y));
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ priv = GET_PRIVATE (a11y);
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ a11y_col_header = g_hash_table_lookup (priv->a11y_column_headers, col);
|
|
|
0489c0 |
+ g_hash_table_remove (priv->a11y_column_headers, col);
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ if (a11y_col_header)
|
|
|
0489c0 |
+ g_object_weak_unref (G_OBJECT (a11y_col_header), eti_column_header_a11y_gone, a11y);
|
|
|
0489c0 |
+}
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+static void
|
|
|
0489c0 |
+eti_column_header_a11y_gone (gpointer user_data,
|
|
|
0489c0 |
+ GObject *a11y_col_header)
|
|
|
0489c0 |
+{
|
|
|
0489c0 |
+ GalA11yETableItem *a11y = user_data;
|
|
|
0489c0 |
+ GalA11yETableItemPrivate *priv;
|
|
|
0489c0 |
+ GHashTableIter iter;
|
|
|
0489c0 |
+ gpointer key, value;
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ g_return_if_fail (GAL_A11Y_IS_E_TABLE_ITEM (a11y));
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ priv = GET_PRIVATE (a11y);
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ g_hash_table_iter_init (&iter, priv->a11y_column_headers);
|
|
|
0489c0 |
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
|
|
|
0489c0 |
+ ETableCol *col = key;
|
|
|
0489c0 |
+ GalA11yETableColumnHeader *stored_a11y_col_header = value;
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ if (((GObject *) stored_a11y_col_header) == a11y_col_header) {
|
|
|
0489c0 |
+ g_object_weak_unref (G_OBJECT (col), eti_table_column_gone, a11y);
|
|
|
0489c0 |
+ g_hash_table_remove (priv->a11y_column_headers, col);
|
|
|
0489c0 |
+ break;
|
|
|
0489c0 |
+ }
|
|
|
0489c0 |
+ }
|
|
|
0489c0 |
+}
|
|
|
0489c0 |
+
|
|
|
0489c0 |
static void
|
|
|
0489c0 |
eti_dispose (GObject *object)
|
|
|
0489c0 |
{
|
|
|
0489c0 |
GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (object);
|
|
|
0489c0 |
GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
|
|
|
0489c0 |
+ GHashTableIter iter;
|
|
|
0489c0 |
+ gpointer key, value;
|
|
|
0489c0 |
|
|
|
0489c0 |
if (priv->columns) {
|
|
|
0489c0 |
free_columns (priv->columns);
|
|
|
0489c0 |
@@ -289,10 +344,35 @@ eti_dispose (GObject *object)
|
|
|
0489c0 |
priv->item = NULL;
|
|
|
0489c0 |
}
|
|
|
0489c0 |
|
|
|
0489c0 |
+ g_clear_object (&priv->state_set);
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ g_hash_table_iter_init (&iter, priv->a11y_column_headers);
|
|
|
0489c0 |
+ while (g_hash_table_iter_next (&iter, &key, &value)) {
|
|
|
0489c0 |
+ ETableCol *col = key;
|
|
|
0489c0 |
+ GalA11yETableColumnHeader *a11y_col_header = value;
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ g_object_weak_unref (G_OBJECT (col), eti_table_column_gone, a11y);
|
|
|
0489c0 |
+ g_object_weak_unref (G_OBJECT (a11y_col_header), eti_column_header_a11y_gone, a11y);
|
|
|
0489c0 |
+ }
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ g_hash_table_remove_all (priv->a11y_column_headers);
|
|
|
0489c0 |
+
|
|
|
0489c0 |
if (parent_class->dispose)
|
|
|
0489c0 |
parent_class->dispose (object);
|
|
|
0489c0 |
}
|
|
|
0489c0 |
|
|
|
0489c0 |
+static void
|
|
|
0489c0 |
+eti_finalize (GObject *object)
|
|
|
0489c0 |
+{
|
|
|
0489c0 |
+ GalA11yETableItem *a11y = GAL_A11Y_E_TABLE_ITEM (object);
|
|
|
0489c0 |
+ GalA11yETableItemPrivate *priv = GET_PRIVATE (a11y);
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ g_hash_table_destroy (priv->a11y_column_headers);
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ if (parent_class->finalize)
|
|
|
0489c0 |
+ parent_class->finalize (object);
|
|
|
0489c0 |
+}
|
|
|
0489c0 |
+
|
|
|
0489c0 |
/* Static functions */
|
|
|
0489c0 |
static gint
|
|
|
0489c0 |
eti_get_n_children (AtkObject *accessible)
|
|
|
0489c0 |
@@ -318,12 +398,24 @@ eti_ref_child (AtkObject *accessible,
|
|
|
0489c0 |
return NULL;
|
|
|
0489c0 |
|
|
|
0489c0 |
if (index < item->cols) {
|
|
|
0489c0 |
+ GalA11yETableItemPrivate *priv = GET_PRIVATE (accessible);
|
|
|
0489c0 |
ETableCol *ecol;
|
|
|
0489c0 |
AtkObject *child;
|
|
|
0489c0 |
|
|
|
0489c0 |
ecol = e_table_header_get_column (item->header, index);
|
|
|
0489c0 |
- child = gal_a11y_e_table_column_header_new (ecol, item, accessible);
|
|
|
0489c0 |
- return child;
|
|
|
0489c0 |
+ child = g_hash_table_lookup (priv->a11y_column_headers, ecol);
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ if (!child) {
|
|
|
0489c0 |
+ child = gal_a11y_e_table_column_header_new (ecol, item, accessible);
|
|
|
0489c0 |
+ if (child) {
|
|
|
0489c0 |
+ g_hash_table_insert (priv->a11y_column_headers, ecol, child);
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ g_object_weak_ref (G_OBJECT (ecol), eti_table_column_gone, accessible);
|
|
|
0489c0 |
+ g_object_weak_ref (G_OBJECT (child), eti_column_header_a11y_gone, accessible);
|
|
|
0489c0 |
+ }
|
|
|
0489c0 |
+ }
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ return child ? g_object_ref (child) : NULL;
|
|
|
0489c0 |
}
|
|
|
0489c0 |
index -= item->cols;
|
|
|
0489c0 |
|
|
|
0489c0 |
@@ -966,6 +1058,7 @@ eti_header_structure_changed (ETableHeader *eth,
|
|
|
0489c0 |
g_free (state);
|
|
|
0489c0 |
g_free (reorder);
|
|
|
0489c0 |
g_free (prev_state);
|
|
|
0489c0 |
+ free_columns (cols);
|
|
|
0489c0 |
return;
|
|
|
0489c0 |
}
|
|
|
0489c0 |
|
|
|
0489c0 |
@@ -1051,6 +1144,7 @@ eti_class_init (GalA11yETableItemClass *class)
|
|
|
0489c0 |
parent_class = g_type_class_ref (PARENT_TYPE);
|
|
|
0489c0 |
|
|
|
0489c0 |
object_class->dispose = eti_dispose;
|
|
|
0489c0 |
+ object_class->finalize = eti_finalize;
|
|
|
0489c0 |
|
|
|
0489c0 |
atk_object_class->get_n_children = eti_get_n_children;
|
|
|
0489c0 |
atk_object_class->ref_child = eti_ref_child;
|
|
|
0489c0 |
@@ -1069,6 +1163,7 @@ eti_init (GalA11yETableItem *a11y)
|
|
|
0489c0 |
priv->selection_row_changed_id = 0;
|
|
|
0489c0 |
priv->cursor_changed_id = 0;
|
|
|
0489c0 |
priv->selection = NULL;
|
|
|
0489c0 |
+ priv->a11y_column_headers = g_hash_table_new (g_direct_hash, g_direct_equal);
|
|
|
0489c0 |
}
|
|
|
0489c0 |
|
|
|
0489c0 |
/* atk selection */
|
|
|
0489c0 |
@@ -1189,14 +1284,17 @@ gal_a11y_e_table_item_new (ETableItem *item)
|
|
|
0489c0 |
|
|
|
0489c0 |
accessible = ATK_OBJECT (a11y);
|
|
|
0489c0 |
|
|
|
0489c0 |
- GET_PRIVATE (a11y)->item = item;
|
|
|
0489c0 |
/* Initialize cell data. */
|
|
|
0489c0 |
GET_PRIVATE (a11y)->cols = item->cols;
|
|
|
0489c0 |
GET_PRIVATE (a11y)->rows = item->rows >= 0 ? item->rows : 0;
|
|
|
0489c0 |
|
|
|
0489c0 |
GET_PRIVATE (a11y)->columns = e_table_header_get_columns (item->header);
|
|
|
0489c0 |
- if (GET_PRIVATE (a11y)->columns == NULL)
|
|
|
0489c0 |
+ if (GET_PRIVATE (a11y)->columns == NULL) {
|
|
|
0489c0 |
+ g_clear_object (&a11y);
|
|
|
0489c0 |
return NULL;
|
|
|
0489c0 |
+ }
|
|
|
0489c0 |
+
|
|
|
0489c0 |
+ GET_PRIVATE (a11y)->item = item;
|
|
|
0489c0 |
|
|
|
0489c0 |
g_signal_connect (
|
|
|
0489c0 |
item, "selection_model_removed",
|