From 0feca163be47db2ea94f7546e696136d6f9496e9 Mon Sep 17 00:00:00 2001 From: Sven Gothel Date: Thu, 23 Sep 2010 16:21:39 +0200 Subject: NEWT: Fix Display/Window/Screen OO Identity, Reparenting and requestFocus NativeWindow: Interface NativeWindow changes: - Remove 'throws' qualifier in lockSurface(), since it is not - Adding convenient 'one call' isSurfaceLockedByOtherThread() - Adding getSurfaceLockOwner() NEWT Window/GLWindow: - Unclutter Window/GLWindow relationship - save Window's indentity GLWindow's role is a GLAutoDrawable implementation aggregating (maybe even compositioning) a Window. The previous implementation just derived from the Window implementation, overwriting methods and fields - impossible to ensure sanity / completness. It was also not ensured that the added functionality of GLWindow (setVisible, destroy, ..) has been issued in case of handling the aggregated Window alone (window callbacks, ..). To solve this issue in a 1st attempt without changing the GLWindow API, Window is just an interface, being implemented by their specializations, hence sanity is intrinsic. GLWindow's added functionality is ensured by a Window.LifecycleHook interfaced implementation, registered at the aggregated Window. - Screen and Window are interfaces now (new files) - Display is an abstract class. - Their (abstract) implementations resides in impl/Impl - GLWindow implements Window as well - Remove Screen reference handled by setScreen(Screen) method. - Lock native parentWindow if used (createNative/reparenting) - Move lockSurface/unlockSurface from unchecked override pattern to an callback style using abstract methods lockSurfaceImpl/... - Sorting all methods to semantic sections, abstract, superinterface, .. - Reparenting: Handling different reparenting situations: - Unchanged - No change - Native Reparenting - Compatible Display/Screen, try native reparenting - Native (Re)Creation - Use destroy/create pattern - Native Creation Pending - Create later - setUndecorated() calls reconfigure Window now, ie tries to change the window actually - Don't issue 'requestFocus()' directly from the native implementation anymore, call it from the Java code. - Window/GLWindow/NewtFactory: Constructor simplification Avoid explosion of constructor overloading, ie removing the 'undecorated' variant, since this is redundant due to the 'setUndecorated(boolean)' method. - Fixed/added API documentation --- src/newt/classes/com/jogamp/newt/Display.java | 441 +---- src/newt/classes/com/jogamp/newt/NewtFactory.java | 81 +- .../classes/com/jogamp/newt/OffscreenWindow.java | 114 -- src/newt/classes/com/jogamp/newt/Screen.java | 214 +-- src/newt/classes/com/jogamp/newt/Window.java | 1854 +++----------------- .../classes/com/jogamp/newt/awt/NewtCanvasAWT.java | 13 +- .../com/jogamp/newt/awt/NewtFactoryAWT.java | 11 - .../com/jogamp/newt/event/WindowListener.java | 12 + .../classes/com/jogamp/newt/impl/DisplayImpl.java | 381 ++++ .../com/jogamp/newt/impl/OffscreenWindow.java | 119 ++ .../classes/com/jogamp/newt/impl/ScreenImpl.java | 188 ++ .../classes/com/jogamp/newt/impl/WindowImpl.java | 1771 +++++++++++++++++++ .../com/jogamp/newt/impl/awt/AWTDisplay.java | 3 +- .../com/jogamp/newt/impl/awt/AWTScreen.java | 3 +- .../com/jogamp/newt/impl/awt/AWTWindow.java | 19 +- .../com/jogamp/newt/impl/intel/gdl/Display.java | 2 +- .../com/jogamp/newt/impl/intel/gdl/Screen.java | 2 +- .../com/jogamp/newt/impl/intel/gdl/Window.java | 26 +- .../com/jogamp/newt/impl/macosx/MacDisplay.java | 2 +- .../com/jogamp/newt/impl/macosx/MacScreen.java | 3 +- .../com/jogamp/newt/impl/macosx/MacWindow.java | 94 +- .../newt/impl/opengl/broadcom/egl/Display.java | 2 +- .../newt/impl/opengl/broadcom/egl/Screen.java | 2 +- .../newt/impl/opengl/broadcom/egl/Window.java | 23 +- .../com/jogamp/newt/impl/opengl/kd/KDDisplay.java | 2 +- .../com/jogamp/newt/impl/opengl/kd/KDScreen.java | 3 +- .../com/jogamp/newt/impl/opengl/kd/KDWindow.java | 16 +- .../jogamp/newt/impl/windows/WindowsDisplay.java | 2 +- .../jogamp/newt/impl/windows/WindowsScreen.java | 3 +- .../jogamp/newt/impl/windows/WindowsWindow.java | 71 +- .../com/jogamp/newt/impl/x11/X11Display.java | 2 +- .../com/jogamp/newt/impl/x11/X11Screen.java | 3 +- .../com/jogamp/newt/impl/x11/X11Window.java | 42 +- .../classes/com/jogamp/newt/opengl/GLWindow.java | 836 +++++---- 34 files changed, 3511 insertions(+), 2849 deletions(-) delete mode 100644 src/newt/classes/com/jogamp/newt/OffscreenWindow.java create mode 100644 src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java create mode 100644 src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java create mode 100644 src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java create mode 100644 src/newt/classes/com/jogamp/newt/impl/WindowImpl.java (limited to 'src/newt/classes/com/jogamp') diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index 5e3e32964..b09f63962 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -1,85 +1,95 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. */ package com.jogamp.newt; -import javax.media.nativewindow.*; -import com.jogamp.nativewindow.impl.RecursiveToolkitLock; -import com.jogamp.newt.event.*; -import com.jogamp.newt.impl.event.*; -import com.jogamp.newt.impl.Debug; import com.jogamp.newt.util.EDTUtil; -import com.jogamp.newt.util.MainThread; -import com.jogamp.newt.util.DefaultEDTUtil; +import com.jogamp.newt.impl.Debug; +import com.jogamp.newt.impl.DisplayImpl; + import java.util.*; +import javax.media.nativewindow.AbstractGraphicsDevice; + public abstract class Display { public static final boolean DEBUG = Debug.debug("Display"); - public static final boolean DEBUG_TEST_EDT_MAINTHREAD = Debug.isPropertyDefined("newt.test.EDTMainThread", true); // JAU EDT Test .. - private static Class getDisplayClass(String type) - throws ClassNotFoundException - { - Class displayClass = NewtFactory.getCustomClass(type, "Display"); - if(null==displayClass) { - if (NativeWindowFactory.TYPE_EGL.equals(type)) { - displayClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDDisplay"); - } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { - displayClass = Class.forName("com.jogamp.newt.impl.windows.WindowsDisplay"); - } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { - displayClass = Class.forName("com.jogamp.newt.impl.macosx.MacDisplay"); - } else if (NativeWindowFactory.TYPE_X11.equals(type)) { - displayClass = Class.forName("com.jogamp.newt.impl.x11.X11Display"); - } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { - displayClass = Class.forName("com.jogamp.newt.impl.awt.AWTDisplay"); - } else { - throw new RuntimeException("Unknown display type \"" + type + "\""); - } - } - return displayClass; - } + /** + * @return true if the native display handle is valid and ready to operate, + * otherwise false. + * + * @see #destroy() + */ + public abstract boolean isNativeValid(); + + /** + * @return number of references by Screen + */ + public abstract int getReferenceCount(); + + public abstract void destroy(); + + public abstract boolean getDestroyWhenUnused(); + + /** + * + * @param v + */ + public abstract void setDestroyWhenUnused(boolean v); + public abstract AbstractGraphicsDevice getGraphicsDevice(); + + public abstract String getFQName(); + + public abstract long getHandle(); + + public abstract int getId(); + + public abstract String getName(); + + public abstract String getType(); + + public abstract EDTUtil getEDTUtil(); + + public abstract boolean isEDTRunning(); + + public abstract void dispatchMessages(); + // Global Displays - private static ArrayList displayList = new ArrayList(); - private static int displaysActive = 0; - private static int serialno = 1; + protected static ArrayList displayList = new ArrayList(); + protected static int displaysActive = 0; public static void dumpDisplayList(String prefix) { synchronized(displayList) { Iterator i = displayList.iterator(); System.err.println(prefix+" DisplayList[] entries: "+displayList.size()+" - "+getThreadName()); for(int j=0; i.hasNext(); j++) { - Display d = (Display) i.next(); + DisplayImpl d = (DisplayImpl) i.next(); System.err.println(" ["+j+"] : "+d); } } @@ -100,219 +110,6 @@ public abstract class Display { } } - /** Make sure to reuse a Display with the same name */ - protected static Display create(String type, String name, final long handle) { - try { - Class displayClass = getDisplayClass(type); - Display display = (Display) displayClass.newInstance(); - name = display.validateDisplayName(name, handle); - display.name = name; - display.type=type; - display.destroyWhenUnused=false; - synchronized(displayList) { - display.id = serialno++; - display.fqname = getFQName(display.id, display.type, display.name); - displayList.add(display); - } - display.createEDTUtil(); - if(DEBUG) { - System.err.println("Display.create() NEW: "+display+" "+getThreadName()); - } - return display; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - protected synchronized final void createNative() { - if(null==aDevice) { - if(DEBUG) { - System.err.println("Display.createNative() START ("+getThreadName()+", "+this+")"); - } - final Display f_dpy = this; - runOnEDTIfAvail(true, new Runnable() { - public void run() { - f_dpy.createNativeImpl(); - }}); - if(null==aDevice) { - throw new RuntimeException("Display.createNative() failed to instanciate an AbstractGraphicsDevice"); - } - if(DEBUG) { - System.err.println("Display.createNative() END ("+getThreadName()+", "+this+")"); - } - synchronized(displayList) { - displaysActive++; - } - } - } - - protected boolean shallRunOnEDT() { - return true; - } - - protected void createEDTUtil() { - if(NewtFactory.useEDT()) { - if ( ! DEBUG_TEST_EDT_MAINTHREAD ) { - Thread current = Thread.currentThread(); - edtUtil = new DefaultEDTUtil(current.getThreadGroup(), "Display-"+getFQName(), dispatchMessagesRunnable); - } else { - // Begin JAU EDT Test .. - MainThread.addPumpMessage(this, dispatchMessagesRunnable); - edtUtil = MainThread.getSingleton(); - // End JAU EDT Test .. - } - if(DEBUG) { - System.err.println("Display.createNative("+getFQName()+") Create EDTUtil: "+edtUtil.getClass().getName()); - } - } - } - - public final EDTUtil getEDTUtil() { - return edtUtil; - } - - public void runOnEDTIfAvail(boolean wait, final Runnable task) { - if( shallRunOnEDT() && null!=edtUtil ) { - edtUtil.invoke(wait, task); - } else { - task.run(); - } - } - - public synchronized final void destroy() { - if ( null != aDevice ) { - if(DEBUG) { - dumpDisplayList("Display.destroy("+getFQName()+") BEGIN"); - } - synchronized(displayList) { - displayList.remove(this); - displaysActive--; - } - if(DEBUG) { - System.err.println("Display.destroy(): "+this+" "+getThreadName()); - } - final Display f_dpy = this; - final EDTUtil f_edtUtil = edtUtil; - runOnEDTIfAvail(true, new Runnable() { - public void run() { - f_dpy.closeNativeImpl(); - if(null!=f_edtUtil) { - f_edtUtil.stop(); - } - } - } ); - if(null!=edtUtil) { - if ( DEBUG_TEST_EDT_MAINTHREAD ) { - MainThread.removePumpMessage(this); // JAU EDT Test .. - } - edtUtil.waitUntilStopped(); - edtUtil.reset(); - } - aDevice = null; - if(DEBUG) { - dumpDisplayList("Display.destroy("+getFQName()+") END"); - } - } - } - - protected synchronized final int addReference() { - if(DEBUG) { - System.err.println("Display.addReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount+1)); - } - if ( 0 == refCount ) { - createNative(); - } - if(null == aDevice) { - throw new RuntimeException("Display.addReference() (refCount "+refCount+") null AbstractGraphicsDevice"); - } - return ++refCount; - } - - - protected synchronized final int removeReference() { - if(DEBUG) { - System.err.println("Display.removeReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount-1)); - } - refCount--; - if(0==refCount && destroyWhenUnused) { - destroy(); - } - return refCount; - } - - /** - * @return number of references by Screen - */ - public synchronized final int getReferenceCount() { - return refCount; - } - - public final boolean getDestroyWhenUnused() { return destroyWhenUnused; } - public final void setDestroyWhenUnused(boolean v) { destroyWhenUnused=v; } - - protected abstract void createNativeImpl(); - protected abstract void closeNativeImpl(); - - public final int getId() { - return id; - } - - public final String getType() { - return type; - } - - public final String getName() { - return name; - } - - public final String getFQName() { - return fqname; - } - - public static final String nilString = "nil" ; - - public String validateDisplayName(String name, long handle) { - if(null==name && 0!=handle) { - name="wrapping-"+toHexString(handle); - } - return ( null == name ) ? nilString : name ; - } - - public static final String getFQName(int id, String type, String name) { - if(null==type) type=nilString; - if(null==name) name=nilString; - StringBuffer sb = new StringBuffer(); - sb.append(type); - sb.append("_"); - sb.append(name); - sb.append("-"); - sb.append(id); - return sb.toString(); - } - - public final long getHandle() { - if(null!=aDevice) { - return aDevice.getHandle(); - } - return 0; - } - - public final AbstractGraphicsDevice getGraphicsDevice() { - return aDevice; - } - - public final boolean isNativeValid() { - return null != aDevice; - } - - public synchronized void pumpMessages() { - dispatchMessages(); - } - - public String toString() { - return "NEWT-Display["+getFQName()+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", "+aDevice+"]"; - } - public static String getThreadName() { return Thread.currentThread().getName(); } @@ -325,93 +122,7 @@ public abstract class Display { return "0x" + Long.toHexString(hex); } - - protected abstract void dispatchMessagesNative(); - - private Object eventsLock = new Object(); - private LinkedList/**/ events = new LinkedList(); - - class DispatchMessagesRunnable implements Runnable { - public void run() { - Display.this.dispatchMessages(); - } - } - DispatchMessagesRunnable dispatchMessagesRunnable = new DispatchMessagesRunnable(); - - public void dispatchMessages() { - if(0==refCount) return; // no screens - if(null==getGraphicsDevice()) return; // no native device - - LinkedList/**/ _events = null; - - if(!events.isEmpty()) { - // swap events list to free ASAP - synchronized(eventsLock) { - if(!events.isEmpty()) { - _events = events; - events = new LinkedList(); - } - eventsLock.notifyAll(); - } - if( null != _events ) { - for (Iterator iter = _events.iterator(); iter.hasNext(); ) { - NEWTEventTask eventTask = (NEWTEventTask) iter.next(); - NEWTEvent event = eventTask.get(); - Object source = event.getSource(); - if(source instanceof NEWTEventConsumer) { - NEWTEventConsumer consumer = (NEWTEventConsumer) source ; - if(!consumer.consumeEvent(event)) { - enqueueEvent(false, event); - } - } else { - throw new RuntimeException("Event source not NEWT: "+source.getClass().getName()+", "+source); - } - eventTask.notifyIssuer(); - } - } - } - - // lock(); - try { - dispatchMessagesNative(); - } finally { - // unlock(); - } - } - - public void enqueueEvent(boolean wait, NEWTEvent e) { - Object lock = new Object(); - NEWTEventTask eTask = new NEWTEventTask(e, wait?lock:null); - synchronized(lock) { - synchronized(eventsLock) { - events.addLast(eTask); - eventsLock.notifyAll(); - } - if( wait ) { - try { - lock.wait(); - } catch (InterruptedException ie) { - throw new RuntimeException(ie); - } - } - } - } - - public void lock() { - aDevice.lock(); + public static int hashCode(Object o) { + return ( null != o ) ? o.hashCode() : 0; } - - public void unlock() { - aDevice.unlock(); - } - - protected EDTUtil edtUtil = null; - protected int id; - protected String name; - protected String type; - protected String fqname; - protected int refCount; // number of Display references by Screen - protected boolean destroyWhenUnused; - protected AbstractGraphicsDevice aDevice; } - diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java index 7c610c1b8..5f969777a 100644 --- a/src/newt/classes/com/jogamp/newt/NewtFactory.java +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are @@ -40,19 +41,22 @@ import java.util.Iterator; import com.jogamp.common.jvm.JVMUtil; import com.jogamp.newt.event.WindowAdapter; import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.impl.DisplayImpl; +import com.jogamp.newt.impl.ScreenImpl; +import com.jogamp.newt.impl.WindowImpl; import com.jogamp.newt.impl.Debug; -public abstract class NewtFactory { +public class NewtFactory { public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); // Work-around for initialization order problems on Mac OS X // between native Newt and (apparently) Fmod static { JVMUtil.initSingleton(); - Window.init(NativeWindowFactory.getNativeWindowType(true)); + WindowImpl.init(NativeWindowFactory.getNativeWindowType(true)); } - static Class getCustomClass(String packageName, String classBaseName) { + public static Class getCustomClass(String packageName, String classBaseName) { Class clazz = null; if(packageName!=null || classBaseName!=null) { String clazzName = packageName + "." + classBaseName ; @@ -81,42 +85,43 @@ public abstract class NewtFactory { * Create a Display entity, incl native creation */ public static Display createDisplay(String name) { - return Display.create(NativeWindowFactory.getNativeWindowType(true), name, 0); + return DisplayImpl.create(NativeWindowFactory.getNativeWindowType(true), name, 0); } /** * Create a Display entity using the given implementation type, incl native creation */ public static Display createDisplay(String type, String name) { - return Display.create(type, name, 0); + return DisplayImpl.create(type, name, 0); } /** * Create a Screen entity, incl native creation */ public static Screen createScreen(Display display, int index) { - return Screen.create(NativeWindowFactory.getNativeWindowType(true), display, index); + return ScreenImpl.create(NativeWindowFactory.getNativeWindowType(true), display, index); } /** * Create a Screen entity using the given implementation type, incl native creation */ public static Screen createScreen(String type, Display display, int index) { - return Screen.create(type, display, index); + return ScreenImpl.create(type, display, index); } /** - * Create a top level Window entity, incl native creation + * Create a top level Window entity, incl native creation. + * The Display/Screen is created and owned, ie destructed atomatic. */ - public static Window createWindow(Screen screen, Capabilities caps) { - return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), screen, caps, false); + public static Window createWindow(Capabilities caps) { + return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), caps); } /** * Create a top level Window entity, incl native creation */ - public static Window createWindow(Screen screen, Capabilities caps, boolean undecorated) { - return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), screen, caps, undecorated); + public static Window createWindow(Screen screen, Capabilities caps) { + return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), screen, caps); } /** @@ -131,17 +136,13 @@ public abstract class NewtFactory { * The parents visibility is passed to the new Window

*

* In case parentWindowObject is a different {@link javax.media.nativewindow.NativeWindow} implementation,
- * you have to handle all events appropriatly.

+ * you have to handle all events appropriate.

*

* * @param parentWindowObject either a NativeWindow instance - * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always */ - public static Window createWindow(NativeWindow nParentWindow, Capabilities caps, boolean undecorated) { + public static Window createWindow(NativeWindow nParentWindow, Capabilities caps) { final String type = NativeWindowFactory.getNativeWindowType(true); - if(null==nParentWindow) { - return createWindowImpl(type, caps, undecorated); - } Screen screen = null; Window parentWindow = null; @@ -164,33 +165,33 @@ public abstract class NewtFactory { } screen.setDestroyWhenUnused(true); } - final Window win = createWindowImpl(type, nParentWindow, screen, caps, undecorated); + final Window win = createWindowImpl(type, nParentWindow, screen, caps); win.setSize(nParentWindow.getWidth(), nParentWindow.getHeight()); if ( null != parentWindow ) { - parentWindow.getInnerWindow().addChild(win); + parentWindow.addChild(win); win.setVisible(parentWindow.isVisible()); } return win; } - protected static Window createWindowImpl(String type, NativeWindow parentNativeWindow, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(type, parentNativeWindow, 0, screen, caps, undecorated); + protected static Window createWindowImpl(String type, NativeWindow parentNativeWindow, Screen screen, Capabilities caps) { + return WindowImpl.create(type, parentNativeWindow, 0, screen, caps); } - protected static Window createWindowImpl(String type, long parentWindowHandle, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(type, null, parentWindowHandle, screen, caps, undecorated); + protected static Window createWindowImpl(String type, long parentWindowHandle, Screen screen, Capabilities caps) { + return WindowImpl.create(type, null, parentWindowHandle, screen, caps); } - protected static Window createWindowImpl(String type, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(type, null, 0, screen, caps, undecorated); + protected static Window createWindowImpl(String type, Screen screen, Capabilities caps) { + return WindowImpl.create(type, null, 0, screen, caps); } - protected static Window createWindowImpl(String type, Capabilities caps, boolean undecorated) { + protected static Window createWindowImpl(String type, Capabilities caps) { Display display = NewtFactory.createDisplay(type, null); // local display Screen screen = NewtFactory.createScreen(type, display, 0); // screen 0 screen.setDestroyWhenUnused(true); - return Window.create(type, null, 0, screen, caps, undecorated); + return WindowImpl.create(type, null, 0, screen, caps); } /** @@ -199,19 +200,19 @@ public abstract class NewtFactory { * @param parentWindowObject the native parent window handle * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always */ - public static Window createWindow(long parentWindowHandle, Screen screen, Capabilities caps, boolean undecorated) { - return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), parentWindowHandle, screen, caps, undecorated); + public static Window createWindow(long parentWindowHandle, Screen screen, Capabilities caps) { + return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), parentWindowHandle, screen, caps); } /** - * Ability to try a Window type with a construnctor argument, if supported ..

+ * Ability to try a Window type with a constructor argument, if supported ..

* Currently only valid is AWTWindow(Frame frame) , * to support an external created AWT Frame, ie the browsers embedded frame. * * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always */ - public static Window createWindow(Object[] cstrArguments, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(NativeWindowFactory.getNativeWindowType(true), cstrArguments, screen, caps, undecorated); + public static Window createWindow(Object[] cstrArguments, Screen screen, Capabilities caps) { + return WindowImpl.create(NativeWindowFactory.getNativeWindowType(true), cstrArguments, screen, caps); } /** @@ -219,19 +220,19 @@ public abstract class NewtFactory { * * @param undecorated only impacts if the window is in top-level state, while attached to a parent window it's rendered undecorated always */ - public static Window createWindow(String type, Screen screen, Capabilities caps, boolean undecorated) { - return createWindowImpl(type, null, screen, caps, undecorated); + public static Window createWindow(String type, Screen screen, Capabilities caps) { + return createWindowImpl(type, null, screen, caps); } - public static Window createWindow(String type, Object[] cstrArguments, Screen screen, Capabilities caps, boolean undecorated) { - return Window.create(type, cstrArguments, screen, caps, undecorated); + public static Window createWindow(String type, Object[] cstrArguments, Screen screen, Capabilities caps) { + return WindowImpl.create(type, cstrArguments, screen, caps); } /** * Instantiate a Display entity using the native handle. */ public static Display createDisplay(String type, long handle) { - return Display.create(type, null, handle); + return DisplayImpl.create(type, null, handle); } private static final boolean instanceOf(Object obj, String clazzName) { @@ -251,7 +252,7 @@ public abstract class NewtFactory { AbstractGraphicsScreen parentScreen = (AbstractGraphicsScreen) parentConfig.getScreen(); AbstractGraphicsDevice parentDevice = (AbstractGraphicsDevice) parentScreen.getDevice(); - Display childDisplay = childScreen.getDisplay(); + DisplayImpl childDisplay = (DisplayImpl) childScreen.getDisplay(); String parentDisplayName = childDisplay.validateDisplayName(null, parentDevice.getHandle()); String childDisplayName = childDisplay.getName(); if( ! parentDisplayName.equals( childDisplayName ) ) { @@ -276,7 +277,7 @@ public abstract class NewtFactory { if(null != childScreen) { // check if child Display/Screen is compatible already - Display childDisplay = childScreen.getDisplay(); + DisplayImpl childDisplay = (DisplayImpl) childScreen.getDisplay(); String parentDisplayName = childDisplay.validateDisplayName(null, parentDevice.getHandle()); String childDisplayName = childDisplay.getName(); boolean displayEqual = parentDisplayName.equals( childDisplayName ); diff --git a/src/newt/classes/com/jogamp/newt/OffscreenWindow.java b/src/newt/classes/com/jogamp/newt/OffscreenWindow.java deleted file mode 100644 index d17f8df07..000000000 --- a/src/newt/classes/com/jogamp/newt/OffscreenWindow.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * - */ - -package com.jogamp.newt; - -import javax.media.nativewindow.*; - -public class OffscreenWindow extends Window implements SurfaceChangeable { - - long surfaceHandle = 0; - - public OffscreenWindow() { - } - - static long nextWindowHandle = 0x100; // start here - a marker - - protected void createNativeImpl() { - if(0!=parentWindowHandle) { - throw new NativeWindowException("OffscreenWindow does not support window parenting"); - } - if(caps.isOnscreen()) { - throw new NativeWindowException("Capabilities is onscreen"); - } - AbstractGraphicsScreen aScreen = screen.getGraphicsScreen(); - config = GraphicsConfigurationFactory.getFactory(aScreen.getDevice()).chooseGraphicsConfiguration(caps, null, aScreen); - if (config == null) { - throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); - } - - synchronized(OffscreenWindow.class) { - windowHandle = nextWindowHandle++; - } - } - - protected void closeNativeImpl() { - // nop - } - - public void invalidate() { - super.invalidate(); - surfaceHandle = 0; - } - - public synchronized void destroy(boolean deep) { - surfaceHandle = 0; - } - - public void setSurfaceHandle(long handle) { - surfaceHandle = handle ; - } - - public long getSurfaceHandle() { - return surfaceHandle; - } - - protected void setVisibleImpl(boolean visible) { - } - - public void setSize(int width, int height) { - if(!visible) { - this.width = width; - this.height = height; - } - } - protected void setSizeImpl(int width, int height) { - shouldNotCallThis(); - } - - public void setPosition(int x, int y) { - // nop - } - protected void setPositionImpl(int x, int y) { - shouldNotCallThis(); - } - - public boolean setFullscreen(boolean fullscreen) { - // nop - return false; - } - protected void setFullscreenImpl(boolean fullscreen, int x, int y, int w, int h) { - shouldNotCallThis(); - } -} - diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java index d25da86d8..f1b4254d8 100644 --- a/src/newt/classes/com/jogamp/newt/Screen.java +++ b/src/newt/classes/com/jogamp/newt/Screen.java @@ -1,202 +1,70 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. */ package com.jogamp.newt; -import com.jogamp.newt.impl.*; - -import javax.media.nativewindow.*; -import java.security.*; - -public abstract class Screen { +import com.jogamp.newt.impl.Debug; +import javax.media.nativewindow.AbstractGraphicsScreen; +public interface Screen { public static final boolean DEBUG = Debug.debug("Display"); - private static Class getScreenClass(String type) - throws ClassNotFoundException - { - Class screenClass = NewtFactory.getCustomClass(type, "Screen"); - if(null==screenClass) { - if (NativeWindowFactory.TYPE_EGL.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDScreen"); - } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.windows.WindowsScreen"); - } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.macosx.MacScreen"); - } else if (NativeWindowFactory.TYPE_X11.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.x11.X11Screen"); - } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.awt.AWTScreen"); - } else { - throw new RuntimeException("Unknown window type \"" + type + "\""); - } - } - return screenClass; - } - - protected static Screen create(String type, Display display, final int idx) { - try { - if(usrWidth<0 || usrHeight<0) { - usrWidth = Debug.getIntProperty("newt.ws.swidth", true, localACC); - usrHeight = Debug.getIntProperty("newt.ws.sheight", true, localACC); - if(usrWidth>0 || usrHeight>0) { - System.err.println("User screen size "+usrWidth+"x"+usrHeight); - } - } - Class screenClass = getScreenClass(type); - Screen screen = (Screen) screenClass.newInstance(); - screen.display = display; - screen.idx = idx; - return screen; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - protected synchronized final void createNative() { - if(null == aScreen) { - if(DEBUG) { - System.err.println("Screen.createNative() START ("+Display.getThreadName()+", "+this+")"); - } - display.addReference(); - createNativeImpl(); - if(null == aScreen) { - throw new RuntimeException("Screen.createNative() failed to instanciate an AbstractGraphicsScreen"); - } - if(DEBUG) { - System.err.println("Screen.createNative() END ("+Display.getThreadName()+", "+this+")"); - } - } - } - - public synchronized final void destroy() { - if ( null != aScreen ) { - closeNativeImpl(); - display.removeReference(); - aScreen = null; - } - } - - protected synchronized final int addReference() { - if(DEBUG) { - System.err.println("Screen.addReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount+1)); - } - if ( 0 == refCount ) { - createNative(); - } - if(null == aScreen) { - throw new RuntimeException("Screen.addReference() (refCount "+refCount+") null AbstractGraphicsScreen"); - } - return ++refCount; - } + boolean isNativeValid(); - protected synchronized final int removeReference() { - if(DEBUG) { - System.err.println("Screen.removeReference() ("+Display.getThreadName()+"): "+refCount+" -> "+(refCount-1)); - } - refCount--; - if(0==refCount && getDestroyWhenUnused()) { - destroy(); - } - return refCount; - } - - /** + /** + * * @return number of references by Window */ - public synchronized final int getReferenceCount() { - return refCount; - } - - public final boolean getDestroyWhenUnused() { - return display.getDestroyWhenUnused(); - } - public final void setDestroyWhenUnused(boolean v) { - display.setDestroyWhenUnused(v); - } + int getReferenceCount(); - protected abstract void createNativeImpl(); - protected abstract void closeNativeImpl(); + void destroy(); - protected void setScreenSize(int w, int h) { - System.err.println("Detected screen size "+w+"x"+h); - width=w; height=h; - } + boolean getDestroyWhenUnused(); - public final Display getDisplay() { - return display; - } + void setDestroyWhenUnused(boolean v); - public final int getIndex() { - return idx; - } + AbstractGraphicsScreen getGraphicsScreen(); - public final AbstractGraphicsScreen getGraphicsScreen() { - return aScreen; - } - - public final boolean isNativeValid() { - return null != aScreen; - } + int getIndex(); /** * The actual implementation shall return the detected display value, * if not we return 800. * This can be overwritten with the user property 'newt.ws.swidth', */ - public final int getWidth() { - return (usrWidth>0) ? usrWidth : (width>0) ? width : 480; - } + int getWidth(); /** * The actual implementation shall return the detected display value, * if not we return 480. * This can be overwritten with the user property 'newt.ws.sheight', */ - public final int getHeight() { - return (usrHeight>0) ? usrHeight : (height>0) ? height : 480; - } - - public String toString() { - return "NEWT-Screen[idx "+idx+", refCount "+refCount+", "+aScreen+", "+display+"]"; - } + int getHeight(); - protected Display display; - protected int idx; - protected AbstractGraphicsScreen aScreen; - protected int refCount; // number of Screen references by Window - protected int width=-1, height=-1; // detected values: set using setScreenSize - protected static int usrWidth=-1, usrHeight=-1; // property values: newt.ws.swidth and newt.ws.sheight - private static AccessControlContext localACC = AccessController.getContext(); + Display getDisplay(); } - diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java index 67374cc00..ef3e5e69c 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -1,884 +1,118 @@ -/* - * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * - * - Redistribution of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistribution in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * Neither the name of Sun Microsystems, Inc. or the names of - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * This software is provided "AS IS," without a warranty of any kind. ALL - * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, - * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A - * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN - * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR - * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR - * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR - * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR - * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE - * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, - * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF - * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - * +/** + * Copyright 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are + * permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. */ package com.jogamp.newt; -import com.jogamp.newt.event.*; -import com.jogamp.newt.util.*; +import com.jogamp.newt.util.Insets; +import com.jogamp.newt.event.WindowListener; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.NEWTEventConsumer; import com.jogamp.newt.impl.Debug; +import javax.media.nativewindow.Capabilities; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.SurfaceUpdatedListener; -import com.jogamp.common.util.*; -import javax.media.nativewindow.*; -import com.jogamp.nativewindow.util.Rectangle; -import com.jogamp.nativewindow.impl.RecursiveToolkitLock; - -import java.util.ArrayList; -import java.util.List; -import java.util.Iterator; -import java.lang.reflect.Method; - -public abstract class Window implements NativeWindow, NEWTEventConsumer -{ +/** + * Specifying the public Window functionality for the + * using a Window and for shadowing one like {@link com.jogamp.newt.opengl.GLWindow}. + */ +public interface Window extends NativeWindow { public static final boolean DEBUG_MOUSE_EVENT = Debug.debug("Window.MouseEvent"); public static final boolean DEBUG_KEY_EVENT = Debug.debug("Window.KeyEvent"); public static final boolean DEBUG_WINDOW_EVENT = Debug.debug("Window.WindowEvent"); public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); - public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.reparent.incompatible", true); - - // Workaround for initialization order problems on Mac OS X - // between native Newt and (apparently) Fmod -- if Fmod is - // initialized first then the connection to the window server - // breaks, leading to errors from deep within the AppKit - static void init(String type) { - if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { - try { - getWindowClass(type); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - - private static Class getWindowClass(String type) - throws ClassNotFoundException - { - Class windowClass = NewtFactory.getCustomClass(type, "Window"); - if(null==windowClass) { - if (NativeWindowFactory.TYPE_EGL.equals(type)) { - windowClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDWindow"); - } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { - windowClass = Class.forName("com.jogamp.newt.impl.windows.WindowsWindow"); - } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { - windowClass = Class.forName("com.jogamp.newt.impl.macosx.MacWindow"); - } else if (NativeWindowFactory.TYPE_X11.equals(type)) { - windowClass = Class.forName("com.jogamp.newt.impl.x11.X11Window"); - } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { - windowClass = Class.forName("com.jogamp.newt.impl.awt.AWTWindow"); - } else { - throw new NativeWindowException("Unknown window type \"" + type + "\""); - } - } - return windowClass; - } - - protected static Window create(String type, NativeWindow parentNativeWindow, long parentWindowHandle, Screen screen, Capabilities caps, boolean undecorated) { - try { - Class windowClass; - if(caps.isOnscreen()) { - windowClass = getWindowClass(type); - } else { - windowClass = OffscreenWindow.class; - } - Window window = (Window) windowClass.newInstance(); - window.invalidate(true); - window.parentNativeWindow = parentNativeWindow; - window.parentWindowHandle = parentWindowHandle; - window.screen = screen; - window.caps = (Capabilities)caps.clone(); - window.setUndecorated(undecorated||0!=parentWindowHandle); - return window; - } catch (Throwable t) { - t.printStackTrace(); - throw new NativeWindowException(t); - } - } - - protected static Window create(String type, Object[] cstrArguments, Screen screen, Capabilities caps, boolean undecorated) { - try { - Class windowClass = getWindowClass(type); - Class[] cstrArgumentTypes = getCustomConstructorArgumentTypes(windowClass); - if(null==cstrArgumentTypes) { - throw new NativeWindowException("WindowClass "+windowClass+" doesn't support custom arguments in constructor"); - } - int argsChecked = verifyConstructorArgumentTypes(cstrArgumentTypes, cstrArguments); - if ( argsChecked < cstrArguments.length ) { - throw new NativeWindowException("WindowClass "+windowClass+" constructor mismatch at argument #"+argsChecked+"; Constructor: "+getTypeStrList(cstrArgumentTypes)+", arguments: "+getArgsStrList(cstrArguments)); - } - Window window = (Window) ReflectionUtil.createInstance( windowClass, cstrArgumentTypes, cstrArguments ) ; - window.invalidate(true); - window.screen = screen; - window.caps = (Capabilities)caps.clone(); - window.setUndecorated(undecorated); - return window; - } catch (Throwable t) { - throw new NativeWindowException(t); - } - } - - protected Screen screen; - protected boolean screenReferenced = false; - - protected NativeWindow parentNativeWindow; - protected long parentWindowHandle; - - protected Capabilities caps; - protected AbstractGraphicsConfiguration config; - protected long windowHandle; - protected boolean fullscreen, visible; - protected int width, height, x, y; - - // non fullscreen dimensions .. - protected int nfs_width, nfs_height, nfs_x, nfs_y; - - protected String title = "Newt Window"; - protected boolean undecorated = false; - - private final boolean createNative() { - if( null==screen || 0!=windowHandle || !visible ) { - return 0 != windowHandle ; - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.createNative() START ("+getThreadName()+", "+this+")"); - } - if(validateParentWindowHandle()) { - if(!screenReferenced) { - screenReferenced = true; - screen.addReference(); - } - createNativeImpl(); - setVisibleImpl(true); - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.createNative() END ("+getThreadName()+", "+this+")"); - } - return 0 != windowHandle ; - } - - private boolean validateParentWindowHandle() { - if(null!=parentNativeWindow) { - parentWindowHandle = getNativeWindowHandle(parentNativeWindow); - return 0 != parentWindowHandle ; - } - return true; - } - - private static long getNativeWindowHandle(NativeWindow nativeWindow) { - long handle = 0; - if(null!=nativeWindow) { - boolean locked=false; - try { - if( NativeWindow.LOCK_SURFACE_NOT_READY < nativeWindow.lockSurface() ) { - locked=true; - handle = nativeWindow.getWindowHandle(); - if(0==handle) { - throw new NativeWindowException("Parent native window handle is NULL, after succesful locking: "+nativeWindow); - } - } - } catch (NativeWindowException nwe) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.getNativeWindowHandle: not successful yet: "+nwe); - } - } finally { - if(locked) { - nativeWindow.unlockSurface(); - } - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.getNativeWindowHandle: locked "+locked+", "+nativeWindow); - } - } - return handle; - } - - public void runOnEDTIfAvail(boolean wait, final Runnable task) { - Screen screen = getInnerWindow().getScreen(); - if(null==screen) { - throw new RuntimeException("Null screen of inner class: "+this); - } - Display d = screen.getDisplay(); - d.runOnEDTIfAvail(wait, task); - } - - /** - * Create native windowHandle, ie creates a new native invisible window. - */ - protected abstract void createNativeImpl(); - - protected abstract void closeNativeImpl(); - - public Capabilities getRequestedCapabilities() { - return (Capabilities)caps.clone(); - } - - public NativeWindow getParentNativeWindow() { - return parentNativeWindow; - } - - public Screen getScreen() { - return screen; - } - - public String toString() { - StringBuffer sb = new StringBuffer(); - - sb.append(getClass().getName()+"[Config "+config+ - "\n, "+screen+ - "\n, ParentWindow "+parentNativeWindow+ - "\n, ParentWindowHandle "+toHexString(parentWindowHandle)+ - "\n, WindowHandle "+toHexString(getWindowHandle())+ - "\n, SurfaceHandle "+toHexString(getSurfaceHandle())+ - "\n, Pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ - "\n, Visible "+isVisible()+ - "\n, Undecorated "+undecorated+ - "\n, Fullscreen "+fullscreen+ - "\n, WrappedWindow "+getWrappedWindow()+ - "\n, ChildWindows "+childWindows.size()); - - sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedListeners.size()+" ["); - for (Iterator iter = surfaceUpdatedListeners.iterator(); iter.hasNext(); ) { - sb.append(iter.next()+", "); - } - sb.append("], WindowListeners num "+windowListeners.size()+" ["); - for (Iterator iter = windowListeners.iterator(); iter.hasNext(); ) { - sb.append(iter.next()+", "); - } - sb.append("], MouseListeners num "+mouseListeners.size()+" ["); - for (Iterator iter = mouseListeners.iterator(); iter.hasNext(); ) { - sb.append(iter.next()+", "); - } - sb.append("], KeyListeners num "+keyListeners.size()+" ["); - for (Iterator iter = keyListeners.iterator(); iter.hasNext(); ) { - sb.append(iter.next()+", "); - } - sb.append("] ]"); - return sb.toString(); - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - if (title == null) { - title = ""; - } - this.title = title; - if(0 != windowHandle) { - setTitleImpl(title); - } - } - protected void setTitleImpl(String title) {} - - public void setUndecorated(boolean value) { - undecorated = value; - } - - public boolean isUndecorated(boolean fullscreen) { - return 0 != parentWindowHandle || undecorated || fullscreen ; - } - - public boolean isUndecorated() { - return 0 != parentWindowHandle || undecorated || fullscreen ; - } - - public void requestFocus() { - enqueueRequestFocus(false); // FIXME: or shall we wait ? - } - protected void requestFocusImpl() {} - - class RequestFocusAction implements Runnable { - public void run() { - Window.this.requestFocusImpl(); - } - } - RequestFocusAction requestFocusAction = new RequestFocusAction(); - - public void enqueueRequestFocus(boolean wait) { - runOnEDTIfAvail(wait, requestFocusAction); - } - - /** - * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus. - * This allows notifying a covered window toolkit like AWT that the focus is requested, - * hence focus traversal can be made transparent. - */ - public void setFocusAction(FocusRunnable focusAction) { - this.focusAction = focusAction; - } - protected boolean focusAction() { - if(null!=focusAction) { - return focusAction.run(); - } - return false; - } - protected FocusRunnable focusAction = null; - - public static interface FocusRunnable { - /** - * @return false if NEWT shall proceed requesting the focus, - * true if NEWT shall not request the focus. - */ - public boolean run(); - } // - // NativeWindow impl + // Lifecycle // - /** Recursive and blocking lockSurface() implementation */ - public int lockSurface() { - // We leave the ToolkitLock lock to the specializtion's discretion, - // ie the implicit JAWTWindow in case of AWTWindow - - windowLock.lock(); - - // if(windowLock.getRecursionCount() == 0) { // allow recursion to lock again, always - if(!isNativeValid()) { - windowLock.unlock(); - return LOCK_SURFACE_NOT_READY; - } - // } - return LOCK_SUCCESS; - } - - /** Recursive and unblocking unlockSurface() implementation */ - public void unlockSurface() throws NativeWindowException { - windowLock.unlock(); - // We leave the ToolkitLock unlock to the specializtion's discretion, - // ie the implicit JAWTWindow in case of AWTWindow - } - - public boolean isSurfaceLocked() { - return windowLock.isLocked(); - } - - public Thread getSurfaceLockOwner() { - return windowLock.getOwner(); - } - - public Exception getLockedStack() { - return windowLock.getLockedStack(); - } - - /** - *

- * destroys the window and children and releases - * windowing related resources.

- *

- * all other resources and states are kept intact, - * ie listeners, parent handles, size, position and Screen reference.

+ /** + * @return True if native window is valid, can be created or recovered. + * Otherwise false, ie this window is unrecoverable due to a destroy(true) call. * * @see #destroy(boolean) - * @see #invalidate() - */ - public final void destroy() { - destroy(false); - } - - /** - * Destroys the Window and it's children. - * @param unrecoverable If true, all resources, ie listeners, parent handles, - * size, position and reference to it's Screen will be destroyed as well. - * Otherwise you can recreate the window, via setVisible(true). - * @see #destroy() - * @see #invalidate(boolean) * @see #setVisible(boolean) */ - public void destroy(boolean unrecoverable) { - if(isValid()) { - if(DEBUG_IMPLEMENTATION) { - String msg = new String("Window.destroy(unrecoverable: "+unrecoverable+") START "+getThreadName()+", "+this); - //System.err.println(msg); - Exception ee = new Exception(msg); - ee.printStackTrace(); - } - runOnEDTIfAvail(true, new DestroyAction(unrecoverable)); - } - } - - class DestroyAction implements Runnable { - boolean unrecoverable; - public DestroyAction(boolean unrecoverable) { - this.unrecoverable = unrecoverable; - } - public void run() { - windowLock(); - try { - // Childs first .. - synchronized(childWindowsLock) { - for(Iterator i = childWindows.iterator(); i.hasNext(); ) { - NativeWindow nw = (NativeWindow) i.next(); - System.err.println("Window.destroy(unrecoverable: "+unrecoverable+") CHILD BEGIN"); - if(nw instanceof Window) { - ((Window)nw).sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); - if(unrecoverable) { - ((Window)nw).destroy(unrecoverable); - } - } else { - nw.destroy(); - } - System.err.println("Window.destroy(unrecoverable: "+unrecoverable+") CHILD END"); - } - } - - // Now us .. - if(unrecoverable) { - synchronized(childWindowsLock) { - childWindows = new ArrayList(); - } - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners = new ArrayList(); - } - windowListeners = new ArrayList(); - mouseListeners = new ArrayList(); - keyListeners = new ArrayList(); - } - if( null != screen && 0 != windowHandle ) { - closeNativeImpl(); - } - invalidate(unrecoverable); - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.destroy(unrecoverable: "+unrecoverable+") END "+getThreadName()+", "+Window.this); - } - } finally { - windowUnlock(); - } - } - } - - /** - *

- * render all native window information invalid, - * as if the native window was destroyed.

- *

- * all other resources and states are kept intact, - * ie listeners, parent handles and size, position etc.

- * - * @see #destroy() - * @see #destroy(boolean) - * @see #invalidate(boolean) - */ - public void invalidate() { - invalidate(false); - } + boolean isValid(); /** - * @param unrecoverable If true, all states, size, position, parent handles, - * reference to it's Screen are reset. - * Otherwise you can recreate the window, via setVisible(true). - * @see #invalidate() - * @see #destroy() - * @see #destroy(boolean) - */ - protected void invalidate(boolean unrecoverable) { - windowLock(); - try{ - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - String msg = new String("!!! Window Invalidate(unrecoverable: "+unrecoverable+") "+getThreadName()); - System.err.println(msg); - // Exception e = new Exception(msg); - // e.printStackTrace(); - } - windowHandle = 0; - visible = false; - fullscreen = false; - - if(unrecoverable) { - System.err.println("Window.invalidate: 1 "+screen); - if(null!=screen) { - screenReferenced = false; - screen.removeReference(); - } - screen = null; - System.err.println("Window.invalidate: 2 "+screen); - parentWindowHandle = 0; - parentNativeWindow = null; - caps = null; - - // Default position and dimension will be re-set immediately by user - width = 128; - height = 128; - x=0; - y=0; - } - } finally { - windowUnlock(); - } - } - - /** @return true if the native window handle is valid and ready to operate, ie - * if the native window has been created, otherwise false. + * @return true if the native window handle is valid and ready to operate, ie + * if the native window has been created, otherwise false. * * @see #setVisible(boolean) * @see #destroy(boolean) */ - public boolean isNativeValid() { - return null != screen && 0 != windowHandle ; - } - - /** @return True if native window is valid, can be created or recovered. - * Otherwise false, ie this window is unrecoverable due to a destroy(true) call. - * - * @see #destroy(boolean) - * @see #setVisible(boolean) - */ - public boolean isValid() { - return null != screen ; - } - - public boolean surfaceSwap() { - return false; - } - - public long getDisplayHandle() { - return screen.getDisplay().getHandle(); - } - - public int getScreenIndex() { - return screen.getIndex(); - } - - public long getWindowHandle() { - return windowHandle; - } - - public long getSurfaceHandle() { - return windowHandle; // default: return window handle - } - - public AbstractGraphicsConfiguration getGraphicsConfiguration() { - return config; - } + boolean isNativeValid(); /** - * Returns the width of the client area of this window - * @return width of the client area + * @return The associated Screen */ - public int getWidth() { - return width; - } + Screen getScreen(); /** - * Returns the height of the client area of this window - * @return height of the client area + * @return The NativeWindow representation of the parent Window, + * or null if this Window is top level */ - public int getHeight() { - return height; - } + NativeWindow getParentNativeWindow(); /** - * Returns the insets for this native window (the difference between the - * size of the toplevel window with the decorations and the client area). - * - * @return insets for this platform window + * @return The requested capabilities */ - // this probably belongs to NativeWindow interface - public Insets getInsets() { - return new Insets(0,0,0,0); - } + Capabilities getRequestedCapabilities(); - /** Returns the most inner Window instance.
- Currently only {@link com.jogamp.newt.opengl.GLWindow} - has an aggregation to an inner Window instance. - */ - public Window getInnerWindow() { - return this; - } - - /** If this Window actually wraps one from another toolkit such as - the AWT, this will return a non-null value. */ - public Object getWrappedWindow() { - return null; - } - - // - // Additional methods - // - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public boolean isVisible() { - return visible; - } - - public boolean isFullscreen() { - return fullscreen; - } - - private boolean handleDestroyNotify = true; - - /** If the implementation is capable of detecting a device change - return true and clear the status/reason of the change. */ - public boolean hasDeviceChanged() { - return false; - } - - class ReparentAction implements Runnable { - /** No native reparenting action */ - static final int ACTION_NONE = 0; - - /** Change Window tree only */ - static final int ACTION_SOFT_REPARENTING = 1; - - /** Native reparenting incl. Window tree */ - static final int ACTION_NATIVE_REPARENTING = 2; - - /** Native window creation after tree change - instead of reparenting. */ - static final int ACTION_NATIVE_CREATION = 3; - - NativeWindow newParent; - public ReparentAction(NativeWindow newParent) { - this.newParent = newParent; - } - public void run() { - windowLock(); - try{ - Window newParentWindow = null; - if(newParent instanceof Window) { - newParentWindow = (Window) newParent; - } - - int reparentAction = -1; // ensure it's set - long newParentHandle = 0 ; - - if(null!=newParent) { - // Case: Child Window - newParentHandle = getNativeWindowHandle(newParent); - if(0 == newParentHandle) { - // Case: Parent's native window not realized yet - if(null==newParentWindow) { - throw new NativeWindowException("Parent not NEWT Window and not realized yet: "+newParent); - } - // Destroy this window (handle screen + native) and use parent's Screen. - // It may be created properly when the parent is made visible. - destroy(false); - screen = newParentWindow.getScreen(); - reparentAction = ACTION_SOFT_REPARENTING; - } else if(newParent != parentNativeWindow) { - // Case: Parent's native window realized and changed - if( !isNativeValid() ) { - // May create a new compatible Screen/Display and - // mark it for creation. - if(null!=newParentWindow) { - screen = newParentWindow.getScreen(); - } else { - Screen newScreen = NewtFactory.createCompatibleScreen(newParent, screen); - if( screen != newScreen ) { - // auto destroy on-the-fly created Screen/Display - newScreen.setDestroyWhenUnused(true); - screen = newScreen; - } - } - reparentAction = ACTION_NATIVE_CREATION; - } else if ( DEBUG_TEST_REPARENT_INCOMPATIBLE || !NewtFactory.isScreenCompatible(newParent, screen) ) { - // Destroy this window (handle screen + native) and - // may create a new compatible Screen/Display and - // mark it for creation. - destroy(false); - if(null!=newParentWindow) { - screen = newParentWindow.getScreen(); - } else { - screen = NewtFactory.createCompatibleScreen(newParent, screen); - screen.setDestroyWhenUnused(true); - } - reparentAction = ACTION_NATIVE_CREATION; - } else { - // Mark it for native reparenting - reparentAction = ACTION_NATIVE_REPARENTING; - } - } else { - // Case: Parent's native window realized and not changed - reparentAction = ACTION_NONE; - } - } else { - // Case: Top Window - if( 0 == parentWindowHandle ) { - // Already Top Window - reparentAction = ACTION_NONE; - } else { - // Mark it for native reparenting - reparentAction = ACTION_NATIVE_REPARENTING; - } - } - - if ( ACTION_NONE > reparentAction ) { - throw new NativeWindowException("Internal Error: reparentAction not set"); - } - - if( ACTION_NONE == reparentAction ) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("reparent: NO CHANGE ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentHandle)+", visible "+visible+", parentNativeWindow "+(null!=parentNativeWindow)); - } - return; - } - - if(DEBUG_IMPLEMENTATION) { - System.err.println("reparent: START ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentHandle)+", reparentAction "+reparentAction+", visible "+visible+", parentNativeWindow "+(null!=parentNativeWindow)); - } - - // rearrange window tree - if(null!=parentNativeWindow && parentNativeWindow instanceof Window) { - ((Window)parentNativeWindow).getInnerWindow().removeChild(Window.this); - } - parentNativeWindow = newParent; - if(parentNativeWindow instanceof Window) { - ((Window)parentNativeWindow).getInnerWindow().addChild(Window.this); - } - - if( ACTION_SOFT_REPARENTING == reparentAction ) { - return; - } - - if( ACTION_NATIVE_REPARENTING == reparentAction ) { - Display display = screen.getDisplay(); - - parentWindowHandle = newParentHandle; - if(0!=parentWindowHandle) { - // reset position to 0/0 within parent space - // FIXME .. cache position ? - x = 0; - y = 0; - } - getScreen().getDisplay().dispatchMessages(); // status up2date - boolean wasVisible = isVisible(); - if(wasVisible) { - Window.this.visible = false; - setVisibleImpl(false); - display.dispatchMessages(); // status up2date - } - boolean ok = reparentWindowImpl(); - display.dispatchMessages(); // status up2date - if ( !ok ) { - // native reparent failed -> try creation - if(DEBUG_IMPLEMENTATION) { - System.err.println("reparent: native reparenting failed ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentHandle)+" - Trying recreation"); - } - destroy(false); - Window.this.visible = wasVisible; - reparentAction = ACTION_NATIVE_CREATION ; - } else { - if(wasVisible) { - Window.this.visible = true; - setVisibleImpl(true); - requestFocusImpl(); - display.dispatchMessages(); // status up2date - } - } - } - - // not-else: re-entrance via reparentAction value change possible - if( ACTION_NATIVE_CREATION == reparentAction ) { - if(isVisible()) { - setVisible(true); // native creation - screen.getDisplay().dispatchMessages(); // status up2date - } - } - - if(DEBUG_IMPLEMENTATION) { - System.err.println("reparentWindow: END ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentNativeWindow "+(null!=parentNativeWindow)); - } - } finally { - windowUnlock(); - } - } - } + Capabilities getChosenCapabilities(); /** - * Change this window's parent window.
- *

- * In case the old parent is not null and a Window, - * this window is removed from it's list of children.
- * In case the new parent is not null and a Window, - * this window is added to it's list of children.

* - * @param newParent The new parent NativeWindow. If null, this Window becomes a top level window. + *

+ * destroys the window and children and releases + * windowing related resources.

+ *

+ * all other resources and states are kept intact, + * ie listeners, parent handles, size, position and Screen reference.

+ * + * @see #destroy(boolean) + * @see #invalidate() */ - public void reparentWindow(NativeWindow newParent) { - if(isValid()) { - runOnEDTIfAvail(true, new ReparentAction(newParent)); - if( isVisible() ) { - sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener - windowRepaint(0, 0, getWidth(), getHeight()); - } - } - } + void destroy(); - class VisibleAction implements Runnable { - boolean visible; - public VisibleAction(boolean visible) { - this.visible = visible; - } - public void run() { - windowLock(); - try{ - if( isValid() ) { - if(!visible && childWindows.size()>0) { - synchronized(childWindowsLock) { - for(Iterator i = childWindows.iterator(); i.hasNext(); ) { - NativeWindow nw = (NativeWindow) i.next(); - if(nw instanceof Window) { - ((Window)nw).setVisible(false); - } - } - } - } - if(0==windowHandle && visible) { - Window.this.visible = visible; - if( 00) { - synchronized(childWindowsLock) { - for(Iterator i = childWindows.iterator(); i.hasNext(); ) { - NativeWindow nw = (NativeWindow) i.next(); - if(nw instanceof Window) { - ((Window)nw).setVisible(true); - } - } - } - } - } - - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window setVisible: END ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+Window.this.visible); - } - } finally { - windowUnlock(); - } - } - } + /** + * + * Destroys the Window and it's children. + * @param unrecoverable If true, all resources, ie listeners, parent handles, + * size, position and reference to it's Screen will be destroyed as well. + * Otherwise you can recreate the window, via setVisible(true). + * @see #destroy() + * @see #invalidate(boolean) + * @see #setVisible(boolean) + */ + void destroy(boolean unrecoverable); /** *

@@ -889,14 +123,14 @@ public abstract class Window implements NativeWindow, NEWTEventConsumer *

* Zero size semantics are respected, see {@link #setSize(int,int)}:
*

-     * if ( 0 == windowHandle && visible ) { 
-     *      this.visible = visible;
-     *      if( 0

*

@@ -905,18 +139,21 @@ public abstract class Window implements NativeWindow, NEWTEventConsumer * If this action fails, ie if the parent {@link javax.media.nativewindow.NativeWindow} is not valid yet,
* no native window is created yet and setVisible(true) shall be repeated when it is.

*/ - public void setVisible(boolean visible) { - if(DEBUG_IMPLEMENTATION) { - String msg = new String("Window setVisible: START ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+this.visible+" -> "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentNativeWindow "+(null!=parentNativeWindow)); - //System.err.println(msg); - Exception ee = new Exception(msg); - ee.printStackTrace(); - } - if(isValid()) { - runOnEDTIfAvail(true, new VisibleAction(visible)); - } - } - protected abstract void setVisibleImpl(boolean visible); + void setVisible(boolean visible); + + boolean isVisible(); + + // + // Child Window Management + // + + void addChild(NativeWindow win); + + void removeChild(NativeWindow win); + + // + // Modes / States + // /** * Sets the size of the client area of the window, excluding decorations @@ -926,11 +163,11 @@ public abstract class Window implements NativeWindow, NEWTEventConsumer * Zero size semantics are respected, see {@link #setVisible(boolean)}:
*
      * if ( 0 != windowHandle && 0>=width*height && visible ) {
-     *      setVisible(false);
+     * setVisible(false);
      * } else if ( 0 == windowHandle && 0

*

@@ -939,48 +176,57 @@ public abstract class Window implements NativeWindow, NEWTEventConsumer * @param width of the client area of the window * @param height of the client area of the window */ - public void setSize(int width, int height) { - int visibleAction = 0; // 1 invisible, 2 visible - windowLock(); - try{ - if(DEBUG_IMPLEMENTATION) { - String msg = new String("Window setSize: START "+this.width+"x"+this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible); - System.err.println(msg); - // Exception e = new Exception(msg); - // e.printStackTrace(); - } - if (width != this.width || this.height != height) { - if(!fullscreen) { - nfs_width=width; - nfs_height=height; - if ( 0 != windowHandle && 0>=width*height && visible ) { - visibleAction=1; // invisible - this.width = 0; - this.height = 0; - } else if ( 0 == windowHandle && 00) { - setVisible( ( 1 == visibleAction ) ? false : true ); - } + void setSize(int width, int height); + + /** + * Returns the width of the client area of this window + * @return width of the client area + */ + int getWidth(); + + /** + * Returns the height of the client area of this window + * @return height of the client area + */ + int getHeight(); + + /** Defining ids for the reparenting strategy */ + public interface ReparentAction { + /** No native reparenting valid */ + static final int ACTION_INVALID = -1; + + /** No native reparenting action required, no change*/ + static final int ACTION_UNCHANGED = 0; + + /** Native reparenting incl. Window tree */ + static final int ACTION_NATIVE_REPARENTING = 1; + + /** Native window creation after tree change - instead of reparenting. */ + static final int ACTION_NATIVE_CREATION = 2; + + /** Change Window tree only, native creation is pending */ + static final int ACTION_NATIVE_CREATION_PENDING = 3; } - protected abstract void setSizeImpl(int width, int height); + + /** + * Change this window's parent window.
+ *

+ * In case the old parent is not null and a Window, + * this window is removed from it's list of children.
+ * In case the new parent is not null and a Window, + * this window is added to it's list of children.

+ * + * @param newParent The new parent NativeWindow. If null, this Window becomes a top level window. + * + * @return The issued reparent action type (strategy) as defined in Window.ReparentAction + */ + int reparentWindow(NativeWindow newParent); + + int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate); + + boolean setFullscreen(boolean fullscreen); + + boolean isFullscreen(); /** * Sets the location of the top left corner of the window, including @@ -992,774 +238,176 @@ public abstract class Window implements NativeWindow, NEWTEventConsumer * @param x coord of the top left corner * @param y coord of the top left corner */ - public void setPosition(int x, int y) { - windowLock(); - try{ - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window setPosition: "+this.x+"/"+this.y+" -> "+x+"/"+y+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)); - } - if ( this.x != x || this.y != y ) { - if(!fullscreen) { - nfs_x=x; - nfs_y=y; - if(0!=windowHandle) { - // this x/y will be set by windowChanged, called by X11 - setPositionImpl(x, y); - } else { - this.x = x; - this.y = y; - } - } - } - } finally { - windowUnlock(); - } - } - protected abstract void setPositionImpl(int x, int y); - - public boolean setFullscreen(boolean fullscreen) { - windowLock(); - try{ - if(0!=windowHandle && this.fullscreen!=fullscreen) { - int x,y,w,h; - if(fullscreen) { - x = 0; y = 0; - w = screen.getWidth(); - h = screen.getHeight(); - } else { - if(0!=parentWindowHandle) { - x=0; - y=0; - } else { - x = nfs_x; - y = nfs_y; - } - w = nfs_width; - h = nfs_height; - } - if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("X11Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()); - } - this.fullscreen = fullscreen; - setFullscreenImpl(fullscreen, x, y, w, h); - } - } finally { - windowUnlock(); - } - if( isVisible() ) { - windowRepaint(0, 0, getWidth(), getHeight()); - } - return this.fullscreen; - } - protected abstract void setFullscreenImpl(boolean fullscreen, int x, int y, int widht, int height); + void setPosition(int x, int y); + + int getX(); - // - // Child Window Management - // + int getY(); - private ArrayList childWindows = new ArrayList(); - private Object childWindowsLock = new Object(); + /** + * Returns the insets for this native window (the difference between the + * size of the toplevel window with the decorations and the client area). + * + * @return insets for this platform window + */ + Insets getInsets(); - protected void removeChild(NativeWindow win) { - synchronized(childWindowsLock) { - childWindows.remove(win); - } - } + void setUndecorated(boolean value); + + boolean isUndecorated(); + + void setTitle(String title); - protected void addChild(NativeWindow win) { - if (win == null) { - return; - } - synchronized(childWindowsLock) { - childWindows.add(win); - } + String getTitle(); + + static interface FocusRunnable { + /** + * @return false if NEWT shall proceed requesting the focus, + * true if NEWT shall not request the focus. + */ + public boolean run(); } - // - // Generic Event Support - // - private void doEvent(boolean enqueue, boolean wait, com.jogamp.newt.event.NEWTEvent event) { - boolean done = false; + /** + * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus. + * This allows notifying a covered window toolkit like AWT that the focus is requested, + * hence focus traversal can be made transparent. + */ + void setFocusAction(FocusRunnable focusAction); - if(!enqueue) { - done = consumeEvent(event); - wait = done; // don't wait if event can't be consumed now - } + void requestFocus(); - if(!done) { - enqueueEvent(wait, event); - } - } + void windowRepaint(int x, int y, int width, int height); - public void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { - if(getInnerWindow().isValid()) { - getInnerWindow().getScreen().getDisplay().enqueueEvent(wait, event); - } - } + void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event); + + void runOnEDTIfAvail(boolean wait, final Runnable task); - public boolean consumeEvent(NEWTEvent e) { - switch(e.getEventType()) { - case WindowEvent.EVENT_WINDOW_REPAINT: - if( windowIsLocked() ) { - // make sure only one repaint event is queued - if(!repaintQueued) { - repaintQueued=true; - return false; - } - return true; - } - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.windowRepaint: "+e); - // Exception ee = new Exception("Window.windowRepaint: "+e); - // ee.printStackTrace(); - } - repaintQueued=false; // no repaint event queued - break; - default: - break; - } - if(e instanceof WindowEvent) { - getInnerWindow().consumeWindowEvent((WindowEvent)e); - } else if(e instanceof KeyEvent) { - getInnerWindow().consumeKeyEvent((KeyEvent)e); - } else if(e instanceof MouseEvent) { - getInnerWindow().consumeMouseEvent((MouseEvent)e); - } else { - throw new NativeWindowException("Unexpected NEWTEvent type " + e); - } - return true; - } - protected boolean repaintQueued = false; // - // SurfaceUpdatedListener Support + // SurfaceUpdateListener // - private ArrayList surfaceUpdatedListeners = new ArrayList(); - private Object surfaceUpdatedListenersLock = new Object(); - - /** - * Appends the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} to the end of + /** + * Appends the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} to the end of * the list. */ - public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { - getInnerWindow().addSurfaceUpdatedListener(-1, l); - } + void addSurfaceUpdatedListener(SurfaceUpdatedListener l); - /** - * Inserts the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} at the + /** + * + * Inserts the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} at the * specified position in the list.
- - * @param index Position where the listener will be inserted. - * Should be within (0 <= index && index <= size()). - * An index value of -1 is interpreted as the end of the list, size(). + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). * @param l The listener object to be inserted * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 */ - public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) - throws IndexOutOfBoundsException - { - if(l == null) { - return; - } - synchronized(surfaceUpdatedListenersLock) { - if(0>index) { - index = surfaceUpdatedListeners.size(); - } - surfaceUpdatedListeners.add(index, l); - } - } + void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException; - public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { - if (l == null) { - return; - } - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners.remove(l); - } - } + void removeAllSurfaceUpdatedListener(); - public void removeAllSurfaceUpdatedListener() { - synchronized(surfaceUpdatedListenersLock) { - surfaceUpdatedListeners = new ArrayList(); - } - } + void removeSurfaceUpdatedListener(SurfaceUpdatedListener l); - public SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { - synchronized(surfaceUpdatedListenersLock) { - if(0>index) { - index = surfaceUpdatedListeners.size()-1; - } - return (SurfaceUpdatedListener) surfaceUpdatedListeners.get(index); - } - } + SurfaceUpdatedListener getSurfaceUpdatedListener(int index); - public SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { - synchronized(surfaceUpdatedListenersLock) { - return (SurfaceUpdatedListener[]) surfaceUpdatedListeners.toArray(); - } - } + SurfaceUpdatedListener[] getSurfaceUpdatedListeners(); - public void surfaceUpdated(Object updater, NativeWindow window, long when) { - synchronized(surfaceUpdatedListenersLock) { - for(Iterator i = surfaceUpdatedListeners.iterator(); i.hasNext(); ) { - SurfaceUpdatedListener l = (SurfaceUpdatedListener) i.next(); - l.surfaceUpdated(updater, window, when); - } - } - } // - // MouseListener/Event Support + // WindowListener // - private ArrayList mouseListeners = new ArrayList(); - private int mouseButtonPressed = 0; // current pressed mouse button number - private long lastMousePressed = 0; // last time when a mouse button was pressed - private int lastMouseClickCount = 0; // last mouse button click count - public static final int ClickTimeout = 300; - - public void sendMouseEvent(int eventType, int modifiers, - int x, int y, int button, int rotation) { - doMouseEvent(false, false, eventType, modifiers, x, y, button, rotation); - } - public void enqueueMouseEvent(boolean wait, int eventType, int modifiers, - int x, int y, int button, int rotation) { - doMouseEvent(true, wait, eventType, modifiers, x, y, button, rotation); - } - private void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers, - int x, int y, int button, int rotation) { - if(x<0||y<0||x>=width||y>=height) { - return; // .. invalid .. - } - if(DEBUG_MOUSE_EVENT) { - System.err.println("doMouseEvent: enqueue"+enqueue+", wait "+wait+", "+MouseEvent.getEventTypeString(eventType)+ - ", mod "+modifiers+", pos "+x+"/"+y+", button "+button); - } - if(button<0||button>MouseEvent.BUTTON_NUMBER) { - throw new NativeWindowException("Invalid mouse button number" + button); - } - long when = System.currentTimeMillis(); - MouseEvent eClicked = null; - MouseEvent e = null; - - if(MouseEvent.EVENT_MOUSE_PRESSED==eventType) { - if(when-lastMousePressed0) { - e = new MouseEvent(MouseEvent.EVENT_MOUSE_DRAGGED, this, when, - modifiers, x, y, 1, mouseButtonPressed, 0); - } else { - e = new MouseEvent(eventType, this, when, - modifiers, x, y, 0, button, 0); - } - } else if(MouseEvent.EVENT_MOUSE_WHEEL_MOVED==eventType) { - e = new MouseEvent(eventType, this, when, modifiers, x, y, 0, button, rotation); - } else { - e = new MouseEvent(eventType, this, when, modifiers, x, y, 0, button, 0); - } - doEvent(enqueue, wait, e); - if(null!=eClicked) { - if(DEBUG_MOUSE_EVENT) { - System.err.println("doMouseEvent: synthesized MOUSE_CLICKED event"); - } - doEvent(enqueue, wait, eClicked); - } - } + public void sendWindowEvent(int eventType); - /** - * Appends the given {@link com.jogamp.newt.event.MouseListener} to the end of + /** + * + * Appends the given {@link com.jogamp.newt.event.WindowListener} to the end of * the list. */ - public void addMouseListener(MouseListener l) { - getInnerWindow().addMouseListener(-1, l); - } + void addWindowListener(WindowListener l); - /** - * Inserts the given {@link com.jogamp.newt.event.MouseListener} at the + /** + * + * Inserts the given {@link com.jogamp.newt.event.WindowListener} at the * specified position in the list.
- - * @param index Position where the listener will be inserted. - * Should be within (0 <= index && index <= size()). - * An index value of -1 is interpreted as the end of the list, size(). + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). * @param l The listener object to be inserted * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 */ - public void addMouseListener(int index, MouseListener l) { - if(l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); - if(0>index) { - index = clonedListeners.size(); - } - clonedListeners.add(index, l); - mouseListeners = clonedListeners; - } - - public void removeMouseListener(MouseListener l) { - if (l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); - clonedListeners.remove(l); - mouseListeners = clonedListeners; - } + void addWindowListener(int index, WindowListener l) throws IndexOutOfBoundsException; - public MouseListener getMouseListener(int index) { - ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); - if(0>index) { - index = clonedListeners.size()-1; - } - return (MouseListener) clonedListeners.get(index); - } + void removeWindowListener(WindowListener l); - public MouseListener[] getMouseListeners() { - return (MouseListener[]) mouseListeners.toArray(); - } + WindowListener getWindowListener(int index); - protected void consumeMouseEvent(MouseEvent e) { - if(DEBUG_MOUSE_EVENT) { - System.err.println("consumeMouseEvent: event: "+e); - } - - for(Iterator i = mouseListeners.iterator(); i.hasNext(); ) { - MouseListener l = (MouseListener) i.next(); - switch(e.getEventType()) { - case MouseEvent.EVENT_MOUSE_CLICKED: - l.mouseClicked(e); - break; - case MouseEvent.EVENT_MOUSE_ENTERED: - l.mouseEntered(e); - break; - case MouseEvent.EVENT_MOUSE_EXITED: - l.mouseExited(e); - break; - case MouseEvent.EVENT_MOUSE_PRESSED: - l.mousePressed(e); - break; - case MouseEvent.EVENT_MOUSE_RELEASED: - l.mouseReleased(e); - break; - case MouseEvent.EVENT_MOUSE_MOVED: - l.mouseMoved(e); - break; - case MouseEvent.EVENT_MOUSE_DRAGGED: - l.mouseDragged(e); - break; - case MouseEvent.EVENT_MOUSE_WHEEL_MOVED: - l.mouseWheelMoved(e); - break; - default: - throw new NativeWindowException("Unexpected mouse event type " + e.getEventType()); - } - } - } + WindowListener[] getWindowListeners(); // - // KeyListener/Event Support + // KeyListener // - public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { - consumeKeyEvent(new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) ); - } - - public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) { - enqueueEvent(wait, new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) ); - } - /** - * Appends the given {@link com.jogamp.newt.event.KeyListener} to the end of + /** + * + * Appends the given {@link com.jogamp.newt.event.KeyListener} to the end of * the list. */ - public void addKeyListener(KeyListener l) { - getInnerWindow().addKeyListener(-1, l); - } + void addKeyListener(KeyListener l); - /** - * Inserts the given {@link com.jogamp.newt.event.KeyListener} at the + /** + * + * Inserts the given {@link com.jogamp.newt.event.KeyListener} at the * specified position in the list.
- - * @param index Position where the listener will be inserted. - * Should be within (0 <= index && index <= size()). - * An index value of -1 is interpreted as the end of the list, size(). + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). * @param l The listener object to be inserted * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 */ - public void addKeyListener(int index, KeyListener l) { - if(l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) keyListeners.clone(); - if(0>index) { - index = clonedListeners.size(); - } - clonedListeners.add(index, l); - keyListeners = clonedListeners; - } + void addKeyListener(int index, KeyListener l); - public void removeKeyListener(KeyListener l) { - if (l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) keyListeners.clone(); - clonedListeners.remove(l); - keyListeners = clonedListeners; - } + void removeKeyListener(KeyListener l); - public KeyListener getKeyListener(int index) { - ArrayList clonedListeners = (ArrayList) keyListeners.clone(); - if(0>index) { - index = clonedListeners.size()-1; - } - return (KeyListener) clonedListeners.get(index); - } + KeyListener getKeyListener(int index); - public KeyListener[] getKeyListeners() { - return (KeyListener[]) keyListeners.toArray(); - } + KeyListener[] getKeyListeners(); - private ArrayList keyListeners = new ArrayList(); - - protected void consumeKeyEvent(KeyEvent e) { - if(DEBUG_KEY_EVENT) { - System.err.println("consumeKeyEvent: "+e); - } - for(Iterator i = keyListeners.iterator(); i.hasNext(); ) { - KeyListener l = (KeyListener) i.next(); - switch(e.getEventType()) { - case KeyEvent.EVENT_KEY_PRESSED: - l.keyPressed(e); - break; - case KeyEvent.EVENT_KEY_RELEASED: - l.keyReleased(e); - break; - case KeyEvent.EVENT_KEY_TYPED: - l.keyTyped(e); - break; - default: - throw new NativeWindowException("Unexpected key event type " + e.getEventType()); - } - } - } // - // WindowListener/Event Support + // MouseListener // - public void sendWindowEvent(int eventType) { - consumeWindowEvent( new WindowEvent(eventType, this, System.currentTimeMillis()) ); - } - - public void enqueueWindowEvent(boolean wait, int eventType) { - enqueueEvent( wait, new WindowEvent(eventType, this, System.currentTimeMillis()) ); - } - private ArrayList windowListeners = new ArrayList(); - - /** - * Appends the given {@link com.jogamp.newt.event.WindowListener} to the end of + /** + * + * Appends the given {@link com.jogamp.newt.event.MouseListener} to the end of * the list. */ - public void addWindowListener(WindowListener l) { - getInnerWindow().addWindowListener(-1, l); - } + void addMouseListener(MouseListener l); - /** - * Inserts the given {@link com.jogamp.newt.event.WindowListener} at the + /** + * + * Inserts the given {@link com.jogamp.newt.event.MouseListener} at the * specified position in the list.
- - * @param index Position where the listener will be inserted. - * Should be within (0 <= index && index <= size()). - * An index value of -1 is interpreted as the end of the list, size(). + * + * @param index Position where the listener will be inserted. + * Should be within (0 <= index && index <= size()). + * An index value of -1 is interpreted as the end of the list, size(). * @param l The listener object to be inserted * @throws IndexOutOfBoundsException If the index is not within (0 <= index && index <= size()), or -1 */ - public void addWindowListener(int index, WindowListener l) - throws IndexOutOfBoundsException - { - if(l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) windowListeners.clone(); - if(0>index) { - index = clonedListeners.size(); - } - clonedListeners.add(index, l); - windowListeners = clonedListeners; - } + void addMouseListener(int index, MouseListener l); - public void removeWindowListener(WindowListener l) { - if (l == null) { - return; - } - ArrayList clonedListeners = (ArrayList) windowListeners.clone(); - clonedListeners.remove(l); - windowListeners = clonedListeners; - } - - public WindowListener getWindowListener(int index) { - ArrayList clonedListeners = (ArrayList) windowListeners.clone(); - if(0>index) { - index = clonedListeners.size()-1; - } - return (WindowListener) clonedListeners.get(index); - } + void removeMouseListener(MouseListener l); - public WindowListener[] getWindowListeners() { - return (WindowListener[]) windowListeners.toArray(); - } - - protected void consumeWindowEvent(WindowEvent e) { - if(DEBUG_WINDOW_EVENT) { - System.err.println("consumeWindowEvent: "+e); - } - for(Iterator i = windowListeners.iterator(); i.hasNext(); ) { - WindowListener l = (WindowListener) i.next(); - switch(e.getEventType()) { - case WindowEvent.EVENT_WINDOW_RESIZED: - l.windowResized(e); - break; - case WindowEvent.EVENT_WINDOW_MOVED: - l.windowMoved(e); - break; - case WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY: - l.windowDestroyNotify(e); - break; - case WindowEvent.EVENT_WINDOW_GAINED_FOCUS: - l.windowGainedFocus(e); - break; - case WindowEvent.EVENT_WINDOW_LOST_FOCUS: - l.windowLostFocus(e); - break; - case WindowEvent.EVENT_WINDOW_REPAINT: - l.windowRepaint((WindowUpdateEvent)e); - break; - default: - throw - new NativeWindowException("Unexpected window event type " - + e.getEventType()); - } - } - } + MouseListener getMouseListener(int index); - /** - * @param focusGained - */ - protected void focusChanged(boolean focusGained) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.focusChanged: "+focusGained); - } - if (focusGained) { - sendWindowEvent(WindowEvent.EVENT_WINDOW_GAINED_FOCUS); - } else { - sendWindowEvent(WindowEvent.EVENT_WINDOW_LOST_FOCUS); - } - } - - protected void visibleChanged(boolean visible) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.visibleChanged ("+getThreadName()+"): "+this.visible+" -> "+visible+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); - // Exception e = new Exception("Window.visibleChanged ("+getThreadName()+"): "+this.visible+" -> "+visible+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); - // e.printStackTrace(); - } - this.visible = visible ; - } + MouseListener[] getMouseListeners(); - protected void sizeChanged(int newWidth, int newHeight) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.sizeChanged: "+width+"x"+height+" -> "+newWidth+"x"+newHeight); - } - if(width != newWidth || height != newHeight) { - width = newWidth; - height = newHeight; - if(!fullscreen) { - nfs_width=width; - nfs_height=height; - } - sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); - } - } - - protected void positionChanged(int newX, int newY) { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.positionChanged: "+x+"/"+y+" -> "+newX+"/"+newY); - } - if( 0==parentWindowHandle && ( x != newX || y != newY ) ) { - x = newX; - y = newY; - if(!fullscreen) { - nfs_x=x; - nfs_y=y; - } - sendWindowEvent(WindowEvent.EVENT_WINDOW_MOVED); - } - } - - /** - * If set to true, the default value, this NEWT Window implementation will - * handle the destruction (ie {@link #destroy()} call) within {@link #windowDestroyNotify()} implementation.
- * If set to false, it's up to the caller/owner to handle destruction within {@link #windowDestroyNotify()}. - */ - public void setHandleDestroyNotify(boolean b) { - handleDestroyNotify = b; - } - - protected void windowDestroyNotify() { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.windowDestroyNotify START "+getThreadName()); - } - - enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); - - if(handleDestroyNotify && isValid()) { - destroy(); - } - - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.windowDestroyeNotify END "+getThreadName()); - } - } - - protected void windowDestroyed() { - if(DEBUG_IMPLEMENTATION) { - System.err.println("Window.windowDestroyed "+getThreadName()); - } - invalidate(); - } - - public boolean getPropagateRepaint() { - return propagateRepaint; - } - public void setPropagateRepaint(boolean v) { - propagateRepaint = v; - } - protected boolean propagateRepaint = true; - - public void windowRepaint(int x, int y, int width, int height) { - if(!propagateRepaint) { - return; - } - if(0>width) { - width=this.width; - } - if(0>height) { - height=this.height; - } - - NEWTEvent e = new WindowUpdateEvent(WindowEvent.EVENT_WINDOW_REPAINT, this, System.currentTimeMillis(), - new Rectangle(x, y, width, height)); - doEvent(false, false, e); - } - - protected boolean reparentWindowImpl() { - // default implementation, no native reparenting support - return false; - } - - // - // Reflection helper .. - // - - private static Class[] getCustomConstructorArgumentTypes(Class windowClass) { - Class[] argTypes = null; - try { - Method m = windowClass.getDeclaredMethod("getCustomConstructorArgumentTypes", new Class[] {}); - argTypes = (Class[]) m.invoke(null, null); - } catch (Throwable t) {} - return argTypes; - } - - private static int verifyConstructorArgumentTypes(Class[] types, Object[] args) { - if(types.length != args.length) { - return -1; - } - for(int i=0; i "+(refCount+1)); + } + if ( 0 == refCount ) { + createNative(); + } + if(null == aDevice) { + throw new RuntimeException("Display.addReference() (refCount "+refCount+") null AbstractGraphicsDevice"); + } + return ++refCount; + } + + + protected synchronized final int removeReference() { + if(DEBUG) { + System.err.println("Display.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); + } + refCount--; + if(0==refCount && destroyWhenUnused) { + destroy(); + } + return refCount; + } + + public synchronized final int getReferenceCount() { + return refCount; + } + + public final boolean getDestroyWhenUnused() { return destroyWhenUnused; } + public final void setDestroyWhenUnused(boolean v) { destroyWhenUnused=v; } + + protected abstract void createNativeImpl(); + protected abstract void closeNativeImpl(); + + public final int getId() { + return id; + } + + public final String getType() { + return type; + } + + public final String getName() { + return name; + } + + public final String getFQName() { + return fqname; + } + + public static final String nilString = "nil" ; + + public String validateDisplayName(String name, long handle) { + if(null==name && 0!=handle) { + name="wrapping-"+toHexString(handle); + } + return ( null == name ) ? nilString : name ; + } + + public static final String getFQName(int id, String type, String name) { + if(null==type) type=nilString; + if(null==name) name=nilString; + StringBuffer sb = new StringBuffer(); + sb.append(type); + sb.append("_"); + sb.append(name); + sb.append("-"); + sb.append(id); + return sb.toString(); + } + + public final long getHandle() { + if(null!=aDevice) { + return aDevice.getHandle(); + } + return 0; + } + + public final AbstractGraphicsDevice getGraphicsDevice() { + return aDevice; + } + + public final boolean isNativeValid() { + return null != aDevice; + } + + public boolean isEDTRunning() { + if(null!=edtUtil) { + return edtUtil.isRunning(); + } + return false; + } + + public String toString() { + return "NEWT-Display["+getFQName()+", refCount "+refCount+", hasEDT "+(null!=edtUtil)+", edtRunning "+isEDTRunning()+", "+aDevice+"]"; + } + + protected abstract void dispatchMessagesNative(); + + private Object eventsLock = new Object(); + private LinkedList/**/ events = new LinkedList(); + + class DispatchMessagesRunnable implements Runnable { + public void run() { + DisplayImpl.this.dispatchMessages(); + } + } + DispatchMessagesRunnable dispatchMessagesRunnable = new DispatchMessagesRunnable(); + + public void dispatchMessages() { + // System.err.println("Display.dispatchMessages() 0 "+this+" "+getThreadName()); + if(0==refCount) return; // no screens + if(null==getGraphicsDevice()) return; // no native device + + LinkedList/**/ _events = null; + + if(!events.isEmpty()) { + // swap events list to free ASAP + synchronized(eventsLock) { + if(!events.isEmpty()) { + _events = events; + events = new LinkedList(); + } + eventsLock.notifyAll(); + } + if( null != _events ) { + for (Iterator iter = _events.iterator(); iter.hasNext(); ) { + NEWTEventTask eventTask = (NEWTEventTask) iter.next(); + NEWTEvent event = eventTask.get(); + Object source = event.getSource(); + if(source instanceof NEWTEventConsumer) { + NEWTEventConsumer consumer = (NEWTEventConsumer) source ; + if(!consumer.consumeEvent(event)) { + enqueueEvent(false, event); + } + } else { + throw new RuntimeException("Event source not NEWT: "+source.getClass().getName()+", "+source); + } + eventTask.notifyIssuer(); + } + } + } + + // lock(); + try { + // System.err.println("Display.dispatchMessages() NATIVE "+this+" "+getThreadName()); + dispatchMessagesNative(); + } finally { + // unlock(); + // System.err.println("Display.dispatchMessages() X "+this+" "+getThreadName()); + } + } + + public void enqueueEvent(boolean wait, NEWTEvent e) { + Object lock = new Object(); + NEWTEventTask eTask = new NEWTEventTask(e, wait?lock:null); + synchronized(lock) { + synchronized(eventsLock) { + events.addLast(eTask); + eventsLock.notifyAll(); + } + if( wait ) { + try { + lock.wait(); + } catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + } + } + } + + public void lock() { + aDevice.lock(); + } + + public void unlock() { + aDevice.unlock(); + } + + protected EDTUtil edtUtil = null; + protected int id; + protected String name; + protected String type; + protected String fqname; + protected int refCount; // number of Display references by Screen + protected boolean destroyWhenUnused; + protected AbstractGraphicsDevice aDevice; +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java b/src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java new file mode 100644 index 000000000..217d9d293 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +package com.jogamp.newt.impl; + +import javax.media.nativewindow.*; + +public class OffscreenWindow extends WindowImpl implements SurfaceChangeable { + + long surfaceHandle = 0; + + public OffscreenWindow() { + } + + static long nextWindowHandle = 0x100; // start here - a marker + + protected void createNativeImpl() { + if(0!=getParentWindowHandle()) { + throw new NativeWindowException("OffscreenWindow does not support window parenting"); + } + if(caps.isOnscreen()) { + throw new NativeWindowException("Capabilities is onscreen"); + } + AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen(); + config = GraphicsConfigurationFactory.getFactory(aScreen.getDevice()).chooseGraphicsConfiguration(caps, null, aScreen); + if (config == null) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + + synchronized(OffscreenWindow.class) { + setWindowHandle(nextWindowHandle++); + } + } + + protected void closeNativeImpl() { + // nop + } + + public void invalidate(boolean unrecoverable) { + super.invalidate(unrecoverable); + surfaceHandle = 0; + } + + public synchronized void destroy(boolean unrecoverable) { + super.destroy(unrecoverable); + surfaceHandle = 0; + } + + public void setSurfaceHandle(long handle) { + surfaceHandle = handle ; + } + + public long getSurfaceHandle() { + return surfaceHandle; + } + + protected void setVisibleImpl(boolean visible) { + } + + protected void requestFocusImpl(boolean reparented) { + } + + public void setSize(int width, int height) { + if(!visible) { + this.width = width; + this.height = height; + } + } + protected void setSizeImpl(int width, int height) { + shouldNotCallThis(); + } + + public void setPosition(int x, int y) { + // nop + } + protected void setPositionImpl(int x, int y) { + shouldNotCallThis(); + } + + public boolean setFullscreen(boolean fullscreen) { + // nop + return false; + } + protected void reconfigureWindowImpl(int x, int y, int width, int height) { + shouldNotCallThis(); + } +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java new file mode 100644 index 000000000..0104b4a4c --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright (c) 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +package com.jogamp.newt.impl; + +import com.jogamp.newt.*; + +import javax.media.nativewindow.*; +import java.security.*; + +public abstract class ScreenImpl implements Screen { + + private static Class getScreenClass(String type) + throws ClassNotFoundException + { + Class screenClass = NewtFactory.getCustomClass(type, "Screen"); + if(null==screenClass) { + if (NativeWindowFactory.TYPE_EGL.equals(type)) { + screenClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDScreen"); + } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { + screenClass = Class.forName("com.jogamp.newt.impl.windows.WindowsScreen"); + } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { + screenClass = Class.forName("com.jogamp.newt.impl.macosx.MacScreen"); + } else if (NativeWindowFactory.TYPE_X11.equals(type)) { + screenClass = Class.forName("com.jogamp.newt.impl.x11.X11Screen"); + } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { + screenClass = Class.forName("com.jogamp.newt.impl.awt.AWTScreen"); + } else { + throw new RuntimeException("Unknown window type \"" + type + "\""); + } + } + return screenClass; + } + + public static ScreenImpl create(String type, Display display, final int idx) { + try { + if(usrWidth<0 || usrHeight<0) { + usrWidth = Debug.getIntProperty("newt.ws.swidth", true, localACC); + usrHeight = Debug.getIntProperty("newt.ws.sheight", true, localACC); + if(usrWidth>0 || usrHeight>0) { + System.err.println("User screen size "+usrWidth+"x"+usrHeight); + } + } + Class screenClass = getScreenClass(type); + ScreenImpl screen = (ScreenImpl) screenClass.newInstance(); + screen.display = (DisplayImpl) display; + screen.idx = idx; + return screen; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected synchronized final void createNative() { + if(null == aScreen) { + if(DEBUG) { + System.err.println("Screen.createNative() START ("+DisplayImpl.getThreadName()+", "+this+")"); + } + display.addReference(); + createNativeImpl(); + if(null == aScreen) { + throw new RuntimeException("Screen.createNative() failed to instanciate an AbstractGraphicsScreen"); + } + if(DEBUG) { + System.err.println("Screen.createNative() END ("+DisplayImpl.getThreadName()+", "+this+")"); + } + } + } + + public synchronized final void destroy() { + if ( null != aScreen ) { + closeNativeImpl(); + display.removeReference(); + aScreen = null; + } + } + + protected synchronized final int addReference() { + if(DEBUG) { + System.err.println("Screen.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1)); + } + if ( 0 == refCount ) { + createNative(); + } + if(null == aScreen) { + throw new RuntimeException("Screen.addReference() (refCount "+refCount+") null AbstractGraphicsScreen"); + } + return ++refCount; + } + + protected synchronized final int removeReference() { + if(DEBUG) { + System.err.println("Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); + } + refCount--; + if(0==refCount && getDestroyWhenUnused()) { + destroy(); + } + return refCount; + } + + public synchronized final int getReferenceCount() { + return refCount; + } + + public final boolean getDestroyWhenUnused() { + return display.getDestroyWhenUnused(); + } + public final void setDestroyWhenUnused(boolean v) { + display.setDestroyWhenUnused(v); + } + + protected abstract void createNativeImpl(); + protected abstract void closeNativeImpl(); + + protected void setScreenSize(int w, int h) { + System.err.println("Detected screen size "+w+"x"+h); + width=w; height=h; + } + + public final Display getDisplay() { + return display; + } + + public final int getIndex() { + return idx; + } + + public final AbstractGraphicsScreen getGraphicsScreen() { + return aScreen; + } + + public final boolean isNativeValid() { + return null != aScreen; + } + + public final int getWidth() { + return (usrWidth>0) ? usrWidth : (width>0) ? width : 480; + } + + public final int getHeight() { + return (usrHeight>0) ? usrHeight : (height>0) ? height : 480; + } + + public String toString() { + return "NEWT-Screen[idx "+idx+", refCount "+refCount+", "+getWidth()+"x"+getHeight()+", "+aScreen+", "+display+"]"; + } + + protected DisplayImpl display; + protected int idx; + protected AbstractGraphicsScreen aScreen; + protected int refCount; // number of Screen references by Window + protected int width=-1, height=-1; // detected values: set using setScreenSize + protected static int usrWidth=-1, usrHeight=-1; // property values: newt.ws.swidth and newt.ws.sheight + private static AccessControlContext localACC = AccessController.getContext(); +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java new file mode 100644 index 000000000..9111419fc --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java @@ -0,0 +1,1771 @@ +/* + * Copyright (c) 2008 Sun Microsystems, Inc. All Rights Reserved. + Copyright (c) 2010 JogAmp Community. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistribution of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistribution in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * Neither the name of Sun Microsystems, Inc. or the names of + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * This software is provided "AS IS," without a warranty of any kind. ALL + * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, + * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN + * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR + * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR + * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR + * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR + * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE + * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, + * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF + * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + * + */ + +package com.jogamp.newt.impl; + +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Display; +import com.jogamp.newt.Screen; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.*; +import com.jogamp.newt.util.*; + +import com.jogamp.common.util.*; +import javax.media.nativewindow.*; +import com.jogamp.nativewindow.util.Rectangle; +import com.jogamp.nativewindow.impl.RecursiveToolkitLock; +import com.jogamp.newt.impl.OffscreenWindow; + +import java.util.ArrayList; +import java.util.Iterator; +import java.lang.reflect.Method; + +public abstract class WindowImpl implements Window, NEWTEventConsumer +{ + public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true); + + // Workaround for initialization order problems on Mac OS X + // between native Newt and (apparently) Fmod -- if Fmod is + // initialized first then the connection to the window server + // breaks, leading to errors from deep within the AppKit + public static void init(String type) { + if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { + try { + getWindowClass(type); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + // + // Construction Methods + // + + private static Class getWindowClass(String type) + throws ClassNotFoundException + { + Class windowClass = NewtFactory.getCustomClass(type, "Window"); + if(null==windowClass) { + if (NativeWindowFactory.TYPE_EGL.equals(type)) { + windowClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDWindow"); + } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { + windowClass = Class.forName("com.jogamp.newt.impl.windows.WindowsWindow"); + } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { + windowClass = Class.forName("com.jogamp.newt.impl.macosx.MacWindow"); + } else if (NativeWindowFactory.TYPE_X11.equals(type)) { + windowClass = Class.forName("com.jogamp.newt.impl.x11.X11Window"); + } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { + windowClass = Class.forName("com.jogamp.newt.impl.awt.AWTWindow"); + } else { + throw new NativeWindowException("Unknown window type \"" + type + "\""); + } + } + return windowClass; + } + + public static WindowImpl create(String type, NativeWindow parentWindow, long parentWindowHandle, Screen screen, Capabilities caps) { + try { + Class windowClass; + if(caps.isOnscreen()) { + windowClass = getWindowClass(type); + } else { + windowClass = OffscreenWindow.class; + } + WindowImpl window = (WindowImpl) windowClass.newInstance(); + window.invalidate(true); + window.parentWindow = parentWindow; + window.parentWindowHandle = parentWindowHandle; + window.screen = (ScreenImpl) screen; + window.caps = (Capabilities)caps.clone(); + window.setUndecorated(0!=parentWindowHandle); + return window; + } catch (Throwable t) { + t.printStackTrace(); + throw new NativeWindowException(t); + } + } + + public static WindowImpl create(String type, Object[] cstrArguments, Screen screen, Capabilities caps) { + try { + Class windowClass = getWindowClass(type); + Class[] cstrArgumentTypes = getCustomConstructorArgumentTypes(windowClass); + if(null==cstrArgumentTypes) { + throw new NativeWindowException("WindowClass "+windowClass+" doesn't support custom arguments in constructor"); + } + int argsChecked = verifyConstructorArgumentTypes(cstrArgumentTypes, cstrArguments); + if ( argsChecked < cstrArguments.length ) { + throw new NativeWindowException("WindowClass "+windowClass+" constructor mismatch at argument #"+argsChecked+"; Constructor: "+getTypeStrList(cstrArgumentTypes)+", arguments: "+getArgsStrList(cstrArguments)); + } + WindowImpl window = (WindowImpl) ReflectionUtil.createInstance( windowClass, cstrArgumentTypes, cstrArguments ) ; + window.invalidate(true); + window.screen = (ScreenImpl) screen; + window.caps = (Capabilities)caps.clone(); + return window; + } catch (Throwable t) { + throw new NativeWindowException(t); + } + } + + public static interface LifecycleHook { + /** + * Invoked after Window setVisible, + * allows allocating resources depending on the native Window. + * Called from EDT. + */ + void setVisibleAction(boolean visible, boolean nativeWindowCreated); + + /** + * Invoked before Window destroy action, + * allows releasing of resources depending on the native Window. + * Called from EDT. + */ + void destroyAction(boolean unrecoverable); + + /** Only informal, when starting reparenting */ + void reparentActionPre(); + + /** Only informal, when finishing reparenting */ + void reparentActionPost(int reparentActionType); + } + + private LifecycleHook lifecycleHook = null; + private RecursiveToolkitLock windowLock = new RecursiveToolkitLock(); + private long windowHandle; + private ScreenImpl screen; + private boolean screenReferenced = false; + private NativeWindow parentWindow; + private long parentWindowHandle; + + protected AbstractGraphicsConfiguration config; + protected Capabilities caps; + protected boolean fullscreen, visible; + protected int width, height, x, y; + + // non fullscreen dimensions .. + protected int nfs_width, nfs_height, nfs_x, nfs_y; + + protected String title = "Newt Window"; + protected boolean undecorated = false; + + private final void setScreen(ScreenImpl newScreen) { + if(screenReferenced) { + screenReferenced = false; + screen.removeReference(); + } + screen = newScreen; + } + + private boolean createNative() { + if( null==screen || 0!=windowHandle || !visible ) { + return 0 != windowHandle ; + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.createNative() START ("+getThreadName()+", "+this+")"); + } + if( null != parentWindow && + NativeWindow.LOCK_SURFACE_NOT_READY >= parentWindow.lockSurface() ) { + throw new NativeWindowException("Parent surface lock: not ready: "+parentWindow); + } + try { + if(validateParentWindowHandle()) { + if(!screenReferenced) { + screenReferenced = true; + screen.addReference(); + } + createNativeImpl(); + setVisibleImpl(true); + } + } finally { + if(null!=parentWindow) { + parentWindow.unlockSurface(); + } + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.createNative() END ("+getThreadName()+", "+this+")"); + } + return 0 != windowHandle ; + } + + private boolean validateParentWindowHandle() { + if(null!=parentWindow) { + parentWindowHandle = getNativeWindowHandle(parentWindow); + return 0 != parentWindowHandle ; + } + return true; + } + + private static long getNativeWindowHandle(NativeWindow nativeWindow) { + long handle = 0; + if(null!=nativeWindow) { + boolean locked=false; + try { + if( NativeWindow.LOCK_SURFACE_NOT_READY < nativeWindow.lockSurface() ) { + locked=true; + handle = nativeWindow.getWindowHandle(); + if(0==handle) { + throw new NativeWindowException("Parent native window handle is NULL, after succesful locking: "+nativeWindow); + } + } + } catch (NativeWindowException nwe) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.getNativeWindowHandle: not successful yet: "+nwe); + } + } finally { + if(locked) { + nativeWindow.unlockSurface(); + } + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.getNativeWindowHandle: locked "+locked+", "+nativeWindow); + } + } + return handle; + } + + + //---------------------------------------------------------------------- + // NativeWindow: Native implementation + // + + protected int lockSurfaceImpl() { return LOCK_SUCCESS; } + + protected void unlockSurfaceImpl() { } + + //---------------------------------------------------------------------- + // Window: Native implementation + // + + protected abstract void createNativeImpl(); + + protected abstract void closeNativeImpl(); + + protected abstract void requestFocusImpl(boolean reparented); + + protected abstract void setVisibleImpl(boolean visible); + + protected abstract void setSizeImpl(int width, int height); + + protected abstract void setPositionImpl(int x, int y); + + protected abstract void reconfigureWindowImpl(int x, int y, int width, int height); + + protected void setTitleImpl(String title) {} + + //---------------------------------------------------------------------- + // NativeWindow + // + + public final int lockSurface() { + // We leave the ToolkitLock lock to the specializtion's discretion, + // ie the implicit JAWTWindow in case of AWTWindow + + // may throw RuntimeException if timed out while waiting for lock + windowLock.lock(); + + int res = lockSurfaceImpl(); + if(!isNativeValid()) { + windowLock.unlock(); + res = LOCK_SURFACE_NOT_READY; + } + return res; + } + + public final void unlockSurface() { + // may throw RuntimeException if not locked + windowLock.validateLocked(); + + unlockSurfaceImpl(); + + windowLock.unlock(); + // We leave the ToolkitLock unlock to the specializtion's discretion, + // ie the implicit JAWTWindow in case of AWTWindow + } + + public final boolean isSurfaceLockedByOtherThread() { + return windowLock.isLockedByOtherThread(); + } + + public final boolean isSurfaceLocked() { + return windowLock.isLocked(); + } + + public final Thread getSurfaceLockOwner() { + return windowLock.getOwner(); + } + + public final Exception getSurfaceLockStack() { + return windowLock.getLockedStack(); + } + + public final long getDisplayHandle() { + return getScreen().getDisplay().getHandle(); + } + + public final int getScreenIndex() { + return getScreen().getIndex(); + } + + public AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config; + } + + public final long getWindowHandle() { + return windowHandle; + } + + public long getSurfaceHandle() { + return windowHandle; // default: return window handle + } + + public boolean surfaceSwap() { + return false; + } + + //---------------------------------------------------------------------- + // Window + // + + public final boolean isNativeValid() { + return null != getScreen() && 0 != getWindowHandle() ; + } + + public final boolean isValid() { + return null != getScreen() ; + } + + public final NativeWindow getParentNativeWindow() { + return parentWindow; + } + + public final Screen getScreen() { + return screen; + } + + public void setVisible(boolean visible) { + if(DEBUG_IMPLEMENTATION) { + String msg = new String("Window setVisible: START ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+this.visible+" -> "+visible+", parentWindowHandle "+toHexString(this.parentWindowHandle)+", parentWindow "+(null!=this.parentWindow)/*+", "+this*/); + System.err.println(msg); + //Exception ee = new Exception(msg); + //ee.printStackTrace(); + } + if(isValid()) { + VisibleAction va = new VisibleAction(visible); + runOnEDTIfAvail(true, va); + if( va.getChanged() ) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + + } + } + + class VisibleAction implements Runnable { + boolean visible; + boolean nativeWindowCreated; + boolean madeVisible; + + public VisibleAction(boolean visible) { + this.visible = visible; + this.nativeWindowCreated = false; + this.madeVisible = false; + } + + public final boolean getNativeWindowCreated() { return nativeWindowCreated; } + public final boolean getBecameVisible() { return madeVisible; } + public final boolean getChanged() { return nativeWindowCreated || madeVisible; } + + public void run() { + windowLock.lock(); + try { + if( isValid() ) { + if(!visible && childWindows.size()>0) { + synchronized(childWindowsLock) { + for(Iterator i = childWindows.iterator(); i.hasNext(); ) { + NativeWindow nw = (NativeWindow) i.next(); + if(nw instanceof WindowImpl) { + ((WindowImpl)nw).setVisible(false); + } + } + } + } + if(0==windowHandle && visible) { + WindowImpl.this.visible = visible; + if( 00) { + synchronized(childWindowsLock) { + for(Iterator i = childWindows.iterator(); i.hasNext(); ) { + NativeWindow nw = (NativeWindow) i.next(); + if(nw instanceof WindowImpl) { + ((WindowImpl)nw).setVisible(true); + } + } + } + } + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setVisible: END ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+WindowImpl.this.visible+", nativeWindowCreated: "+nativeWindowCreated+", madeVisible: "+madeVisible); + } + + } finally { + windowLock.unlock(); + } + getScreen().getDisplay().dispatchMessages(); // status up2date + } + } + + public void setSize(int width, int height) { + int visibleAction = 0; // 1 invisible, 2 visible + windowLock.lock(); + try{ + if(DEBUG_IMPLEMENTATION) { + String msg = new String("Window setSize: START "+this.width+"x"+this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible); + System.err.println(msg); + // Exception e = new Exception(msg); + // e.printStackTrace(); + } + if (width != this.width || this.height != height) { + if(!fullscreen) { + nfs_width=width; + nfs_height=height; + if ( 0 != windowHandle && 0>=width*height && visible ) { + visibleAction=1; // invisible + this.width = 0; + this.height = 0; + } else if ( 0 == windowHandle && 00) { + setVisible( ( 1 == visibleAction ) ? false : true ); + } + } + + public final void destroy() { + destroy(false); + } + + public void destroy(boolean unrecoverable) { + if(isValid()) { + if(DEBUG_IMPLEMENTATION) { + String msg = new String("Window.destroy(unrecoverable: "+unrecoverable+") START "+getThreadName()/*+", "+this*/); + System.err.println(msg); + //Exception ee = new Exception(msg); + //ee.printStackTrace(); + } + runOnEDTIfAvail(true, new DestroyAction(unrecoverable)); + } + } + + class DestroyAction implements Runnable { + boolean unrecoverable; + public DestroyAction(boolean unrecoverable) { + this.unrecoverable = unrecoverable; + } + public void run() { + windowLock.lock(); + try { + if( !isValid() ) { + return; // nop + } + + // Childs first .. + synchronized(childWindowsLock) { + // avoid ConcurrentModificationException: parent -> child -> parent.removeChild(this) + ArrayList clonedChildWindows = (ArrayList) childWindows.clone(); + while( clonedChildWindows.size() > 0 ) { + NativeWindow nw = (NativeWindow) clonedChildWindows.remove(0); + if(nw instanceof WindowImpl) { + ((WindowImpl)nw).sendWindowEvent(WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); + if(unrecoverable) { + ((WindowImpl)nw).destroy(unrecoverable); + } + } else { + nw.destroy(); + } + } + } + + if(null!=lifecycleHook) { + lifecycleHook.destroyAction(unrecoverable); + } + + // Now us .. + if(unrecoverable) { + if(null!=parentWindow && parentWindow instanceof Window) { + ((Window)parentWindow).removeChild(WindowImpl.this); + } + synchronized(childWindowsLock) { + childWindows = new ArrayList(); + } + synchronized(surfaceUpdatedListenersLock) { + surfaceUpdatedListeners = new ArrayList(); + } + windowListeners = new ArrayList(); + mouseListeners = new ArrayList(); + keyListeners = new ArrayList(); + } + if( null != screen && 0 != windowHandle ) { + closeNativeImpl(); + } + invalidate(unrecoverable); + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.destroy(unrecoverable: "+unrecoverable+") END "+getThreadName()/*+", "+WindowImpl.this*/); + } + } finally { + windowLock.unlock(); + } + } + } + + /** + *

+ * render all native window information invalid, + * as if the native window was destroyed.

+ *

+ * all other resources and states are kept intact, + * ie listeners, parent handles and size, position etc.

+ * + * @see #destroy() + * @see #destroy(boolean) + * @see #invalidate(boolean) + */ + public final void invalidate() { + invalidate(false); + } + + /** + * @param unrecoverable If true, all states, size, position, parent handles, + * reference to it's Screen are reset. + * Otherwise you can recreate the window, via setVisible(true). + * @see #invalidate() + * @see #destroy() + * @see #destroy(boolean) + */ + protected void invalidate(boolean unrecoverable) { + windowLock.lock(); + try{ + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + String msg = new String("!!! Window Invalidate(unrecoverable: "+unrecoverable+") "+getThreadName()); + System.err.println(msg); + // Exception e = new Exception(msg); + // e.printStackTrace(); + } + windowHandle = 0; + visible = false; + fullscreen = false; + + if(unrecoverable) { + setScreen(null); + parentWindowHandle = 0; + parentWindow = null; + caps = null; + lifecycleHook = null; + + // Default position and dimension will be re-set immediately by user + width = 128; + height = 128; + x=0; + y=0; + } + } finally { + windowLock.unlock(); + } + } + + class ReparentActionImpl implements Runnable, ReparentAction { + NativeWindow newParentWindow; + boolean forceDestroyCreate; + int reparentAction; + + public ReparentActionImpl(NativeWindow newParentWindow, boolean forceDestroyCreate) { + this.newParentWindow = newParentWindow; + this.forceDestroyCreate = forceDestroyCreate; + this.reparentAction = -1; // ensure it's set + } + + public int getStrategy() { + return reparentAction; + } + + public void run() { + boolean wasVisible; + boolean displayChanged = false; + + windowLock.lock(); + try { + wasVisible = isVisible(); + + Window newParentWindowNEWT = null; + if(newParentWindow instanceof Window) { + newParentWindowNEWT = (Window) newParentWindow; + } + + long newParentWindowHandle = 0 ; + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparent: START ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+", visible "+wasVisible+", old parentWindow: "+Display.hashCode(parentWindow)+", new parentWindow: "+Display.hashCode(newParentWindow)+", forceDestroyCreate "+forceDestroyCreate+", DEBUG_TEST_REPARENT_INCOMPATIBLE "+DEBUG_TEST_REPARENT_INCOMPATIBLE); + } + + if(null!=newParentWindow) { + // Case: Child Window + newParentWindowHandle = getNativeWindowHandle(newParentWindow); + if(0 == newParentWindowHandle) { + // Case: Parent's native window not realized yet + if(null==newParentWindowNEWT) { + throw new NativeWindowException("Reparenting with non NEWT Window type only available after it's realized: "+newParentWindow); + } + // Destroy this window (handle screen + native) and use parent's Screen. + // It may be created properly when the parent is made visible. + destroy(false); + setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); + displayChanged = true; + reparentAction = ACTION_NATIVE_CREATION_PENDING; + } else if(newParentWindow != getParentNativeWindow()) { + // Case: Parent's native window realized and changed + if( !isNativeValid() ) { + // May create a new compatible Screen/Display and + // mark it for creation. + if(null!=newParentWindowNEWT) { + setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); + } else { + Screen newScreen = NewtFactory.createCompatibleScreen(newParentWindow, getScreen()); + if( getScreen() != newScreen ) { + // auto destroy on-the-fly created Screen/Display + newScreen.setDestroyWhenUnused(true); + setScreen( (ScreenImpl) newScreen ); + displayChanged = true; + } + } + reparentAction = ACTION_NATIVE_CREATION; + } else if ( DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate || + !NewtFactory.isScreenCompatible(newParentWindow, getScreen()) ) { + // Destroy this window (handle screen + native) and + // may create a new compatible Screen/Display and + // mark it for creation. + destroy(false); + if(null!=newParentWindowNEWT) { + setScreen( (ScreenImpl) newParentWindowNEWT.getScreen() ); + } else { + setScreen( (ScreenImpl) NewtFactory.createCompatibleScreen(newParentWindow, getScreen()) ); + screen.setDestroyWhenUnused(true); + } + displayChanged = true; + reparentAction = ACTION_NATIVE_CREATION; + } else { + // Mark it for native reparenting + reparentAction = ACTION_NATIVE_REPARENTING; + } + } else { + // Case: Parent's native window realized and not changed + reparentAction = ACTION_UNCHANGED; + } + } else { + // Case: Top Window + if( 0 == getParentWindowHandle() ) { + // Already Top Window + reparentAction = ACTION_UNCHANGED; + } else if ( DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate ) { + // Destroy this window (handle screen + native) and + // keep Screen/Display and + // mark it for creation. + destroy(false); + reparentAction = ACTION_NATIVE_CREATION; + } else { + // Mark it for native reparenting + reparentAction = ACTION_NATIVE_REPARENTING; + } + } + parentWindowHandle = newParentWindowHandle; + + if ( ACTION_UNCHANGED > reparentAction ) { + throw new NativeWindowException("Internal Error: reparentAction not set"); + } + + if( ACTION_UNCHANGED == reparentAction ) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparent: NO CHANGE ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" new parentWindowHandle "+toHexString(newParentWindowHandle)+", visible "+wasVisible); + } + return; + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparent: ACTION ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" new parentWindowHandle "+toHexString(newParentWindowHandle)+", reparentAction "+reparentAction+", visible "+wasVisible); + } + + // rearrange window tree + if(null!=parentWindow && parentWindow instanceof Window) { + ((Window)parentWindow).removeChild(WindowImpl.this); + } + parentWindow = newParentWindow; + if(parentWindow instanceof Window) { + ((Window)parentWindow).addChild(WindowImpl.this); + } + + if( ACTION_NATIVE_CREATION_PENDING == reparentAction ) { + return; + } + + if( ACTION_NATIVE_REPARENTING == reparentAction ) { + NativeWindow parentWindowLocked = null; + if( null != parentWindow ) { + parentWindowLocked = parentWindow; + if(NativeWindow.LOCK_SURFACE_NOT_READY >= parentWindowLocked.lockSurface() ) { + throw new NativeWindowException("Parent surface lock: not ready: "+parentWindow); + } + } + try { + if(0!=parentWindowHandle) { + // reset position to 0/0 within parent space + // FIXME .. cache position ? + x = 0; + y = 0; + } + DisplayImpl display = (DisplayImpl) screen.getDisplay(); + display.dispatchMessages(); // status up2date + if(wasVisible) { + visible = false; + setVisibleImpl(false); + display.dispatchMessages(); // status up2date + } + boolean ok = reparentWindowImpl(); + display.dispatchMessages(); // status up2date + if ( !ok ) { + // native reparent failed -> try creation + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparent: native reparenting failed ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)+" -> "+toHexString(newParentWindowHandle)+" - Trying recreation"); + } + destroy(false); + reparentAction = ACTION_NATIVE_CREATION ; + } if(wasVisible) { + visible = true; + setVisibleImpl(true); + requestFocusImpl(true); + display.dispatchMessages(); // status up2date + } + } finally { + if(null!=parentWindowLocked) { + parentWindowLocked.unlockSurface(); + } + } + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparentWindow: END ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+ Display.hashCode(parentWindow)); + } + } finally { + windowLock.unlock(); + } + + if( ACTION_NATIVE_CREATION == reparentAction && wasVisible ) { + // This may run on the the Display/Screen connection, + // hence a new EDT task + runOnEDTIfAvail(true, reparentActionRecreate); + } + } + } + + class ReparentActionRecreate implements Runnable { + public void run() { + windowLock.lock(); + try { + visible = true; + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparentWindow: ReparentActionRecreate ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+Display.hashCode(parentWindow)); + } + setVisible(true); // native creation + requestFocus(); + } finally { + windowLock.unlock(); + } + } + } + private ReparentActionRecreate reparentActionRecreate = new ReparentActionRecreate(); + + public final int reparentWindow(NativeWindow newParent) { + return reparentWindow(newParent, false); + } + + public int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) { + int reparentActionStrategy = ReparentAction.ACTION_INVALID; + if(isValid()) { + if(null!=lifecycleHook) { + lifecycleHook.reparentActionPre(); + } + try { + ReparentActionImpl reparentAction = new ReparentActionImpl(newParent, forceDestroyCreate); + runOnEDTIfAvail(true, reparentAction); + reparentActionStrategy = reparentAction.getStrategy(); + if( isVisible() ) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + } finally { + if(null!=lifecycleHook) { + lifecycleHook.reparentActionPost(reparentActionStrategy); + } + } + } + return reparentActionStrategy; + } + + public final Capabilities getChosenCapabilities() { + return config.getNativeGraphicsConfiguration().getChosenCapabilities(); + } + + public final Capabilities getRequestedCapabilities() { + return (Capabilities)caps.clone(); + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + if (title == null) { + title = ""; + } + this.title = title; + if(0 != getWindowHandle()) { + setTitleImpl(title); + } + } + + public void setUndecorated(boolean value) { + if(this.undecorated != value) { + undecorated = value; + if( 0 != windowHandle ) { + reconfigureWindowImpl(x, y, width, height); + requestFocus(); + } + } + } + + public boolean isUndecorated(boolean fullscreen) { + return 0 != getParentWindowHandle() || undecorated || fullscreen ; + } + + public boolean isUndecorated() { + return 0 != parentWindowHandle || undecorated || fullscreen ; + } + + public void requestFocus() { + enqueueRequestFocus(false); // FIXME: or shall we wait ? + } + + public Insets getInsets() { + return new Insets(0,0,0,0); + } + + public final int getWidth() { + return width; + } + + public final int getHeight() { + return height; + } + + public final int getX() { + return x; + } + + public final int getY() { + return y; + } + + public final boolean isVisible() { + return visible; + } + + public final boolean isFullscreen() { + return fullscreen; + } + + + //---------------------------------------------------------------------- + // Window + // + + /** + * If the implementation is capable of detecting a device change + * return true and clear the status/reason of the change. + */ + public boolean hasDeviceChanged() { + return false; + } + + public LifecycleHook getLifecycleHook() { + return lifecycleHook; + } + + public LifecycleHook setLifecycleHook(LifecycleHook hook) { + LifecycleHook old = lifecycleHook; + lifecycleHook = hook; + return old; + } + + /** If this Window actually wraps one from another toolkit such as + the AWT, this will return a non-null value. */ + public Object getWrappedWindow() { + return null; + } + + /** + * If set to true, the default value, this NEWT Window implementation will + * handle the destruction (ie {@link #destroy()} call) within {@link #windowDestroyNotify()} implementation.
+ * If set to false, it's up to the caller/owner to handle destruction within {@link #windowDestroyNotify()}. + */ + public void setHandleDestroyNotify(boolean b) { + handleDestroyNotify = b; + } + + //---------------------------------------------------------------------- + // WindowImpl + // + + protected final long getParentWindowHandle() { + return parentWindowHandle; + } + + public String toString() { + StringBuffer sb = new StringBuffer(); + + sb.append(getClass().getName()+"[Config "+config+ + "\n, "+screen+ + "\n, ParentWindow "+parentWindow+ + "\n, ParentWindowHandle "+toHexString(parentWindowHandle)+ + "\n, WindowHandle "+toHexString(getWindowHandle())+ + "\n, SurfaceHandle "+toHexString(getSurfaceHandle())+ " (lockedExt "+isSurfaceLockedByOtherThread()+")"+ + "\n, Pos "+getX()+"/"+getY()+", size "+getWidth()+"x"+getHeight()+ + "\n, Visible "+isVisible()+ + "\n, Undecorated "+undecorated+ + "\n, Fullscreen "+fullscreen+ + "\n, WrappedWindow "+getWrappedWindow()+ + "\n, ChildWindows "+childWindows.size()); + + sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedListeners.size()+" ["); + for (Iterator iter = surfaceUpdatedListeners.iterator(); iter.hasNext(); ) { + sb.append(iter.next()+", "); + } + sb.append("], WindowListeners num "+windowListeners.size()+" ["); + for (Iterator iter = windowListeners.iterator(); iter.hasNext(); ) { + sb.append(iter.next()+", "); + } + sb.append("], MouseListeners num "+mouseListeners.size()+" ["); + for (Iterator iter = mouseListeners.iterator(); iter.hasNext(); ) { + sb.append(iter.next()+", "); + } + sb.append("], KeyListeners num "+keyListeners.size()+" ["); + for (Iterator iter = keyListeners.iterator(); iter.hasNext(); ) { + sb.append(iter.next()+", "); + } + sb.append("] ]"); + return sb.toString(); + } + + protected final void setWindowHandle(long handle) { + windowHandle = handle; + } + + public void runOnEDTIfAvail(boolean wait, final Runnable task) { + Screen screen = getScreen(); + if(null==screen) { + throw new RuntimeException("Null screen of inner class: "+this); + } + DisplayImpl d = (DisplayImpl) screen.getDisplay(); + d.runOnEDTIfAvail(wait, task); + } + + class RequestFocusAction implements Runnable { + public void run() { + WindowImpl.this.requestFocusImpl(false); + } + } + RequestFocusAction requestFocusAction = new RequestFocusAction(); + + public void enqueueRequestFocus(boolean wait) { + runOnEDTIfAvail(wait, requestFocusAction); + } + + /** + * May set to a {@link FocusRunnable}, {@link FocusRunnable#run()} before Newt requests the native focus. + * This allows notifying a covered window toolkit like AWT that the focus is requested, + * hence focus traversal can be made transparent. + */ + public void setFocusAction(FocusRunnable focusAction) { + focusAction = focusAction; + } + protected boolean focusAction() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.focusAction() START - "+getThreadName()+", focusAction: "+focusAction+" - windowHandle "+toHexString(getWindowHandle())); + } + boolean res; + if(null!=focusAction) { + res = focusAction.run(); + } else { + res = false; + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.focusAction() END - "+getThreadName()+", focusAction: "+focusAction+" - windowHandle "+toHexString(getWindowHandle())+", res: "+res); + } + return res; + } + protected FocusRunnable focusAction = null; + + private boolean handleDestroyNotify = true; + + public void setPosition(int x, int y) { + windowLock.lock(); + try{ + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setPosition: "+this.x+"/"+this.y+" -> "+x+"/"+y+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)); + } + if ( this.x != x || this.y != y ) { + if(!fullscreen) { + nfs_x=x; + nfs_y=y; + if(0!=windowHandle) { + // this x/y will be set by windowChanged, called by X11 + setPositionImpl(x, y); + } else { + this.x = x; + this.y = y; + } + } + } + } finally { + windowLock.unlock(); + } + } + + public boolean setFullscreen(boolean fullscreen) { + windowLock.lock(); + try{ + if(0!=windowHandle && this.fullscreen!=fullscreen) { + int x,y,w,h; + if(fullscreen) { + x = 0; y = 0; + w = screen.getWidth(); + h = screen.getHeight(); + } else { + if(0!=parentWindowHandle) { + x=0; + y=0; + } else { + x = nfs_x; + y = nfs_y; + } + w = nfs_width; + h = nfs_height; + } + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("X11Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()+", "+screen); + } + this.fullscreen = fullscreen; + reconfigureWindowImpl(x, y, w, h); + requestFocus(); + } + } finally { + windowLock.unlock(); + } + if( isVisible() ) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + return this.fullscreen; + } + + //---------------------------------------------------------------------- + // Child Window Management + // + + private ArrayList childWindows = new ArrayList(); + private Object childWindowsLock = new Object(); + + public final void removeChild(NativeWindow win) { + synchronized(childWindowsLock) { + childWindows.remove(win); + } + } + + public final void addChild(NativeWindow win) { + if (win == null) { + return; + } + synchronized(childWindowsLock) { + childWindows.add(win); + } + } + + //---------------------------------------------------------------------- + // Generic Event Support + // + private void doEvent(boolean enqueue, boolean wait, com.jogamp.newt.event.NEWTEvent event) { + boolean done = false; + + if(!enqueue) { + done = consumeEvent(event); + wait = done; // don't wait if event can't be consumed now + } + + if(!done) { + enqueueEvent(wait, event); + } + } + + public void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { + if(isValid()) { + ((DisplayImpl)getScreen().getDisplay()).enqueueEvent(wait, event); + } + } + + public boolean consumeEvent(NEWTEvent e) { + switch(e.getEventType()) { + // special repaint treatment + case WindowEvent.EVENT_WINDOW_REPAINT: + // queue repaint event in case surface is locked, ie in operation + if( isSurfaceLocked() ) { + // make sure only one repaint event is queued + if(!repaintQueued) { + repaintQueued=true; + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.consumeEvent: queued "+e); + // Exception ee = new Exception("Window.windowRepaint: "+e); + // ee.printStackTrace(); + } + return false; + } + return true; + } + repaintQueued=false; // no repaint event queued + break; + + // common treatment + case WindowEvent.EVENT_WINDOW_RESIZED: + // queue event in case surface is locked, ie in operation + if( isSurfaceLocked() ) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.consumeEvent: queued "+e); + // Exception ee = new Exception("Window.windowRepaint: "+e); + // ee.printStackTrace(); + } + return false; + } + break; + default: + break; + } + if(e instanceof WindowEvent) { + consumeWindowEvent((WindowEvent)e); + } else if(e instanceof KeyEvent) { + consumeKeyEvent((KeyEvent)e); + } else if(e instanceof MouseEvent) { + consumeMouseEvent((MouseEvent)e); + } else { + throw new NativeWindowException("Unexpected NEWTEvent type " + e); + } + return true; + } + protected boolean repaintQueued = false; + + // + // SurfaceUpdatedListener Support + // + + private ArrayList surfaceUpdatedListeners = new ArrayList(); + private Object surfaceUpdatedListenersLock = new Object(); + + public void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + addSurfaceUpdatedListener(-1, l); + } + + public void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) + throws IndexOutOfBoundsException + { + if(l == null) { + return; + } + synchronized(surfaceUpdatedListenersLock) { + if(0>index) { + index = surfaceUpdatedListeners.size(); + } + surfaceUpdatedListeners.add(index, l); + } + } + + public void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + if (l == null) { + return; + } + synchronized(surfaceUpdatedListenersLock) { + surfaceUpdatedListeners.remove(l); + } + } + + public void removeAllSurfaceUpdatedListener() { + synchronized(surfaceUpdatedListenersLock) { + surfaceUpdatedListeners = new ArrayList(); + } + } + + public SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { + synchronized(surfaceUpdatedListenersLock) { + if(0>index) { + index = surfaceUpdatedListeners.size()-1; + } + return (SurfaceUpdatedListener) surfaceUpdatedListeners.get(index); + } + } + + public SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { + synchronized(surfaceUpdatedListenersLock) { + return (SurfaceUpdatedListener[]) surfaceUpdatedListeners.toArray(); + } + } + + public void surfaceUpdated(Object updater, NativeWindow window, long when) { + synchronized(surfaceUpdatedListenersLock) { + for(Iterator i = surfaceUpdatedListeners.iterator(); i.hasNext(); ) { + SurfaceUpdatedListener l = (SurfaceUpdatedListener) i.next(); + l.surfaceUpdated(updater, window, when); + } + } + } + + // + // MouseListener/Event Support + // + private ArrayList mouseListeners = new ArrayList(); + private int mouseButtonPressed = 0; // current pressed mouse button number + private long lastMousePressed = 0; // last time when a mouse button was pressed + private int lastMouseClickCount = 0; // last mouse button click count + public static final int ClickTimeout = 300; + + public void sendMouseEvent(int eventType, int modifiers, + int x, int y, int button, int rotation) { + doMouseEvent(false, false, eventType, modifiers, x, y, button, rotation); + } + public void enqueueMouseEvent(boolean wait, int eventType, int modifiers, + int x, int y, int button, int rotation) { + doMouseEvent(true, wait, eventType, modifiers, x, y, button, rotation); + } + private void doMouseEvent(boolean enqueue, boolean wait, int eventType, int modifiers, + int x, int y, int button, int rotation) { + if(x<0||y<0||x>=width||y>=height) { + return; // .. invalid .. + } + if(DEBUG_MOUSE_EVENT) { + System.err.println("doMouseEvent: enqueue"+enqueue+", wait "+wait+", "+MouseEvent.getEventTypeString(eventType)+ + ", mod "+modifiers+", pos "+x+"/"+y+", button "+button); + } + if(button<0||button>MouseEvent.BUTTON_NUMBER) { + throw new NativeWindowException("Invalid mouse button number" + button); + } + long when = System.currentTimeMillis(); + MouseEvent eClicked = null; + MouseEvent e = null; + + if(MouseEvent.EVENT_MOUSE_PRESSED==eventType) { + if(when-lastMousePressed0) { + e = new MouseEvent(MouseEvent.EVENT_MOUSE_DRAGGED, this, when, + modifiers, x, y, 1, mouseButtonPressed, 0); + } else { + e = new MouseEvent(eventType, this, when, + modifiers, x, y, 0, button, 0); + } + } else if(MouseEvent.EVENT_MOUSE_WHEEL_MOVED==eventType) { + e = new MouseEvent(eventType, this, when, modifiers, x, y, 0, button, rotation); + } else { + e = new MouseEvent(eventType, this, when, modifiers, x, y, 0, button, 0); + } + doEvent(enqueue, wait, e); + if(null!=eClicked) { + if(DEBUG_MOUSE_EVENT) { + System.err.println("doMouseEvent: synthesized MOUSE_CLICKED event"); + } + doEvent(enqueue, wait, eClicked); + } + } + + + public void addMouseListener(MouseListener l) { + addMouseListener(-1, l); + } + + public void addMouseListener(int index, MouseListener l) { + if(l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); + if(0>index) { + index = clonedListeners.size(); + } + clonedListeners.add(index, l); + mouseListeners = clonedListeners; + } + + public void removeMouseListener(MouseListener l) { + if (l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); + clonedListeners.remove(l); + mouseListeners = clonedListeners; + } + + public MouseListener getMouseListener(int index) { + ArrayList clonedListeners = (ArrayList) mouseListeners.clone(); + if(0>index) { + index = clonedListeners.size()-1; + } + return (MouseListener) clonedListeners.get(index); + } + + public MouseListener[] getMouseListeners() { + return (MouseListener[]) mouseListeners.toArray(); + } + + protected void consumeMouseEvent(MouseEvent e) { + if(DEBUG_MOUSE_EVENT) { + System.err.println("consumeMouseEvent: event: "+e); + } + + for(Iterator i = mouseListeners.iterator(); i.hasNext(); ) { + MouseListener l = (MouseListener) i.next(); + switch(e.getEventType()) { + case MouseEvent.EVENT_MOUSE_CLICKED: + l.mouseClicked(e); + break; + case MouseEvent.EVENT_MOUSE_ENTERED: + l.mouseEntered(e); + break; + case MouseEvent.EVENT_MOUSE_EXITED: + l.mouseExited(e); + break; + case MouseEvent.EVENT_MOUSE_PRESSED: + l.mousePressed(e); + break; + case MouseEvent.EVENT_MOUSE_RELEASED: + l.mouseReleased(e); + break; + case MouseEvent.EVENT_MOUSE_MOVED: + l.mouseMoved(e); + break; + case MouseEvent.EVENT_MOUSE_DRAGGED: + l.mouseDragged(e); + break; + case MouseEvent.EVENT_MOUSE_WHEEL_MOVED: + l.mouseWheelMoved(e); + break; + default: + throw new NativeWindowException("Unexpected mouse event type " + e.getEventType()); + } + } + } + + // + // KeyListener/Event Support + // + + public void sendKeyEvent(int eventType, int modifiers, int keyCode, char keyChar) { + consumeKeyEvent(new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) ); + } + + public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) { + enqueueEvent(wait, new KeyEvent(eventType, this, System.currentTimeMillis(), modifiers, keyCode, keyChar) ); + } + + public void addKeyListener(KeyListener l) { + addKeyListener(-1, l); + } + + public void addKeyListener(int index, KeyListener l) { + if(l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) keyListeners.clone(); + if(0>index) { + index = clonedListeners.size(); + } + clonedListeners.add(index, l); + keyListeners = clonedListeners; + } + + public void removeKeyListener(KeyListener l) { + if (l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) keyListeners.clone(); + clonedListeners.remove(l); + keyListeners = clonedListeners; + } + + public KeyListener getKeyListener(int index) { + ArrayList clonedListeners = (ArrayList) keyListeners.clone(); + if(0>index) { + index = clonedListeners.size()-1; + } + return (KeyListener) clonedListeners.get(index); + } + + public KeyListener[] getKeyListeners() { + return (KeyListener[]) keyListeners.toArray(); + } + + private ArrayList keyListeners = new ArrayList(); + + protected void consumeKeyEvent(KeyEvent e) { + if(DEBUG_KEY_EVENT) { + System.err.println("consumeKeyEvent: "+e); + } + for(Iterator i = keyListeners.iterator(); i.hasNext(); ) { + KeyListener l = (KeyListener) i.next(); + switch(e.getEventType()) { + case KeyEvent.EVENT_KEY_PRESSED: + l.keyPressed(e); + break; + case KeyEvent.EVENT_KEY_RELEASED: + l.keyReleased(e); + break; + case KeyEvent.EVENT_KEY_TYPED: + l.keyTyped(e); + break; + default: + throw new NativeWindowException("Unexpected key event type " + e.getEventType()); + } + } + } + + // + // WindowListener/Event Support + // + public void sendWindowEvent(int eventType) { + consumeWindowEvent( new WindowEvent(eventType, this, System.currentTimeMillis()) ); + } + + public void enqueueWindowEvent(boolean wait, int eventType) { + enqueueEvent( wait, new WindowEvent(eventType, this, System.currentTimeMillis()) ); + } + + private ArrayList windowListeners = new ArrayList(); + + public void addWindowListener(WindowListener l) { + addWindowListener(-1, l); + } + + public void addWindowListener(int index, WindowListener l) + throws IndexOutOfBoundsException + { + if(l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) windowListeners.clone(); + if(0>index) { + index = clonedListeners.size(); + } + clonedListeners.add(index, l); + windowListeners = clonedListeners; + } + + public final void removeWindowListener(WindowListener l) { + if (l == null) { + return; + } + ArrayList clonedListeners = (ArrayList) windowListeners.clone(); + clonedListeners.remove(l); + windowListeners = clonedListeners; + } + + public WindowListener getWindowListener(int index) { + ArrayList clonedListeners = (ArrayList) windowListeners.clone(); + if(0>index) { + index = clonedListeners.size()-1; + } + return (WindowListener) clonedListeners.get(index); + } + + public WindowListener[] getWindowListeners() { + return (WindowListener[]) windowListeners.toArray(); + } + + protected void consumeWindowEvent(WindowEvent e) { + if(DEBUG_WINDOW_EVENT) { + System.err.println("consumeWindowEvent: "+e); + } + for(Iterator i = windowListeners.iterator(); i.hasNext(); ) { + WindowListener l = (WindowListener) i.next(); + switch(e.getEventType()) { + case WindowEvent.EVENT_WINDOW_RESIZED: + l.windowResized(e); + break; + case WindowEvent.EVENT_WINDOW_MOVED: + l.windowMoved(e); + break; + case WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY: + l.windowDestroyNotify(e); + break; + case WindowEvent.EVENT_WINDOW_GAINED_FOCUS: + l.windowGainedFocus(e); + break; + case WindowEvent.EVENT_WINDOW_LOST_FOCUS: + l.windowLostFocus(e); + break; + case WindowEvent.EVENT_WINDOW_REPAINT: + l.windowRepaint((WindowUpdateEvent)e); + break; + default: + throw + new NativeWindowException("Unexpected window event type " + + e.getEventType()); + } + } + } + + /** + * @param focusGained + */ + protected void focusChanged(boolean focusGained) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.focusChanged: ("+getThreadName()+"): "+focusGained+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + } + if (focusGained) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_GAINED_FOCUS); + } else { + sendWindowEvent(WindowEvent.EVENT_WINDOW_LOST_FOCUS); + } + } + + protected void visibleChanged(boolean visible) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.visibleChanged ("+getThreadName()+"): "+this.visible+" -> "+visible+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + // Exception e = new Exception("Window.visibleChanged ("+getThreadName()+"): "+this.visible+" -> "+visible+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + // e.printStackTrace(); + } + this.visible = visible ; + } + + protected void sizeChanged(int newWidth, int newHeight) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.sizeChanged: ("+getThreadName()+"): "+width+"x"+height+" -> "+newWidth+"x"+newHeight+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + } + if(width != newWidth || height != newHeight) { + width = newWidth; + height = newHeight; + if(!fullscreen) { + nfs_width=width; + nfs_height=height; + } + if(isNativeValid()) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); + } + } + } + + protected void positionChanged(int newX, int newY) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.positionChanged: ("+getThreadName()+"): "+x+"/"+y+" -> "+newX+"/"+newY+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + } + if( 0==parentWindowHandle && ( x != newX || y != newY ) ) { + x = newX; + y = newY; + if(!fullscreen) { + nfs_x=x; + nfs_y=y; + } + sendWindowEvent(WindowEvent.EVENT_WINDOW_MOVED); + } + } + + protected void windowDestroyNotify() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.windowDestroyNotify START "+getThreadName()); + } + + enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); + + if(handleDestroyNotify && isValid()) { + destroy(); + } + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.windowDestroyeNotify END "+getThreadName()); + } + } + + protected void windowDestroyed() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.windowDestroyed "+getThreadName()); + } + invalidate(); + } + + public void windowRepaint(int x, int y, int width, int height) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.windowRepaint "+getThreadName()+" - "+x+"/"+y+" "+width+"x"+height); + } + if(0>width) { + width=this.width; + } + if(0>height) { + height=this.height; + } + + NEWTEvent e = new WindowUpdateEvent(WindowEvent.EVENT_WINDOW_REPAINT, this, System.currentTimeMillis(), + new Rectangle(x, y, width, height)); + if(isNativeValid()) { + doEvent(false, false, e); + } + } + + protected boolean reparentWindowImpl() { + // default implementation, no native reparenting support + return false; + } + + protected int getWindowLockRecursionCount() { + return windowLock.getRecursionCount(); + } + + // + // Reflection helper .. + // + + private static Class[] getCustomConstructorArgumentTypes(Class windowClass) { + Class[] argTypes = null; + try { + Method m = windowClass.getDeclaredMethod("getCustomConstructorArgumentTypes", new Class[] {}); + argTypes = (Class[]) m.invoke(null, null); + } catch (Throwable t) {} + return argTypes; + } + + private static int verifyConstructorArgumentTypes(Class[] types, Object[] args) { + if(types.length != args.length) { + return -1; + } + for(int i=0; i * This implementation does not make the OpenGL context current
- * before calling the various input EventListener callbacks (MouseListener, KeyListener, - * etc.).
- * This design decision is made to favor a more performant and simplified - * implementation, as well as the event dispatcher shall be allowed - * not having a notion about OpenGL. + * before calling the various input EventListener callbacks, ie {@link com.jogamp.newt.event.MouseListener} etc.
+ * This design decision is made in favor of a more performant and simplified + * implementation. Also the event dispatcher shall be implemented OpenGL agnostic.
+ * To be able to use OpenGL commands from within such input {@link com.jogamp.newt.event.NEWTEventListener},
+ * you can inject {@link javax.media.opengl.GLRunnable} objects + * via {@link #invoke(boolean, javax.media.opengl.GLRunnable)} to the OpenGL command stream.
*

*/ -public class GLWindow extends Window implements GLAutoDrawable { - private Window window; +public class GLWindow implements GLAutoDrawable, Window { + private WindowImpl window; /** * Constructor. Do not call this directly -- use {@link #create()} instead. */ protected GLWindow(Window window) { - this.startTime = System.currentTimeMillis(); - this.window = window; - this.window.setHandleDestroyNotify(false); + resetPerfCounter(); + this.window = (WindowImpl) window; + ((WindowImpl)this.window).setHandleDestroyNotify(false); window.addWindowListener(new WindowAdapter() { public void windowRepaint(WindowUpdateEvent e) { - if( !windowIsLocked() && null == getAnimator() ) { + if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { display(); } } public void windowResized(WindowEvent e) { sendReshape = true; - if( !windowIsLocked() && null == getAnimator() ) { + if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { display(); } } public void windowDestroyNotify(WindowEvent e) { - if( !windowIsLocked() && null == getAnimator() ) { + if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { destroy(); } else { sendDestroy = true; } } }); + this.window.setLifecycleHook(new GLLifecycleHook()); } - /** Creates a new GLWindow attaching the given window - not owning the Window. */ - public static GLWindow create(Window window) { - return create(null, window, null, false); - } - - /** Creates a new GLWindow attaching a new native child Window of the given parentNativeWindow - with the given GLCapabilities - owning the Window */ - public static GLWindow create(NativeWindow parentNativeWindow, GLCapabilities caps) { - return create(parentNativeWindow, null, caps, false); - } - - /** Creates a new GLWindow attaching a new decorated Window on the local display, screen 0, with a - dummy visual ID and given GLCapabilities - owning the window */ + /** + * Creates a new GLWindow attaching a new Window referencing a new Screen + * with the given GLCapabilities. + *

+ * The resulting GLWindow owns the Window, Screen and Device, ie it will be destructed. + */ public static GLWindow create(GLCapabilities caps) { - return create(null, null, caps, false); + return new GLWindow(NewtFactory.createWindow(caps)); } - /** Creates a new GLWindow attaching a new Window on the local display, screen 0, with a - dummy visual ID and given GLCapabilities - owning the window */ - public static GLWindow create(GLCapabilities caps, boolean undecorated) { - return create(null, null, caps, undecorated); + /** + * Creates a new GLWindow attaching a new Window referencing the given Screen + * with the given GLCapabilities. + *

+ * The resulting GLWindow owns the Window, ie it will be destructed. + */ + public static GLWindow create(Screen screen, GLCapabilities caps) { + return new GLWindow(NewtFactory.createWindow(screen, caps)); } - /** Either or: window (prio), or caps and undecorated (2nd choice) */ - private static GLWindow create(NativeWindow parentNativeWindow, Window window, - GLCapabilities caps, - boolean undecorated) { - if (window == null) { - if (caps == null) { - caps = new GLCapabilities(null); // default .. - } - window = NewtFactory.createWindow(parentNativeWindow, caps, undecorated); - } - + /** + * Creates a new GLWindow attaching the given window. + *

+ * The resulting GLWindow does not own the given Window, ie it will not be destructed. + */ + public static GLWindow create(Window window) { return new GLWindow(window); } - - public boolean isNativeValid() { - return (null!=window)?window.isNativeValid():false; - } - - public boolean isValid() { - return (null!=window)?window.isValid():true; - } - - public final Window getInnerWindow() { - return window.getInnerWindow(); - } - public final Object getWrappedWindow() { - return window.getWrappedWindow(); - } - - protected void createNativeImpl() { - shouldNotCallThis(); - } - - protected void closeNativeImpl() { - shouldNotCallThis(); - } - - class DisposeAction implements Runnable { - public void run() { - // Lock: Covered by DestroyAction .. - helper.dispose(GLWindow.this); - } + /** + * Creates a new GLWindow attaching a new child Window + * of the given parentNativeWindow with the given GLCapabilities. + *

+ * The Display/Screen will be compatible with the parentNativeWindow, + * or even identical in case it's a Newt Window. + *

+ * The resulting GLWindow owns the Window, ie it will be destructed. + */ + public static GLWindow create(NativeWindow parentNativeWindow, GLCapabilities caps) { + return new GLWindow(NewtFactory.createWindow(parentNativeWindow, caps)); } - private DisposeAction disposeAction = new DisposeAction(); - - class DestroyAction implements Runnable { - boolean unrecoverable; - public DestroyAction(boolean unrecoverable) { - this.unrecoverable = unrecoverable; - } - public void run() { - // Lock: Have to cover whole workflow (dispose all, context, drawable and window) - windowLock(); - try { - if( !isValid() ) { - return; // nop - } - if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { - Exception e1 = new Exception("GLWindow.destroy("+unrecoverable+") "+Thread.currentThread()+", start: "+GLWindow.this); - e1.printStackTrace(); - } - - if( window.isNativeValid() && null != drawable && drawable.isRealized() ) { - if( null != context && context.isCreated() ) { - // Catch dispose GLExceptions by GLEventListener, just 'print' them - // so we can continue with the destruction. - try { - helper.invokeGL(drawable, context, disposeAction, null); - } catch (GLException gle) { - gle.printStackTrace(); - } - - context.destroy(); - context = null; - } - - drawable.setRealized(false); - drawable = null; - } - - if(null!=window) { - window.destroy(unrecoverable); - } - if(unrecoverable) { - helper=null; - } - if(Window.DEBUG_WINDOW_EVENT || window.DEBUG_IMPLEMENTATION) { - System.out.println("GLWindow.destroy("+unrecoverable+") "+Thread.currentThread()+", fin: "+GLWindow.this); - } - } finally { - windowUnlock(); - } - } - } + //---------------------------------------------------------------------- + // Window Access + // - public void destroy(boolean unrecoverable) { - if( isValid() ) { - runOnEDTIfAvail(true, new DestroyAction(unrecoverable)); + public final Capabilities getChosenCapabilities() { + if (drawable == null) { + return window.getChosenCapabilities(); } - } - - public boolean getPerfLogEnabled() { return perfLog; } - - public void enablePerfLog(boolean v) { - perfLog = v; - } - - protected void setVisibleImpl(boolean visible) { - shouldNotCallThis(); - } - - public void reparentWindow(NativeWindow newParent) { - window.reparentWindow(newParent); - } - class VisibleAction implements Runnable { - boolean visible; - public VisibleAction(boolean visible) { - this.visible = visible; - } - public void run() { - // Lock: Have to cover whole workflow (window, may do nativeCreation, drawable and context) - windowLock(); - try{ - window.setVisible(visible); - if (null == context && visible && 0 != window.getWindowHandle() && 0 5000 ) { dt1 = curTime-startTime; - System.out.println(dt0/1000 +"s: "+ lastFrames + "f, " + (lastFrames*1000)/dt0 + " fps, "+dt0/lastFrames+" ms/f; "+ + System.err.println(dt0/1000 +"s: "+ lastFrames + "f, " + (lastFrames*1000)/dt0 + " fps, "+dt0/lastFrames+" ms/f; "+ "total: "+ dt1/1000+"s, "+(totalFrames*1000)/dt1 + " fps, "+dt1/totalFrames+" ms/f"); lastCheck=curTime; lastFrames=0; @@ -594,15 +524,69 @@ public class GLWindow extends Window implements GLAutoDrawable { } private DisplayAction displayAction = new DisplayAction(); - public long getStartTime() { return startTime; } - public long getCurrentTime() { curTime = System.currentTimeMillis(); return curTime; } - public long getDuration() { return getCurrentTime()-startTime; } - public int getTotalFrames() { return totalFrames; } + /** + * @return Time of the first display call in milliseconds. + * This value is reset if becoming visible again or reparenting. + * In case an animator is used, + * the corresponding {@link javax.media.opengl.GLAnimatorControl} value is returned. + * + * @see javax.media.opengl.GLAnimatorControl#getStartTime() + */ + public final long getStartTime() { + GLAnimatorControl animator = getAnimator(); + if ( null == animator || null == animator.getThread() ) { + // no animator, or not started -> use local time + return startTime; + } else { + return animator.getStartTime(); + } + } - private long startTime = 0; - private long curTime = 0; - private long lastCheck = 0; - private int totalFrames = 0, lastFrames = 0; + /** + * @return Time of the last display call in milliseconds. + * This value is reset if becoming visible again or reparenting. + * In case an animator is used, + * the corresponding {@link javax.media.opengl.GLAnimatorControl} value is returned. + * + * @see javax.media.opengl.GLAnimatorControl#getCurrentTime() + */ + public final long getCurrentTime() { + GLAnimatorControl animator = getAnimator(); + if ( null == animator || null == animator.getThread() ) { + // no animator, or not started -> use local time + return curTime; + } else { + return animator.getCurrentTime(); + } + } + + /** + * @return Duration getCurrentTime() - getStartTime(). + * + * @see #getStartTime() + * @see #getCurrentTime() + */ + public final long getDuration() { + return getCurrentTime()-getStartTime(); + } + + /** + * @return Number of frames displayed since the first display call, ie getStartTime(). + * This value is reset if becoming visible again or reparenting. + * In case an animator is used, + * the corresponding {@link javax.media.opengl.GLAnimatorControl} value is returned. + * + * @see javax.media.opengl.GLAnimatorControl#getTotalFrames() + */ + public final int getTotalFrames() { + GLAnimatorControl animator = getAnimator(); + if ( null == animator || null == animator.getThread() ) { + // no animator, or not started -> use local value + return totalFrames; + } else { + return animator.getTotalFrames(); + } + } class SwapBuffersAction implements Runnable { public void run() { @@ -612,77 +596,53 @@ public class GLWindow extends Window implements GLAutoDrawable { private SwapBuffersAction swapBuffersAction = new SwapBuffersAction(); //---------------------------------------------------------------------- - // NativeWindow/Window methods + // GLDrawable methods // - public int lockSurface() throws NativeWindowException { - if(null!=drawable) return drawable.getNativeWindow().lockSurface(); - return window.lockSurface(); - } - - public void unlockSurface() { - if(null!=drawable) drawable.getNativeWindow().unlockSurface(); - else window.unlockSurface(); - } - - public boolean isSurfaceLocked() { - if(null!=drawable) return drawable.getNativeWindow().isSurfaceLocked(); - return window.isSurfaceLocked(); - } - - public Exception getLockedStack() { - if(null!=drawable) return drawable.getNativeWindow().getLockedStack(); - return window.getLockedStack(); + public final NativeWindow getNativeWindow() { + return null!=drawable ? drawable.getNativeWindow() : null; } - public boolean surfaceSwap() { - if(null!=drawable) return drawable.getNativeWindow().surfaceSwap(); - return super.surfaceSwap(); + public final long getHandle() { + return null!=drawable ? drawable.getHandle() : 0; } - public long getWindowHandle() { - if(null!=drawable) return drawable.getNativeWindow().getWindowHandle(); - return window.getWindowHandle(); + public final void destroy() { + window.destroy(); } - public long getSurfaceHandle() { - if(null!=drawable) return drawable.getNativeWindow().getSurfaceHandle(); - return window.getSurfaceHandle(); + public final int getX() { + return window.getX(); } - public AbstractGraphicsConfiguration getGraphicsConfiguration() { - if(null!=drawable) return drawable.getNativeWindow().getGraphicsConfiguration(); - return window.getGraphicsConfiguration(); + public final int getY() { + return window.getY(); } - //---------------------------------------------------------------------- - // GLDrawable methods - // - - public NativeWindow getNativeWindow() { - return null!=drawable ? drawable.getNativeWindow() : null; + public final int getWidth() { + return window.getWidth(); } - public long getHandle() { - return null!=drawable ? drawable.getHandle() : 0; + public final int getHeight() { + return window.getHeight(); } //---------------------------------------------------------------------- // GLDrawable methods that are not really needed // - public GLContext createContext(GLContext shareWith) { + public final GLContext createContext(GLContext shareWith) { return drawable.createContext(shareWith); } - public void setRealized(boolean realized) { + public final void setRealized(boolean realized) { } - public boolean isRealized() { + public final boolean isRealized() { return ( null != drawable ) ? drawable.isRealized() : false; } - public GLCapabilities getChosenGLCapabilities() { + public final GLCapabilities getChosenGLCapabilities() { if (drawable == null) { throw new GLException("No drawable yet"); } @@ -690,11 +650,177 @@ public class GLWindow extends Window implements GLAutoDrawable { return drawable.getChosenGLCapabilities(); } - public GLProfile getGLProfile() { + public final GLProfile getGLProfile() { if (drawable == null) { throw new GLException("No drawable yet"); } return drawable.getGLProfile(); } + + //---------------------------------------------------------------------- + // Window completion + // + public final void windowRepaint(int x, int y, int width, int height) { + window.windowRepaint(x, y, width, height); + } + + public final void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { + window.enqueueEvent(wait, event); + } + + public final void runOnEDTIfAvail(boolean wait, final Runnable task) { + window.runOnEDTIfAvail(wait, task); + } + + public final SurfaceUpdatedListener getSurfaceUpdatedListener(int index) { + return window.getSurfaceUpdatedListener(index); + } + + public final SurfaceUpdatedListener[] getSurfaceUpdatedListeners() { + return window.getSurfaceUpdatedListeners(); + } + + public final void removeAllSurfaceUpdatedListener() { + window.removeAllSurfaceUpdatedListener(); + } + + public final void removeSurfaceUpdatedListener(SurfaceUpdatedListener l) { + window.removeSurfaceUpdatedListener(l); + } + + public final void addSurfaceUpdatedListener(SurfaceUpdatedListener l) { + window.addSurfaceUpdatedListener(l); + } + + public final void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException { + window.addSurfaceUpdatedListener(index, l); + } + + public void sendWindowEvent(int eventType) { + window.sendWindowEvent(eventType); + } + + public final WindowListener getWindowListener(int index) { + return window.getWindowListener(index); + } + + public final WindowListener[] getWindowListeners() { + return window.getWindowListeners(); + } + + public final void removeWindowListener(WindowListener l) { + window.removeWindowListener(l); + } + + public final void addWindowListener(WindowListener l) { + window.addWindowListener(l); + } + + public final void addWindowListener(int index, WindowListener l) throws IndexOutOfBoundsException { + window.addWindowListener(index, l); + } + + public final void addKeyListener(KeyListener l) { + window.addKeyListener(l); + } + + public final void addKeyListener(int index, KeyListener l) { + window.addKeyListener(index, l); + } + + public final void removeKeyListener(KeyListener l) { + window.removeKeyListener(l); + } + + public final KeyListener getKeyListener(int index) { + return window.getKeyListener(index); + } + + public final KeyListener[] getKeyListeners() { + return window.getKeyListeners(); + } + + public final void addMouseListener(MouseListener l) { + window.addMouseListener(l); + } + + public final void addMouseListener(int index, MouseListener l) { + window.addMouseListener(index, l); + } + + public final void removeMouseListener(MouseListener l) { + window.removeMouseListener(l); + } + + public final MouseListener getMouseListener(int index) { + return window.getMouseListener(index); + } + + public final MouseListener[] getMouseListeners() { + return window.getMouseListeners(); + } + + //---------------------------------------------------------------------- + // NativeWindow completion + // + + public final int lockSurface() { + return window.lockSurface(); + } + + public final void unlockSurface() throws NativeWindowException { + window.unlockSurface(); + } + + public final boolean isSurfaceLockedByOtherThread() { + return window.isSurfaceLockedByOtherThread(); + } + + public final boolean isSurfaceLocked() { + return window.isSurfaceLocked(); + } + + public final Thread getSurfaceLockOwner() { + return window.getSurfaceLockOwner(); + + } + + public final Exception getSurfaceLockStack() { + return window.getSurfaceLockStack(); + } + + public final boolean surfaceSwap() { + return window.surfaceSwap(); + } + + public final void invalidate() { + window.invalidate(); + } + + public final long getWindowHandle() { + return window.getWindowHandle(); + + } + + public final long getSurfaceHandle() { + return window.getSurfaceHandle(); + + } + + public final AbstractGraphicsConfiguration getGraphicsConfiguration() { + return window.getGraphicsConfiguration(); + } + + public final long getDisplayHandle() { + return window.getDisplayHandle(); + } + + public final int getScreenIndex() { + return window.getScreenIndex(); + } + + public final void surfaceUpdated(Object updater, NativeWindow window, long when) { + window.surfaceUpdated(updater, window, when); + } } -- cgit v1.2.3