Community
Participate
Working Groups
On SWT 3212, the dispose state flag is not getting set soon enough for TableItem while the Table is virtual. TableItem.destroyWidget() calls Table.destroyItem() before TableItem.releaseHandle(), which sends an OS message to delete the item. In some cases, the OS will call Table back immediately, requesting view data for a new table row. SetData will be triggered, and that almost-removed TableItem will still return that it's not disposed. Calling a method on it will result in an error, since parts of the object have indeed been destoyed. Here's a snippet which shows the problem: public static void main(String[] args) { System.out.println("SWT Version: " + SWT.getVersion()); Display display = new Display(); final Shell shell = new Shell(display); shell.setLayout(new FillLayout()); final Table table = new Table(shell, SWT.BORDER | SWT.VIRTUAL); table.addListener(SWT.SetData, new Listener() { public void handleEvent(Event event) { try { final TableItem item = (TableItem) event.item; System.err.println("SetData for row " + table.indexOf(item)); item.setText("Row"); TableItem firstItem = table.getItem(0); if (!firstItem.isDisposed()) { System.err.println("Row #0 says it's not disposed"); firstItem.setData("Key4", "4"); } } catch (Exception e) { e.printStackTrace(); } } }); for (int i = 0; i < 2; i++) { TableItem tableItem = new TableItem(table, SWT.NONE); tableItem.setData("Key1", "1"); } shell.setSize(400, shell.getMinimumSize().y + table.getItemHeight()); shell.open(); TableItem item = table.getItem(0); System.err.println("About to Dispose Row 0.."); item.dispose(); while (!shell.isDisposed()) { if (!display.readAndDispatch()) display.sleep(); } display.dispose(); } The output of this snippet is: SWT Version: 3212 SetData for row 0 Row #0 says it's not disposed About to Dispose Row 0.. SetData for row 1 Row #0 says it's not disposed java.lang.NullPointerException at org.eclipse.swt.widgets.Widget.setData(Widget.java:1023) at Test$1.handleEvent(Test.java:43) at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66) at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:896) at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:920) at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:905) at org.eclipse.swt.widgets.Table.checkData(Table.java:341) at org.eclipse.swt.widgets.Table.wmNotifyChild(Table.java:4165) at org.eclipse.swt.widgets.Control.WM_NOTIFY(Control.java:3689) at org.eclipse.swt.widgets.Composite.WM_NOTIFY(Composite.java:1090) at org.eclipse.swt.widgets.Control.windowProc(Control.java:3194) at org.eclipse.swt.widgets.Decorations.windowProc(Decorations.java:1538) at org.eclipse.swt.widgets.Display.windowProc(Display.java:3908) at org.eclipse.swt.internal.win32.OS.CallWindowProcW(Native Method) at org.eclipse.swt.internal.win32.OS.CallWindowProc(OS.java:1627) at org.eclipse.swt.widgets.Table.callWindowProc(Table.java:256) at org.eclipse.swt.widgets.Table.callWindowProc(Table.java:180) at org.eclipse.swt.widgets.Control.windowProc(Control.java:3229) at org.eclipse.swt.widgets.Table.windowProc(Table.java:3633) at org.eclipse.swt.widgets.Display.windowProc(Display.java:3908) at org.eclipse.swt.internal.win32.OS.SendMessageW(Native Method) at org.eclipse.swt.internal.win32.OS.SendMessage(OS.java:2285) at org.eclipse.swt.widgets.Table.destroyItem(Table.java:1314) at org.eclipse.swt.widgets.TableItem.destroyWidget(TableItem.java:137) at org.eclipse.swt.widgets.Widget.release(Widget.java:730) at org.eclipse.swt.widgets.Widget.dispose(Widget.java:400) at Test.main(Test.java:62)
The problem is that the item cannot be marked as disposed until "item.dispose()" returns. However, during the dispose, the table is asked to redraw, the virtual callback is triggered and the application code asks for the item ("table.getItem(0)" inside SWT.SetData and gets the item that is in the process of being disposed. Reordering the code in TableItem.destroyWidget() to save away the fields that are needed to dispose the widget in the operating system (in this case the parent), fixes the problem: void destroyWidget () { Table parent = this.parent; releaseHandle (); parent.destroyItem (this); }
Need to investigate this pattern for every Item subclass on every platform. For example, saving away the parent won't work on GTK because "item.handle" is needed in Table.destroyItem().
Fixed > 20060106