Jogamp
NativeWindow X11: Lock/Unlock Display if using it
[jogl.git] / src / newt / classes / com / sun / javafx / newt / opengl / GLWindow.java
CommitLineData
a959c53b
KR
1/*
2 * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * - Redistribution of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * - Redistribution in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of Sun Microsystems, Inc. or the names of
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * This software is provided "AS IS," without a warranty of any kind. ALL
20 * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
23 * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
24 * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
25 * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
26 * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
27 * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
28 * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY,
29 * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF
30 * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 *
32 */
33
34package com.sun.javafx.newt.opengl;
35
36import com.sun.javafx.newt.*;
37import javax.media.nativewindow.*;
38import javax.media.opengl.*;
39import com.sun.opengl.impl.GLDrawableHelper;
a92906bc 40import java.util.*;
a959c53b
KR
41
42/**
43 * An implementation of {@link Window} which is customized for OpenGL
2268a6ce
SG
44 * use, and which implements the {@link javax.media.opengl.GLAutoDrawable} interface.
45 * <P>
46 * This implementation does not make the OpenGL context current<br>
47 * before calling the various input EventListener callbacks (MouseListener, KeyListener,
48 * etc.).<br>
49 * This design decision is made to favor a more performant and simplified
50 * implementation, as well as the event dispatcher shall be allowed
51 * not having a notion about OpenGL.
52 * <p>
a959c53b
KR
53 */
54public class GLWindow extends Window implements GLAutoDrawable {
a92906bc
SG
55 private static List/*GLWindow*/ glwindows = new ArrayList();
56
2268a6ce 57 private boolean ownerOfDisplayAndScreen;
a959c53b 58 private Window window;
2268a6ce 59 private boolean runPumpMessages;
a959c53b
KR
60
61 /** Constructor. Do not call this directly -- use {@link
62 create()} instead. */
63 protected GLWindow(Window window, boolean ownerOfDisplayAndScreen) {
64 this.ownerOfDisplayAndScreen = ownerOfDisplayAndScreen;
65 this.window = window;
66 this.window.setAutoDrawableClient(true);
2268a6ce 67 this.runPumpMessages = ( null == getScreen().getDisplay().getEDT() ) ;
a959c53b
KR
68 window.addWindowListener(new WindowListener() {
69 public void windowResized(WindowEvent e) {
70 sendReshape = true;
71 }
72
73 public void windowMoved(WindowEvent e) {
74 }
75
76 public void windowGainedFocus(WindowEvent e) {
77 }
78
79 public void windowLostFocus(WindowEvent e) {
80 }
81
82 public void windowDestroyNotify(WindowEvent e) {
83 sendDestroy = true;
84 }
85 });
a92906bc
SG
86
87 List newglw = (List) ((ArrayList) glwindows).clone();
88 newglw.add(this);
89 glwindows=newglw;
a959c53b
KR
90 }
91
92 /** Creates a new GLWindow on the local display, screen 0, with a
93 dummy visual ID, and with the default GLCapabilities. */
94 public static GLWindow create() {
95 return create(null, null, false);
96 }
97
98 public static GLWindow create(boolean undecorated) {
99 return create(null, null, undecorated);
100 }
101
102 /** Creates a new GLWindow referring to the given window. */
103 public static GLWindow create(Window window) {
104 return create(window, null, false);
105 }
106 public static GLWindow create(GLCapabilities caps) {
107 return create(null, caps, false);
108 }
109
110 /** Creates a new GLWindow on the local display, screen 0, with a
111 dummy visual ID, and with the given GLCapabilities. */
112 public static GLWindow create(GLCapabilities caps, boolean undecorated) {
113 return create(null, caps, undecorated);
114 }
115
3cc7335e
SG
116 /** Either or: window (prio), or caps and undecorated (2nd choice) */
117 private static GLWindow create(Window window,
118 GLCapabilities caps,
119 boolean undecorated) {
a92906bc 120 Display display;
a959c53b
KR
121 boolean ownerOfDisplayAndScreen=false;
122 if (window == null) {
3cc7335e
SG
123 if (caps == null) {
124 caps = new GLCapabilities(null); // default ..
125 }
a959c53b 126 ownerOfDisplayAndScreen = true;
a92906bc 127 display = NewtFactory.createDisplay(null); // local display
a959c53b
KR
128 Screen screen = NewtFactory.createScreen(display, 0); // screen 0
129 window = NewtFactory.createWindow(screen, caps, undecorated);
130 }
131
132 return new GLWindow(window, ownerOfDisplayAndScreen);
133 }
134
a92906bc
SG
135 /**
136 * EXPERIMENTAL<br>
137 * Enable or disables running the {@link Display#pumpMessages} in the {@link #display()} call.<br>
138 * The default behavior is to run {@link Display#pumpMessages}.<P>
139 *
140 * The idea was that in a single threaded environment with one {@link Display} and many {@link Window}'s,
141 * a performance benefit was expected while disabling the implicit {@link Display#pumpMessages} and
142 * do it once via {@link GLWindow#runCurrentThreadPumpMessage()} <br>
143 * This could not have been verified. No measurable difference could have been recognized.<P>
144 *
145 * Best performance has been achieved with one GLWindow per thread.<br>
146 *
2268a6ce
SG
147 * Enabling local pump messages while using the EDT,
148 * {@link com.sun.javafx.newt.NewtFactory#setUseEDT(boolean)},
149 * will result in an exception.
150 *
a92906bc
SG
151 * @deprecated EXPERIMENTAL, semantic is about to be removed after further verification.
152 */
153 public void setRunPumpMessages(boolean onoff) {
2268a6ce
SG
154 if( onoff && null!=getScreen().getDisplay().getEDT() ) {
155 throw new GLException("GLWindow.setRunPumpMessages(true) - Can't do with EDT on");
156 }
a92906bc
SG
157 runPumpMessages = onoff;
158 }
159
3cc7335e 160 protected void createNative(long parentWindowHandle, Capabilities caps) {
a959c53b
KR
161 shouldNotCallThis();
162 }
163
164 protected void closeNative() {
165 shouldNotCallThis();
166 }
167
168 protected void dispose(boolean regenerate) {
169 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
2268a6ce 170 Exception e1 = new Exception("GLWindow.dispose("+regenerate+") "+Thread.currentThread()+", 1: "+this);
a959c53b
KR
171 e1.printStackTrace();
172 }
173
174 sendDisposeEvent();
175
176 if (context != null) {
177 context.destroy();
178 }
179 if (drawable != null) {
180 drawable.setRealized(false);
181 }
182
183 if(null!=window) {
184 window.disposeSurfaceHandle();
185 }
186
187 if(regenerate) {
188 if(null==window) {
189 throw new GLException("GLWindow.dispose(true): null window");
190 }
191
192 // recreate GLDrawable, to reflect the new graphics configurations
193 NativeWindow nw;
194 if (window.getWrappedWindow() != null) {
195 nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration());
196 } else {
197 nw = window;
198 }
199 drawable = factory.createGLDrawable(nw);
200 drawable.setRealized(true);
a959c53b
KR
201 context = drawable.createContext(null);
202 sendReshape = true; // ensure a reshape event is send ..
203 }
204
205 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
2268a6ce 206 System.out.println("GLWindow.dispose("+regenerate+") "+Thread.currentThread()+", fin: "+this);
a959c53b
KR
207 }
208 }
209
210 public synchronized void destroy() {
2268a6ce
SG
211 destroy(false);
212 }
213
214 public synchronized void destroy(boolean deep) {
a959c53b 215 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
2268a6ce 216 Exception e1 = new Exception("GLWindow.destroy "+Thread.currentThread()+", 1: "+this);
a959c53b
KR
217 e1.printStackTrace();
218 }
219
a92906bc
SG
220 List newglw = (List) ((ArrayList) glwindows).clone();
221 newglw.remove(this);
222 glwindows=newglw;
223
a959c53b
KR
224 dispose(false);
225
226 Screen _screen = null;
227 Display _device = null;
228 if(null!=window) {
2268a6ce 229 if(!deep && ownerOfDisplayAndScreen) {
a959c53b
KR
230 _screen = getScreen();
231 if(null != _screen) {
232 _device = _screen.getDisplay();
233 }
234 }
2268a6ce 235 window.destroy(deep);
a959c53b
KR
236 }
237
238 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
2268a6ce 239 System.out.println("GLWindow.destroy "+Thread.currentThread()+", fin: "+this);
a959c53b
KR
240 }
241
242 drawable = null;
243 context = null;
244
245 if(null != _screen) {
246 _screen.destroy();
247 }
248 if(null != _device) {
249 _device.destroy();
250 }
251 window = null;
252 }
253
254 public boolean getPerfLogEnabled() { return perfLog; }
255
256 public void enablePerfLog(boolean v) {
257 perfLog = v;
258 }
259
a959c53b 260 public void setVisible(boolean visible) {
2268a6ce
SG
261 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
262 System.out.println(Thread.currentThread()+" GLWindow.setVisible("+visible+") START ; isVisible "+this.visible+" ; has context "+(null!=context));
263 }
264 this.visible=visible;
a959c53b
KR
265 window.setVisible(visible);
266 if (visible && context == null) {
267 NativeWindow nw;
268 if (window.getWrappedWindow() != null) {
269 nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration());
270 } else {
271 nw = window;
272 }
273 GLCapabilities glCaps = (GLCapabilities) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities();
274 factory = GLDrawableFactory.getFactory(glCaps.getGLProfile());
275 drawable = factory.createGLDrawable(nw);
276 drawable.setRealized(true);
a959c53b
KR
277 context = drawable.createContext(null);
278 sendReshape = true; // ensure a reshape event is send ..
279 }
2268a6ce
SG
280 if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) {
281 System.out.println(Thread.currentThread()+" GLWindow.setVisible("+visible+") END ; has context "+(null!=context));
282 }
a959c53b
KR
283 }
284
285 public Screen getScreen() {
286 return window.getScreen();
287 }
288
289 public void setTitle(String title) {
290 window.setTitle(title);
291 }
292
293 public String getTitle() {
294 return window.getTitle();
295 }
296
297 public void setUndecorated(boolean value) {
298 window.setUndecorated(value);
299 }
300
301 public boolean isUndecorated() {
302 return window.isUndecorated();
303 }
304
305 public void setSize(int width, int height) {
306 window.setSize(width, height);
307 }
308
309 public void setPosition(int x, int y) {
310 window.setPosition(x, y);
311 }
312
7bed517f 313 public Insets getInsets() {
314 return window.getInsets();
315 }
316
a959c53b
KR
317 public boolean setFullscreen(boolean fullscreen) {
318 return window.setFullscreen(fullscreen);
319 }
320
321 public boolean isVisible() {
322 return window.isVisible();
323 }
324
325 public int getX() {
326 return window.getX();
327 }
328
329 public int getY() {
330 return window.getY();
331 }
332
333 public int getWidth() {
334 return window.getWidth();
335 }
336
337 public int getHeight() {
338 return window.getHeight();
339 }
340
341 public boolean isFullscreen() {
342 return window.isFullscreen();
343 }
344
bf584fba
SG
345 public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) {
346 window.addSurfaceUpdatedListener(l);
347 }
348 public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) {
349 window.removeSurfaceUpdatedListener(l);
350 }
351 public SurfaceUpdatedListener[] getSurfaceUpdatedListener() {
352 return window.getSurfaceUpdatedListener();
353 }
354 public void surfaceUpdated(Object updater, NativeWindow window0, long when) {
355 window.surfaceUpdated(updater, window, when);
356 }
357
a959c53b
KR
358 public void addMouseListener(MouseListener l) {
359 window.addMouseListener(l);
360 }
361
362 public void removeMouseListener(MouseListener l) {
363 window.removeMouseListener(l);
364 }
365
366 public MouseListener[] getMouseListeners() {
367 return window.getMouseListeners();
368 }
369
370 public void addKeyListener(KeyListener l) {
371 window.addKeyListener(l);
372 }
373
374 public void removeKeyListener(KeyListener l) {
375 window.removeKeyListener(l);
376 }
377
378 public KeyListener[] getKeyListeners() {
379 return window.getKeyListeners();
380 }
381
382 public void addWindowListener(WindowListener l) {
383 window.addWindowListener(l);
384 }
385
386 public void removeWindowListener(WindowListener l) {
387 window.removeWindowListener(l);
388 }
389
390 public WindowListener[] getWindowListeners() {
391 return window.getWindowListeners();
392 }
393
394 public String toString() {
bf584fba 395 return "NEWT-GLWindow[ \n\tDrawable: "+drawable+", \n\tWindow: "+window+", \n\tHelper: "+helper+", \n\tFactory: "+factory+"]";
a959c53b
KR
396 }
397
398 //----------------------------------------------------------------------
399 // OpenGL-related methods and state
400 //
401
a959c53b
KR
402 private GLDrawableFactory factory;
403 private GLDrawable drawable;
404 private GLContext context;
405 private GLDrawableHelper helper = new GLDrawableHelper();
406 // To make reshape events be sent immediately before a display event
407 private boolean sendReshape=false;
408 private boolean sendDestroy=false;
409 private boolean perfLog = false;
410
411 public GLDrawableFactory getFactory() {
412 return factory;
413 }
414
415 public void setContext(GLContext newCtx) {
416 context = newCtx;
417 }
418
419 public GLContext getContext() {
420 return context;
421 }
422
423 public GL getGL() {
424 if (context == null) {
425 return null;
426 }
427 return context.getGL();
428 }
429
4e0a5af0 430 public GL setGL(GL gl) {
a959c53b
KR
431 if (context != null) {
432 context.setGL(gl);
4e0a5af0 433 return gl;
a959c53b 434 }
4e0a5af0 435 return null;
a959c53b
KR
436 }
437
438 public void addGLEventListener(GLEventListener listener) {
439 helper.addGLEventListener(listener);
440 }
441
442 public void removeGLEventListener(GLEventListener listener) {
443 helper.removeGLEventListener(listener);
444 }
445
446 public void display() {
cf4c4037
SG
447 display(false);
448 }
449
450 public void display(boolean forceReshape) {
2268a6ce 451 if(window!=null && drawable!=null && context != null) {
a92906bc 452 if(runPumpMessages) {
2268a6ce 453 window.getScreen().getDisplay().pumpMessages();
a92906bc 454 }
a959c53b
KR
455 if(window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED) {
456 dispose(true);
457 }
458 if (sendDestroy) {
459 destroy();
460 sendDestroy=false;
461 } else {
cf4c4037
SG
462 if(forceReshape) {
463 sendReshape = true;
464 }
a959c53b
KR
465 helper.invokeGL(drawable, context, displayAction, initAction);
466 }
467 }
468 }
469
470 private void sendDisposeEvent() {
2268a6ce 471 if(drawable!=null && context != null) {
a959c53b
KR
472 helper.invokeGL(drawable, context, disposeAction, null);
473 }
474 }
475
a92906bc 476 /** This implementation uses a static value */
a959c53b 477 public void setAutoSwapBufferMode(boolean onOrOff) {
2268a6ce 478 helper.setAutoSwapBufferMode(onOrOff);
a959c53b
KR
479 }
480
a92906bc 481 /** This implementation uses a static value */
a959c53b 482 public boolean getAutoSwapBufferMode() {
2268a6ce 483 return helper.getAutoSwapBufferMode();
a959c53b
KR
484 }
485
486 public void swapBuffers() {
2268a6ce
SG
487 if(drawable!=null && context != null) {
488 if (context != GLContext.getCurrent()) {
a959c53b
KR
489 // Assume we should try to make the context current before swapping the buffers
490 helper.invokeGL(drawable, context, swapBuffersAction, initAction);
491 } else {
492 drawable.swapBuffers();
493 }
494 }
495 }
496
497 class InitAction implements Runnable {
498 public void run() {
499 helper.init(GLWindow.this);
500 startTime = System.currentTimeMillis();
501 curTime = startTime;
502 if(perfLog) {
503 lastCheck = startTime;
504 totalFrames = 0; lastFrames = 0;
505 }
506 }
507 }
508 private InitAction initAction = new InitAction();
509
510 class DisposeAction implements Runnable {
511 public void run() {
512 helper.dispose(GLWindow.this);
513 }
514 }
515 private DisposeAction disposeAction = new DisposeAction();
516
517 class DisplayAction implements Runnable {
518 public void run() {
519 if (sendReshape) {
520 int width = getWidth();
521 int height = getHeight();
522 getGL().glViewport(0, 0, width, height);
523 helper.reshape(GLWindow.this, 0, 0, width, height);
524 sendReshape = false;
525 }
526
527 helper.display(GLWindow.this);
528
529 curTime = System.currentTimeMillis();
530 totalFrames++;
531
532 if(perfLog) {
533 long dt0, dt1;
534 lastFrames++;
535 dt0 = curTime-lastCheck;
536 if ( dt0 > 5000 ) {
537 dt1 = curTime-startTime;
538 System.out.println(dt0/1000 +"s: "+ lastFrames + "f, " + (lastFrames*1000)/dt0 + " fps, "+dt0/lastFrames+" ms/f; "+
539 "total: "+ dt1/1000+"s, "+(totalFrames*1000)/dt1 + " fps, "+dt1/totalFrames+" ms/f");
540 lastCheck=curTime;
541 lastFrames=0;
542 }
543 }
544 }
545 }
a92906bc 546 private DisplayAction displayAction = new DisplayAction();
a959c53b
KR
547
548 public long getStartTime() { return startTime; }
549 public long getCurrentTime() { return curTime; }
550 public long getDuration() { return curTime-startTime; }
551 public int getTotalFrames() { return totalFrames; }
552
553 private long startTime = 0;
554 private long curTime = 0;
555 private long lastCheck = 0;
556 private int totalFrames = 0, lastFrames = 0;
a959c53b 557
a959c53b
KR
558 class SwapBuffersAction implements Runnable {
559 public void run() {
560 drawable.swapBuffers();
561 }
562 }
a959c53b
KR
563 private SwapBuffersAction swapBuffersAction = new SwapBuffersAction();
564
565 //----------------------------------------------------------------------
566 // GLDrawable methods
567 //
568
569 public NativeWindow getNativeWindow() {
570 return null!=drawable ? drawable.getNativeWindow() : null;
571 }
572
573 public synchronized int lockSurface() throws NativeWindowException {
574 if(null!=drawable) return drawable.getNativeWindow().lockSurface();
575 return NativeWindow.LOCK_SURFACE_NOT_READY;
576 }
577
578 public synchronized void unlockSurface() {
579 if(null!=drawable) drawable.getNativeWindow().unlockSurface();
580 else throw new NativeWindowException("NEWT-GLWindow not locked");
581 }
582
583 public synchronized boolean isSurfaceLocked() {
584 if(null!=drawable) return drawable.getNativeWindow().isSurfaceLocked();
585 return false;
586 }
587
588 public synchronized Exception getLockedStack() {
589 if(null!=drawable) return drawable.getNativeWindow().getLockedStack();
590 return null;
591 }
592
8883fa88 593 public boolean surfaceSwap() {
594 if(null!=drawable) return drawable.getNativeWindow().surfaceSwap();
595 return super.surfaceSwap();
596 }
597
a959c53b
KR
598 public long getWindowHandle() {
599 if(null!=drawable) return drawable.getNativeWindow().getWindowHandle();
600 return super.getWindowHandle();
601 }
602
603 public long getSurfaceHandle() {
604 if(null!=drawable) return drawable.getNativeWindow().getSurfaceHandle();
605 return super.getSurfaceHandle();
606 }
607
608 //----------------------------------------------------------------------
609 // GLDrawable methods that are not really needed
610 //
611
612 public GLContext createContext(GLContext shareWith) {
613 return drawable.createContext(shareWith);
614 }
615
616 public void setRealized(boolean realized) {
617 }
618
619 public GLCapabilities getChosenGLCapabilities() {
620 if (drawable == null) {
621 throw new GLException("No drawable yet");
622 }
623
624 return drawable.getChosenGLCapabilities();
625 }
626
627 public GLProfile getGLProfile() {
628 if (drawable == null) {
629 throw new GLException("No drawable yet");
630 }
631
632 return drawable.getGLProfile();
633 }
634
635 //----------------------------------------------------------------------
636 // Internals only below this point
637 //
638
639 private void shouldNotCallThis() {
640 throw new NativeWindowException("Should not call this");
641 }
642}
http://JogAmp.org git info: FAQ, tutorial and man pages.