1 /**
2  * Copyright 2011 JogAmp Community. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without modification, are
5  * permitted provided that the following conditions are met:
6  *
7  *    1. Redistributions of source code must retain the above copyright notice, this list of
8  *       conditions and the following disclaimer.
9  *
10  *    2. Redistributions in binary form must reproduce the above copyright notice, this list
11  *       of conditions and the following disclaimer in the documentation and/or other materials
12  *       provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
15  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
16  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
21  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
22  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  *
24  * The views and conclusions contained in the software and documentation are those of the
25  * authors and should not be interpreted as representing official policies, either expressed
26  * or implied, of JogAmp Community.
27  */
28 
29 package com.jogamp.opengl.test.junit.jogl.swt;
30 
31 import java.io.IOException;
32 import java.lang.reflect.InvocationTargetException;
33 
34 import com.jogamp.nativewindow.swt.SWTAccessor;
35 import com.jogamp.newt.NewtFactory;
36 import com.jogamp.newt.event.KeyAdapter;
37 import com.jogamp.newt.event.KeyEvent;
38 import com.jogamp.newt.event.WindowEvent;
39 import com.jogamp.newt.event.WindowAdapter;
40 import com.jogamp.newt.opengl.GLWindow;
41 import com.jogamp.newt.swt.NewtCanvasSWT;
42 import com.jogamp.opengl.test.junit.util.AWTRobotUtil;
43 import com.jogamp.opengl.test.junit.util.MiscUtils;
44 import com.jogamp.opengl.test.junit.util.UITestCase;
45 import com.jogamp.opengl.test.junit.util.QuitAdapter;
46 import com.jogamp.opengl.util.Animator;
47 import com.jogamp.opengl.util.AnimatorBase;
48 import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
49 
50 import com.jogamp.nativewindow.util.Dimension;
51 import com.jogamp.nativewindow.util.Point;
52 import com.jogamp.nativewindow.util.PointImmutable;
53 import com.jogamp.nativewindow.util.DimensionImmutable;
54 import com.jogamp.opengl.GLCapabilities;
55 import com.jogamp.opengl.GLCapabilitiesImmutable;
56 import com.jogamp.opengl.GLProfile;
57 
58 import org.eclipse.swt.SWT;
59 import org.eclipse.swt.custom.SashForm;
60 import org.eclipse.swt.layout.FillLayout;
61 import org.eclipse.swt.widgets.Composite;
62 import org.eclipse.swt.widgets.Display;
63 import org.eclipse.swt.widgets.Shell;
64 import org.junit.After;
65 import org.junit.Assert;
66 import org.junit.Assume;
67 import org.junit.Before;
68 import org.junit.BeforeClass;
69 import org.junit.AfterClass;
70 import org.junit.Test;
71 import org.junit.FixMethodOrder;
72 import org.junit.runners.MethodSorters;
73 
74 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
75 public class TestBug672NewtCanvasSWTSashFormComposite extends UITestCase {
76     static int screenIdx = 0;
77     static PointImmutable wpos;
78     static DimensionImmutable wsize, rwsize = null;
79 
80     static long duration = 500; // ms
81 
82     @BeforeClass
initClass()83     public static void initClass() {
84         if(null == wsize) {
85             wsize = new Dimension(640, 480);
86         }
87     }
88 
89     @AfterClass
releaseClass()90     public static void releaseClass() {
91     }
92 
93     Display display = null;
94     Shell shell = null;
95     Composite composite = null;
96     SashForm sash = null;
97     Composite innerComposite = null;
98     com.jogamp.newt.Display swtNewtDisplay = null;
99 
100     @Before
init()101     public void init() {
102         SWTAccessor.invoke(true, new Runnable() {
103             public void run() {
104                 display = new Display();
105                 Assert.assertNotNull( display );
106             }});
107         display.syncExec(new Runnable() {
108             public void run() {
109                 shell = new Shell( display );
110                 Assert.assertNotNull( shell );
111                 shell.setLayout( new FillLayout() );
112                 composite = new Composite( shell, SWT.NONE );
113                 composite.setLayout( new FillLayout() );
114                 Assert.assertNotNull( composite );
115                 sash = new SashForm(composite, SWT.NONE);
116                 Assert.assertNotNull( sash );
117                 final org.eclipse.swt.widgets.Label c = new org.eclipse.swt.widgets.Label(sash, SWT.NONE);
118                 c.setText("Left cell");
119                 innerComposite = new Composite(sash, SWT.NONE);
120                 Assert.assertNotNull( innerComposite );
121                 innerComposite.setLayout( new FillLayout() );
122             }});
123         swtNewtDisplay = NewtFactory.createDisplay(null, false); // no-reuse
124     }
125 
126     @After
release()127     public void release() {
128         Assert.assertNotNull( display );
129         Assert.assertNotNull( shell );
130         Assert.assertNotNull( composite );
131         Assert.assertNotNull( sash );
132         Assert.assertNotNull( innerComposite );
133         try {
134             display.syncExec(new Runnable() {
135                public void run() {
136                 innerComposite.dispose();
137                 sash.dispose();
138                 composite.dispose();
139                 shell.dispose();
140                }});
141             SWTAccessor.invoke(true, new Runnable() {
142                public void run() {
143                 display.dispose();
144                }});
145         }
146         catch( final Throwable throwable ) {
147             throwable.printStackTrace();
148             Assume.assumeNoException( throwable );
149         }
150         swtNewtDisplay = null;
151         display = null;
152         shell = null;
153         composite = null;
154         sash = null;
155         innerComposite = null;
156     }
157 
158     class WaitAction implements Runnable {
159         private final long sleepMS;
160 
WaitAction(final long sleepMS)161         WaitAction(final long sleepMS) {
162             this.sleepMS = sleepMS;
163         }
run()164         public void run() {
165             if( !display.readAndDispatch() ) {
166                 // blocks on linux .. display.sleep();
167                 try {
168                     Thread.sleep(sleepMS);
169                 } catch (final InterruptedException e) { }
170             }
171         }
172     }
173     final WaitAction awtRobotWaitAction = new WaitAction(AWTRobotUtil.TIME_SLICE);
174     final WaitAction generalWaitAction = new WaitAction(10);
175 
runTestGL(final GLCapabilitiesImmutable caps)176     protected void runTestGL(final GLCapabilitiesImmutable caps) throws InterruptedException, InvocationTargetException {
177         final com.jogamp.newt.Screen screen = NewtFactory.createScreen(swtNewtDisplay, screenIdx);
178         final GLWindow glWindow = GLWindow.create(screen, caps);
179         Assert.assertNotNull(glWindow);
180 
181         final GearsES2 demo = new GearsES2(1);
182         glWindow.addGLEventListener(demo);
183 
184         final Animator animator = new Animator();
185         animator.setModeBits(false, AnimatorBase.MODE_EXPECT_AWT_RENDERING_THREAD);
186 
187         final QuitAdapter quitAdapter = new QuitAdapter();
188         //glWindow.addKeyListener(new TraceKeyAdapter(quitAdapter));
189         //glWindow.addWindowListener(new TraceWindowAdapter(quitAdapter));
190         glWindow.addKeyListener(quitAdapter);
191         glWindow.addWindowListener(quitAdapter);
192 
193         glWindow.addWindowListener(new WindowAdapter() {
194             public void windowResized(final WindowEvent e) {
195                 System.err.println("window resized: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight());
196             }
197             public void windowMoved(final WindowEvent e) {
198                 System.err.println("window moved:   "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight());
199             }
200         });
201 
202         glWindow.addKeyListener(new KeyAdapter() {
203             public void keyReleased(final KeyEvent e) {
204                 if( !e.isPrintableKey() || e.isAutoRepeat() ) {
205                     return;
206                 }
207                 if(e.getKeyChar()=='f') {
208                     glWindow.invokeOnNewThread(null, false, new Runnable() {
209                         public void run() {
210                             final Thread t = glWindow.setExclusiveContextThread(null);
211                             System.err.println("[set fullscreen  pre]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets());
212                             glWindow.setFullscreen(!glWindow.isFullscreen());
213                             System.err.println("[set fullscreen post]: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", f "+glWindow.isFullscreen()+", a "+glWindow.isAlwaysOnTop()+", "+glWindow.getInsets());
214                             glWindow.setExclusiveContextThread(t);
215                     } } );
216                 }
217             }
218         });
219 
220         animator.add(glWindow);
221         animator.start();
222         Assert.assertTrue(animator.isStarted());
223         Assert.assertTrue(animator.isAnimating());
224         animator.setUpdateFPSFrames(60, null);
225         final NewtCanvasSWT canvas1 = NewtCanvasSWT.create( innerComposite, 0, glWindow );
226         Assert.assertNotNull( canvas1 );
227 
228         display.syncExec( new Runnable() {
229            public void run() {
230               shell.setText( getSimpleTestName(".") );
231               shell.setSize( wsize.getWidth(), wsize.getHeight() );
232               if( null != wpos ) {
233                   shell.setLocation( wpos.getX(), wpos.getY() );
234               }
235               shell.open();
236            }
237         });
238         Assert.assertTrue("GLWindow didn't become visible natively!", AWTRobotUtil.waitForRealized(glWindow, awtRobotWaitAction, true));
239         Assert.assertNotNull( canvas1.getNativeWindow() );
240 
241         System.err.println("NW chosen: "+glWindow.getDelegatedWindow().getChosenCapabilities());
242         System.err.println("GL chosen: "+glWindow.getChosenCapabilities());
243         System.err.println("window pos/siz.0: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", "+glWindow.getInsets());
244         System.err.println("GLWindow LOS.0: "+glWindow.getLocationOnScreen(null));
245         System.err.println("NewtCanvasSWT LOS.0: "+canvas1.getNativeWindow().getLocationOnScreen(null));
246 
247         if( null != rwsize ) {
248             for(int i=0; i<50; i++) { // 500 ms dispatched delay
249                 generalWaitAction.run();
250             }
251             display.syncExec( new Runnable() {
252                public void run() {
253                   shell.setSize( rwsize.getWidth(), rwsize.getHeight() );
254                }
255             });
256             System.err.println("window resize pos/siz.1: "+glWindow.getX()+"/"+glWindow.getY()+" "+glWindow.getSurfaceWidth()+"x"+glWindow.getSurfaceHeight()+", "+glWindow.getInsets());
257             System.err.println("GLWindow LOS.1: "+glWindow.getLocationOnScreen(null));
258             System.err.println("NewtCanvasSWT LOS.1: "+canvas1.getNativeWindow().getLocationOnScreen(null));
259         }
260 
261         final PointImmutable pSashRightClient = new Point(wsize.getWidth(), 0);
262         final PointImmutable pNatWinLOS = canvas1.getNativeWindow().getLocationOnScreen(null);
263         final PointImmutable pGLWinLOS = glWindow.getLocationOnScreen(null);
264 
265         System.err.println("GLWindow LOS: "+pGLWinLOS);
266         System.err.println("NewtCanvasSWT LOS: "+pNatWinLOS);
267 
268         Assert.assertTrue( "NewtCanvasAWT LOS "+pNatWinLOS+" not >= sash-right "+pSashRightClient, pNatWinLOS.compareTo(pSashRightClient) >= 0 );
269         Assert.assertTrue( "GLWindow LOS "+pGLWinLOS+" not >= sash-right "+pSashRightClient, pGLWinLOS.compareTo(pSashRightClient) >= 0 );
270 
271         while( !quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration()<duration ) {
272             generalWaitAction.run();
273         }
274 
275         animator.stop();
276         Assert.assertFalse(animator.isAnimating());
277         Assert.assertFalse(animator.isStarted());
278         Assert.assertEquals(null, glWindow.getExclusiveContextThread());
279 
280         canvas1.dispose();
281         glWindow.destroy();
282         Assert.assertEquals(true,  AWTRobotUtil.waitForRealized(glWindow, false));
283     }
284 
285     @Test
test01()286     public void test01() throws InterruptedException, InvocationTargetException {
287         final GLProfile glp = GLProfile.getGL2ES2();
288         final GLCapabilities caps = new GLCapabilities( glp );
289         runTestGL(caps);
290     }
291 
main(final String args[])292     public static void main(final String args[]) throws IOException {
293         int x=0, y=0, w=640, h=480, rw=-1, rh=-1;
294         boolean usePos = false;
295 
296         for(int i=0; i<args.length; i++) {
297             if(args[i].equals("-time")) {
298                 i++;
299                 duration = MiscUtils.atol(args[i], duration);
300             } else if(args[i].equals("-width")) {
301                 i++;
302                 w = MiscUtils.atoi(args[i], w);
303             } else if(args[i].equals("-height")) {
304                 i++;
305                 h = MiscUtils.atoi(args[i], h);
306             } else if(args[i].equals("-x")) {
307                 i++;
308                 x = MiscUtils.atoi(args[i], x);
309                 usePos = true;
310             } else if(args[i].equals("-y")) {
311                 i++;
312                 y = MiscUtils.atoi(args[i], y);
313                 usePos = true;
314             } else if(args[i].equals("-rwidth")) {
315                 i++;
316                 rw = MiscUtils.atoi(args[i], rw);
317             } else if(args[i].equals("-rheight")) {
318                 i++;
319                 rh = MiscUtils.atoi(args[i], rh);
320             } else if(args[i].equals("-screen")) {
321                 i++;
322                 screenIdx = MiscUtils.atoi(args[i], 0);
323             }
324         }
325         wsize = new Dimension(w, h);
326         if( 0 < rw && 0 < rh ) {
327             rwsize = new Dimension(rw, rh);
328         }
329 
330         if(usePos) {
331             wpos = new Point(x, y);
332         }
333         System.err.println("position "+wpos);
334         System.err.println("size "+wsize);
335         System.err.println("resize "+rwsize);
336         System.err.println("screen "+screenIdx);
337 
338         org.junit.runner.JUnitCore.main(TestBug672NewtCanvasSWTSashFormComposite.class.getName());
339     }
340 }
341