Community
Participate
Working Groups
BuildId: I20100525 I have a part in a stack that contributes an MToolControl. Switching to this part causes an SWTException (trace below) as the part's toolbar widget has been disposed. The code in question: ToolBar tb; MToolBar tbModel = part.getToolbar(); if (tbModel != null) { if (tbModel.getWidget() != null) { ToolBar oldTB = (ToolBar) tbModel.getWidget(); if (oldTB.getParent() instanceof CTabFolder) { // <--- line 523: oldTB is disposed CTabFolder oldCTF = (CTabFolder) oldTB.getParent(); if (oldCTF.getTopRight() == oldTB) oldCTF.setTopRight(null); } oldTB.setParent(ctf); return oldTB; } tb = (ToolBar) renderer.createGui(tbModel, ctf); } else { tb = new ToolBar(ctf, SWT.FLAT | SWT.HORIZONTAL); } The toolbar instance is disposed of in StackRenderer.showTab() when switching tabs. The code above should be checking that the toolbar is not null and that it's not disposed. It also turns out that PartRenderingEngine#createGui() needs similar code. I'm a bit puzzled why this only seems to happen with this particular part. org.eclipse.swt.SWTException: Widget is disposed at org.eclipse.swt.SWT.error(SWT.java:4083) at org.eclipse.swt.SWT.error(SWT.java:3998) at org.eclipse.swt.SWT.error(SWT.java:3969) at org.eclipse.swt.widgets.Widget.error(Widget.java:715) at org.eclipse.swt.widgets.Widget.checkWidget(Widget.java:531) at org.eclipse.swt.widgets.Control.getParent(Control.java:1615) at org.eclipse.e4.workbench.ui.renderers.swt.StackRenderer.getToolbar(StackRenderer.java:523) at org.eclipse.e4.workbench.ui.renderers.swt.StackRenderer.showTab(StackRenderer.java:479) at org.eclipse.e4.workbench.ui.renderers.swt.LazyStackRenderer$1.handleEvent(LazyStackRenderer.java:68) at org.eclipse.e4.ui.services.internal.events.UIEventHandler.handleEvent(UIEventHandler.java:41) at org.eclipse.equinox.internal.event.EventHandlerWrapper.handleEvent(EventHandlerWrapper.java:188) at org.eclipse.equinox.internal.event.EventHandlerTracker.dispatchEvent(EventHandlerTracker.java:198) at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEvent(EventManager.java:227) at org.eclipse.osgi.framework.eventmgr.ListenerQueue.dispatchEventSynchronous(ListenerQueue.java:149) at org.eclipse.equinox.internal.event.EventAdminImpl.dispatchEvent(EventAdminImpl.java:139) at org.eclipse.equinox.internal.event.EventAdminImpl.sendEvent(EventAdminImpl.java:78) at org.eclipse.equinox.internal.event.EventComponent.sendEvent(EventComponent.java:39) at org.eclipse.e4.ui.services.internal.events.EventBroker.send(EventBroker.java:73) at org.eclipse.e4.workbench.ui.internal.UIEventPublisher.notifyChanged(UIEventPublisher.java:58) at org.eclipse.emf.common.notify.impl.BasicNotifierImpl.eNotify(BasicNotifierImpl.java:380) at org.eclipse.e4.ui.model.application.ui.impl.ElementContainerImpl.setSelectedElement(ElementContainerImpl.java:165) at org.eclipse.e4.workbench.ui.renderers.swt.StackRenderer$3.widgetSelected(StackRenderer.java:410) at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:234)
Created attachment 170859 [details] Workaround This patch works around the immediate problem, but I doubt it's the right approach as I thought disposed items should have been removed from the model.
Thanks Brian, before I apply this one I'm going to take another stab at why unrendering/removing/re-opening a perspective is giving us headaches. It may well be that there's an underlying issue that, once resolved, will fix this. If a widget is disposed it's model element is supposed to 'unbind' (which should be setting 'widget' to null), meaning that if 'getWidget()' is non-null it should not be disposed (so the check should be unnecessary)...
I dug into this a bit this morning and found the problem: the MToolControl is being bound to the *ToolBar* and not the *tool control*. You can see this by putting a breakpoint in SWTPartRenderer#bindWidget(MUIElement, Object) conditioned on "widget instanceof org.eclipse.swt.widgets.ToolBar && !(me instanceof org.eclipse.e4.ui.model.application.ui.menu.MToolBar)" The problem is that ToolControlRenderer#createWidget() is returning the *parentWidget*! Daemon Thread [Thread-0] (Suspended (entry into method bindWidget in SWTPartRenderer)) ToolControlRenderer(SWTPartRenderer).bindWidget(MUIElement, Object) line: 85 PartRenderingEngine.createWidget(MUIElement, Object) line: 438 PartRenderingEngine.createGui(MUIElement, Object) line: 330 PartRenderingEngine.createGui(MUIElement) line: 388 ToolBarRenderer(SWTPartRenderer).processContents(MElementContainer<MUIElement>) line: 57 PartRenderingEngine.createGui(MUIElement, Object) line: 342 StackRenderer.getToolbar(MUIElement) line: 531 StackRenderer.showTab(MUIElement) line: 479
Created attachment 170933 [details] Cause ToolControlRenderer to return the tool control widget The fix is so trivial I committed it. Fixed in >20100603.
Fix committed.
Thanks Brian, I thought something like that might be the case (better that than having the while engine spewing disposed widgets...;-).