Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 393771

Summary: SWT Exception when accessing the gc within a paint listener
Product: [RT] RAP Reporter: Holger Staudacher <holger.staudacher>
Component: RWTAssignee: Project Inbox <rap-inbox>
Status: RESOLVED FIXED QA Contact:
Severity: critical    
Priority: P3 CC: rsternberg
Version: 2.0   
Target Milestone: 2.0 M3   
Hardware: PC   
OS: Mac OS X   
Whiteboard:
Attachments:
Description Flags
Testcase to reproduce none

Description Holger Staudacher CLA 2012-11-07 10:10:25 EST
Today I updated Tabris to RAP master and noticed that there are test error. I think they might have todo with the type system.

I will attach a TestCase to reproduce the problem. For me the following StackTrace occured:

org.eclipse.swt.SWTException: Graphic is disposed
	at org.eclipse.swt.SWT.error(SWT.java:3546)
	at org.eclipse.swt.SWT.error(SWT.java:3469)
	at org.eclipse.swt.SWT.error(SWT.java:3440)
	at org.eclipse.swt.graphics.GC.checkDisposed(GC.java:1479)
	at org.eclipse.swt.graphics.GC.getLineWidth(GC.java:435)
	at com.eclipsesource.tabris.widgets.GCTest$1.paintControl(GCTest.java:46)
	at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:216)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:88)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:682)
	at org.eclipse.swt.widgets.Widget.notifyListeners(Widget.java:584)
	at org.eclipse.swt.widgets.Display.executeNextEvent(Display.java:1142)
	at org.eclipse.swt.widgets.Display.runPendingMessages(Display.java:1123)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:1113)
	at org.eclipse.rap.rwt.testfixture.Fixture.executeLifeCycleFromServerThread(Fixture.java:467)
	at com.eclipsesource.tabris.widgets.GCTest.testGCDisposed(GCTest.java:51)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31)
	at org.junit.runners.BlockJUnit4ClassRunner.runNotIgnored(BlockJUnit4ClassRunner.java:79)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:71)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:49)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Comment 1 Holger Staudacher CLA 2012-11-07 10:10:57 EST
Created attachment 223304 [details]
Testcase to reproduce
Comment 2 Ivan Furnadjiev CLA 2012-11-07 11:11:36 EST
The test is not so correct. In the Canvas ctor there is a repaint() call that trigger the SWT.Paint event. Normally, widget creation is done into a PROCESS_ACTION phase. Thus, the SWT.Paint event is executed immediately. In the test case the phase is not specified and the event is put into the queue. When it's time to execute it (by executeLifeCycleFromServerThread()) the GC is already disposed (see Canvas#repaint()). The correct test case should have Fixture.fakePhase( PhaseId.PROCESS_ACTION ); in the beginning.
Comment 3 Holger Staudacher CLA 2012-11-07 11:19:19 EST
Thanks Ivan for the explanation. But why did it worked with RAP 2.0 M1 and earlier?
Comment 4 Ralf Sternberg CLA 2012-11-07 11:44:29 EST
Fixed with commit 30168c469b7713ee8b31d277e31a932ba0ec98dc.

The Canvas constructor unnecessarily called repaint(). This call was useless, because during initialization, gcAdapter is null and there aren't any listeners attached yet. But calling this method created an event that was later being executed in ProcessAction. Before the event system rewrite, this has probably been prevented by EventUtil.isAccessible().
Comment 5 Ivan Furnadjiev CLA 2012-11-07 11:50:27 EST
Recently, we reworked the event system in RAP (see bug 334028). Before, there was a null check for the phase in the TypedEvent#processEvent(). After the event system rework this code is completely gone as this should never happen in the real world.
Comment 6 Ralf Sternberg CLA 2012-11-08 03:51:37 EST
(In reply to comment #5)
> Recently, we reworked the event system in RAP (see bug 334028). Before,
> there was a null check for the phase in the TypedEvent#processEvent(). After
> the event system rework this code is completely gone as this should never
> happen in the real world.

Ah, that explains it. Completely agree that the error could only occur in a test. However, the test case looks valid to me and the exception should not happen.