Commit 10d0e01
committed
[Gtk3] fix for SWTException on Table.remove(...) with focused row #1604
Fix for SWTException on Table.remove(...) with focused row.
This bug happens only in Gtk3.
The cause: `gtk_list_store_remove(...)` for a focused row invokes `Table.cellDataProc(...)` with not-yet-updated `Table.items`.
Fix: remove `TableItem` from `Table.items` before `gtk_list_store_remove(...)`.
Fixes #1604:
The exception only happens in Gtk3.
Java stacktrace:
```java
org.eclipse.swt.SWTException: Widget is disposed
at org.eclipse.swt.SWT.error(SWT.java:4922)
at org.eclipse.swt.SWT.error(SWT.java:4837)
at org.eclipse.swt.SWT.error(SWT.java:4808)
at org.eclipse.swt.widgets.Widget.error(Widget.java:597)
at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:512)
at org.eclipse.swt.widgets.TableItem.setText(TableItem.java:1363)
at org.eclipse.swt.tests.gtk.Test_Gtk3_Table_Remove_Focused_Row.lambda$3(Test_Gtk3_Table_Remove_Focused_Row.java:68)
at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:91)
at org.eclipse.swt.widgets.Display.sendEvent(Display.java:5857)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1617)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1643)
at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1626)
at org.eclipse.swt.widgets.Table.checkData(Table.java:289)
at org.eclipse.swt.widgets.Table.cellDataProc(Table.java:227)
at org.eclipse.swt.widgets.Display.cellDataProc(Display.java:995)
at org.eclipse.swt.internal.gtk.GTK.gtk_list_store_remove(Native Method)
at org.eclipse.swt.widgets.Table.remove(Table.java:2668)
...
```
The main cause of the error is that:
1. when a row with focus is deleted with `gtk_list_store_remove(...)`, then cell data function `Table.cellDataProc(...)` is called for a row after the removed one
2. but inside `Table.cellDataProc(...)` `Table.items` isn't yet updated , therefore `Table.cellDataProc(...)` operates with `TableItem`, which is already disposed but not yet removed from `Table.items`
Inside `gtk_list_store_remove(...)` the row is removed from the `GtkTreeModel`, and only then `GtkTreeView` callbacks are invoked.
It means that when `Table.cellDataProc(...)` is invoked, the row has already been removed in Gtk3.
The fix: remove `TableItem` from `Table.items` before `gtk_list_store_remove(...)` instead of after.
Important: I haven't tried to reproduce this bug in GTK4.
Os: Ubuntu 24.04.1 LTS
Gtk: 3.24.41
Swt: 4.967.8
=================================================
Why `gtk_list_store_remove(...)` invokes `Table.cellDataProc(...)` only for a row with focus and not for ordinary rows?
The reason is that in gtk3 when a row with focus is deleted, the next row receives focus, which among other things creates `GtkCellAccessible` (a "cell with focus" for assistive technology in gtk3).
Creation of `GtkCellAccessible` invokes cell data function `Table.cellDataProc(...)` - just like it happens when a standard cell in `GtkTreeView` gets rendered.
Here is the stacktrace in gtk3 code:
```c
apply_cell_attributes() at gtkcellarea.c:1257
g_hash_table_foreach() at ghash.c:2117
gtk_cell_area_real_apply_attributes() at gtkcellarea.c:1286
gtk_cell_area_box_apply_attributes() at gtkcellareabox.c:1310
_gtk_marshal_VOID__OBJECT_BOXED_BOOLEAN_BOOLEANv() at gtkmarshalers.c:5447
g_type_class_meta_marshalv() at gclosure.c:1062
_g_closure_invoke_va() at gclosure.c:897
signal_emit_valist_unlocked() at gsignal.c:3424
g_signal_emit_valist() at gsignal.c:3263
g_signal_emit() at gsignal.c:3583
gtk_cell_area_apply_attributes() at gtkcellarea.c:2373
gtk_tree_view_column_cell_set_cell_data() at gtktreeviewcolumn.c:2821
set_cell_data() at gtktreeviewaccessible.c:347
create_cell() at gtktreeviewaccessible.c:439
_gtk_tree_view_accessible_add_state() at gtktreeviewaccessible.c:2053
gtk_tree_view_real_set_cursor() at gtktreeview.c:13377
gtk_tree_view_row_deleted() at gtktreeview.c:9430
g_cclosure_marshal_VOID__BOXED() at gmarshal.c:1628
g_closure_invoke() at gclosure.c:834
signal_emit_unlocked_R() at gsignal.c:3888
signal_emit_valist_unlocked() at gsignal.c:3520
g_signal_emit_valist() at gsignal.c:3263
g_signal_emit() at gsignal.c:3583
gtk_tree_model_row_deleted() at gtktreemodel.c:1914
gtk_list_store_remove() at gtkliststore.c:1219
Java_org_eclipse_swt_internal_gtk_GTK_gtk_1list_1store_1remove()
```
The code that leads to execution of cell data function for a row with focus is in gtktreeview.c:
```
static void
gtk_tree_view_row_deleted (GtkTreeModel *model,
GtkTreePath *path,
gpointer data)
{
...
/* If the cursor row got deleted, move the cursor to the next row */
if (tree_view->priv->cursor_node &&
(tree_view->priv->cursor_node == node ||
(node->children && (tree_view->priv->cursor_tree == node->children ||
_gtk_rbtree_contains (node->children, tree_view->priv->cursor_tree)))))
{
...
cursor_changed = TRUE;
}
...
if (cursor_changed)
{
if (cursor_node)
{
...
gtk_tree_view_real_set_cursor (tree_view, cursor_path, CLEAR_AND_SELECT | CURSOR_INVALID);
...
}
...
}
...
}
```1 parent e6588c2 commit 10d0e01
File tree
2 files changed
+99
-8
lines changed- bundles/org.eclipse.swt/Eclipse SWT/gtk/org/eclipse/swt/widgets
- tests/org.eclipse.swt.tests.gtk/JUnit Tests/org/eclipse/swt/tests/gtk
2 files changed
+99
-8
lines changedLines changed: 6 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2663 | 2663 | | |
2664 | 2664 | | |
2665 | 2665 | | |
| 2666 | + | |
| 2667 | + | |
2666 | 2668 | | |
2667 | 2669 | | |
2668 | 2670 | | |
2669 | 2671 | | |
2670 | | - | |
2671 | | - | |
2672 | 2672 | | |
2673 | 2673 | | |
2674 | 2674 | | |
| |||
2708 | 2708 | | |
2709 | 2709 | | |
2710 | 2710 | | |
| 2711 | + | |
| 2712 | + | |
2711 | 2713 | | |
2712 | 2714 | | |
2713 | 2715 | | |
2714 | 2716 | | |
2715 | 2717 | | |
2716 | | - | |
2717 | | - | |
2718 | | - | |
2719 | | - | |
2720 | 2718 | | |
2721 | 2719 | | |
2722 | 2720 | | |
| |||
2764 | 2762 | | |
2765 | 2763 | | |
2766 | 2764 | | |
| 2765 | + | |
| 2766 | + | |
2767 | 2767 | | |
2768 | 2768 | | |
2769 | 2769 | | |
2770 | | - | |
2771 | | - | |
2772 | 2770 | | |
2773 | 2771 | | |
2774 | 2772 | | |
| |||
Lines changed: 93 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
0 commit comments