[evolution-patches] [gal]#52935, evo-1.5 sometime crashes when click on the message list
- From: Eric Zhao <eric zhao sun com>
- To: Jeffrey Stedfast <fejj ximian com>, Mike Kestne <mkestner ximian com>, York <yuedong du sun com>, Not Zed <notzed ximian com>, evo-patch <evolution-patches lists ximian com>
- Subject: [evolution-patches] [gal]#52935, evo-1.5 sometime crashes when click on the message list
- Date: Sun, 11 Apr 2004 16:53:30 +0800
Hi,
Attached is a patch which fixed bug #52935. This is a very critical
bug, which caused a lot of crash when having accessibility enabled.
This bug can be reproduced by the following steps:
1. start evolution with a11y enabled
2. goto a mail folder with few messages
3. click on the message.
4. switch to another folder which contains a lot of messages, click to
the message list several times, then evolution will goto crash at most
times.
The bug is caused by the following reason:
the cell_data pointer (used to the retrieve the AtkObject of table
cell) is initialize the first folder is accessed, when switched to
another folder, the cell_data pointer keeps the original value ( The
cell_data pointer's value should change, but it didn't. )
Then if we access a message out of the first folder's range(in another
folder), the AtkObject which we get via cell_data pointer is invalid,
and a SIGSEGV signal is raised.
Since we can't figure out which messages have been changed when the
message-list is changed(when deleting a message, inserting a new message,
switching mail folder, etc.), so we have to clear all the AtkObjects stored
in the cell_data, and reinit it the next time we access it. As the clearing
operation will cause a noticeable latency when the current-folder contains
a lot of mails, this is not a very good solution, but it can just work.
--
Regards,
Eric
Index: gal-a11y-e-table-item.c
===================================================================
RCS file: /cvs/gnome/gal/gal/a11y/e-table/gal-a11y-e-table-item.c,v
retrieving revision 1.9
diff -u -r1.9 gal-a11y-e-table-item.c
--- gal-a11y-e-table-item.c 2 Dec 2003 08:25:17 -0000 1.9
+++ gal-a11y-e-table-item.c 11 Apr 2004 08:32:21 -0000
@@ -13,6 +13,8 @@
#include "gal-a11y-e-cell.h"
#include "gal-a11y-util.h"
#include <gal/e-table/e-table-subset.h>
+#include <gal/e-table/e-table.h>
+#include <gal/e-table/e-tree.h>
#include <atk/atkobject.h>
#include <atk/atktable.h>
@@ -40,6 +42,7 @@
int cursor_change_id;
ETableCol ** columns;
ESelectionModel *selection;
+ GtkWidget *widget;
};
static gboolean gal_a11y_e_table_item_ref_selection (GalA11yETableItem *a11y,
@@ -294,7 +297,9 @@
ETableCol *ecol = e_table_header_get_column (item->header, column);
gpointer * cell_data;
- cell_data = GET_PRIVATE (table)->cell_data;
+ cell_data = eti_reinit_data (table, item);
+ if (cell_data == NULL)
+ return NULL;
if (cell_data[row*item->cols + column] == NULL) {
ret = gal_a11y_e_cell_registry_get_object (NULL,
@@ -309,7 +314,6 @@
g_object_weak_ref (G_OBJECT (ret),
(GWeakNotify) cell_destroyed,
ret);
-
else
ret = NULL;
} else {
@@ -675,6 +679,79 @@
g_signal_emit_by_name (table_item, "visible-data-changed");
}
+/*
+ * reinit the eti's private data
+ * make sure it is synchronized with the gal-e-table-item
+ */
+static gpointer *
+eti_reinit_data (AtkTable *table, ETableItem *item)
+{
+ gpointer * cell_data;
+
+ int oldsize, newsize;
+ cell_data = GET_PRIVATE (table)->cell_data;
+ if (GET_PRIVATE (table)->rows != item->rows
+ || GET_PRIVATE (table)->cols != item->cols ) { /* reinit cell_data */
+ oldsize = GET_PRIVATE (table)->cols * GET_PRIVATE (table)->rows;
+ newsize = item->cols*item->rows;
+ GET_PRIVATE (table)->cols = item->cols;
+ GET_PRIVATE (table)->rows = item->rows;
+
+ cell_data = g_realloc(cell_data, newsize*sizeof(gpointer));
+ if (newsize > oldsize)
+ memset(&cell_data[oldsize], 0, (newsize-oldsize)*sizeof(gpointer));
+
+ GET_PRIVATE (table)->cell_data = cell_data;
+ }
+ return cell_data;
+}
+
+/*
+ * clear all the AtkObjects stored in the cell_data
+ * doesn't free the cell_data or resize it.
+ */
+static void
+eti_clear_rows (ETableModel * model, AtkObject * table_item, int row, int count)
+{
+ gint i,j, n_rows, n_cols;
+ gpointer *cell_data;
+
+ g_return_if_fail (model && table_item);
+
+ cell_data = GET_PRIVATE (table_item)->cell_data;
+ g_return_if_fail (cell_data);
+
+ n_rows = GET_PRIVATE (table_item)->rows;
+ n_cols = GET_PRIVATE (table_item)->cols;
+
+ g_return_if_fail( row >= 0 && count > 0 && row+count <= n_rows);
+
+ /* DEFUNCT the deleted cells. */
+ for (i = row; i < row+count; i ++) {
+ for (j = 0; j < n_cols; j ++) {
+ if (cell_data[i*n_cols + j] != NULL) {
+ AtkObject * a11y;
+
+ a11y = ATK_OBJECT(cell_data[i*n_cols + j]);
+ gal_a11y_e_cell_add_state (GAL_A11Y_E_CELL(a11y), ATK_STATE_DEFUNCT, TRUE);
+ cell_data[i*n_cols + j] = NULL;
+ }
+ }
+ }
+
+ g_signal_emit_by_name (table_item, "row-deleted", row,
+ count, NULL);
+
+ for (i = row; i < row+count; i ++) {
+ for (j = 0; j < n_cols; j ++) {
+ g_signal_emit_by_name (table_item,
+ "children_changed::remove",
+ ( (i*n_cols) + j), NULL, NULL);
+ }
+ }
+ g_signal_emit_by_name (table_item, "visible-data-changed");
+}
+
static void
eti_rows_deleted (ETableModel * model, int row, int count,
AtkObject * table_item)
@@ -742,6 +819,22 @@
g_signal_emit_by_name (table_item, "visible-data-changed");
}
+static void
+eti_tree_model_node_changed_cb (ETreeModel *model, ETreePath node, ETableItem *eti)
+{
+ AtkObject *atk_obj;
+ GalA11yETableItem *a11y;
+
+ g_return_if_fail (E_IS_TABLE_ITEM (eti));
+
+ atk_obj = atk_gobject_accessible_for_object (G_OBJECT (eti));
+ a11y = GAL_A11Y_E_TABLE_ITEM (atk_obj);
+
+ /* we can't figure out which rows are changed, so just clear all of them ... */
+ if (GET_PRIVATE (a11y)->rows > 0)
+ eti_clear_rows (eti->table_model, atk_obj, 0, GET_PRIVATE (a11y)->rows);
+}
+
enum {
ETI_HEADER_UNCHANGED = 0,
ETI_HEADER_REORDERED,
@@ -1035,8 +1128,10 @@
int index_in_parent)
{
GalA11yETableItem *a11y;
+ AtkObject *accessible;
int n;
+ g_return_val_if_fail (item && item->cols >= 0 && item->rows >= 0, NULL);
a11y = g_object_new (gal_a11y_e_table_item_get_type (), NULL);
atk_object_initialize (ATK_OBJECT (a11y), item);
@@ -1044,7 +1139,8 @@
GET_PRIVATE (a11y)->parent = parent;
GET_PRIVATE (a11y)->index_in_parent = index_in_parent;
- g_return_val_if_fail (item->cols >= 0 && item->rows >= 0, NULL);
+ accessible = ATK_OBJECT(a11y);
+ accessible->role = ATK_ROLE_TREE_TABLE;
/* Initialize cell data. */
n = item->cols * item->rows;
GET_PRIVATE (a11y)->cols = item->cols;
@@ -1070,6 +1166,15 @@
if (item->selection)
gal_a11y_e_table_item_ref_selection (a11y,
item->selection);
+
+ /* find the TableItem's parent: table or tree */
+ GET_PRIVATE (a11y)->widget = gtk_widget_get_parent (GTK_WIDGET (item->parent.canvas));
+ if (E_IS_TREE (GET_PRIVATE (a11y)->widget)) {
+ ETreeModel *model;
+ model = e_tree_get_model (E_TREE (GET_PRIVATE (a11y)->widget));
+ g_signal_connect (G_OBJECT(model), "node_changed",
+ G_CALLBACK (eti_tree_model_node_changed_cb), item);
+ }
}
if (parent)
g_object_ref (parent);
@@ -1186,11 +1291,13 @@
g_signal_emit_by_name (a11y, "selection_changed");
- cell = atk_table_ref_at (ATK_TABLE (a11y), row, col);
- if (ATK_IS_OBJECT (cell))
- g_signal_emit_by_name (a11y,
- "active-descendant-changed",
- cell);
+ cell = atk_table_ref_at (ATK_TABLE (a11y), row, col);
+ if (cell != NULL) {
+ if (ATK_IS_OBJECT (cell)) {
+ gal_a11y_e_cell_add_state(cell, ATK_STATE_FOCUSED, FALSE);
+ atk_focus_tracker_notify (cell);
+ }
+ }
}
/* atk selection */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]