From 0feca163be47db2ea94f7546e696136d6f9496e9 Mon Sep 17 00:00:00 2001
From: Sven Gothel
* In case parentWindowObject
is a different {@link javax.media.nativewindow.NativeWindow} implementation,
- * you have to handle all events appropriatly.
* * @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.
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.
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.
- * 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.
+ * 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.
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,
*/ - 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)}:
* no native window is created yet andsetVisible(true)
shall be repeated when it is.
** 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 && 0
0) { - 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.
+ * + * @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.
+ * In case the new parent is not null and a Window, + * this window is added to it's list of children.
- - * @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( 0 0) { + 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 && 0 0) { + 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, viasetVisible(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, iegetStartTime()
. + * 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); + } } diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index 6b8f2b73f..4bf2545ab 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -600,10 +600,11 @@ static int WmKeyUp(JNIEnv *env, jobject window, UINT wkey, UINT repCnt, } static void NewtWindows_requestFocus (JNIEnv *env, jobject window, HWND hwnd, BOOL reparented) { - HWND pHwnd = GetParent(hwnd); - HWND current = GetFocus(); - DBG_PRINT("*** WindowsWindow: requestFocus.0 parent %p, window %p, isCurrent %d\n", - (void*) pHwnd, (void*)hwnd, current==hwnd); + HWND pHwnd, current; + pHwnd = GetParent(hwnd); + current = GetFocus(); + DBG_PRINT("*** WindowsWindow: requestFocus.S parent %p, window %p, isCurrent %d, reparented %d\n", + (void*) pHwnd, (void*)hwnd, current==hwnd, (int) reparented); if(reparented || current!=hwnd) { if( JNI_FALSE == (*env)->CallBooleanMethod(env, window, focusActionID) ) { UINT flags = SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; @@ -621,6 +622,7 @@ static void NewtWindows_requestFocus (JNIEnv *env, jobject window, HWND hwnd, BO DBG_PRINT("*** WindowsWindow: requestFocus.X0\n"); } } + DBG_PRINT("*** WindowsWindow: requestFocus.XX\n"); } static RECT * UpdateInsets(JNIEnv *env, HWND hwnd, jobject window) @@ -738,12 +740,12 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, env = wud->jenv; window = wud->jinstance; + // DBG_PRINT("*** WindowsWindow: thread 0x%X - window %p -> %p, 0x%X %d/%d\n", (int)GetCurrentThreadId(), wnd, window, message, (int)LOWORD(lParam), (int)HIWORD(lParam)); + if (NULL==window || NULL==env) { return DefWindowProc(wnd, message, wParam, lParam); } - // DBG_PRINT("*** WindowsWindow: window %p -> %p, 0x%X %d/%d\n", wnd, window, message, (int)LOWORD(lParam), (int)HIWORD(lParam)); - switch (message) { // @@ -961,6 +963,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsDisplay_Dispatch // Periodically take a break do { gotOne = PeekMessage(&msg, (HWND) NULL, 0, 0, PM_REMOVE); + // DBG_PRINT("*** WindowsWindow.DispatchMessages0: thread 0x%X - gotOne %d\n", (int)GetCurrentThreadId(), (int)gotOne); if (gotOne) { ++i; #ifdef DEBUG_KEYS @@ -1149,7 +1152,8 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_CreateWi (HINSTANCE) (intptr_t) hInstance, NULL); - DBG_PRINT("*** WindowsWindow: CreateWindow parent %p, window %p, %d/%d %dx%d\n", parentWindow, window, x, y, width, height); + DBG_PRINT("*** WindowsWindow: CreateWindow thread 0xX, parent %p, window %p, %d/%d %dx%d\n", + (int)GetCurrentThreadId(), parentWindow, window, x, y, width, height); if (NULL == window) { int lastError = (int) GetLastError(); @@ -1186,7 +1190,7 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_CreateWi JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_DestroyWindow0 (JNIEnv *env, jobject obj, jlong window) { - DBG_PRINT("*** WindowsWindow: DestroyWindow window %p\n", window); + DBG_PRINT("*** WindowsWindow: DestroyWindow thread 0x%X, window %p\n", (int)GetCurrentThreadId(), window); DestroyWindow((HWND) (intptr_t) window); } @@ -1362,10 +1366,10 @@ static void NewtWindows_reparentWindow(JNIEnv *env, jobject obj, HWND hwndP, HWN /* * Class: com_jogamp_newt_impl_windows_WindowsWindow - * Method: setFullscreen + * Method: reconfigureWindow0 * Signature: (JIIIIZ)V */ -JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setFullscreen0 +JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_reconfigureWindow0 (JNIEnv *env, jobject obj, jlong parent, jlong window, jint x, jint y, jint width, jint height, jboolean bIsUndecorated) { UINT flags; @@ -1374,7 +1378,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setFullsc HWND hWndInsertAfter; BOOL isVisible = IsWindowVisible(hwnd); - DBG_PRINT("*** WindowsWindow: setFullscreen.1 parent %p, window %p, %d/%d %dx%d undeco %d visible\n", + DBG_PRINT("*** WindowsWindow: reconfigureWindow0.1 parent %p, window %p, %d/%d %dx%d undeco %d visible\n", parent, window, x, y, width, height, bIsUndecorated, isVisible); NewtWindows_reparentWindow(env, obj, hwndP, hwnd, FALSE, x, y, width, height, bIsUndecorated); @@ -1388,11 +1392,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setFullsc } SetWindowPos(hwnd, hWndInsertAfter, x, y, width, height, flags); - if(isVisible) { - NewtWindows_requestFocus ( env, obj, hwnd, TRUE ); // request focus on this window, if not already .. - } - - DBG_PRINT("*** WindowsWindow: setFullscreen.X\n"); + DBG_PRINT("*** WindowsWindow: reconfigureWindow0.X\n"); (*env)->CallVoidMethod(env, obj, sizeChangedID, (jint) width, (jint) height); // resize necessary .. } @@ -1409,11 +1409,6 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_reparentW BOOL isVisible = IsWindowVisible(hwnd); NewtWindows_reparentWindow(env, obj, hwndP, hwnd, FALSE, x, y, width, height, bIsUndecorated); - - if(isVisible) { - NewtWindows_requestFocus ( env, obj, hwnd, TRUE ); // request focus on this window, if not already .. - } - } /* @@ -1440,9 +1435,9 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setTitle0 * Signature: (J)V */ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_requestFocus0 - (JNIEnv *env, jobject obj, jlong window) + (JNIEnv *env, jobject obj, jlong window, jboolean bReparented) { - DBG_PRINT("*** WindowsWindow: RequestFocus0\n"); - NewtWindows_requestFocus ( env, obj, (HWND) (intptr_t) window, FALSE ) ; + DBG_PRINT("*** WindowsWindow: RequestFocus0: reparented %d\n", (int)bReparented); + NewtWindows_requestFocus ( env, obj, (HWND) (intptr_t) window, bReparented ) ; } diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 61575c947..350a0a704 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -393,27 +393,22 @@ static Window NewtWindows_getParent (Display *dpy, Window w) { return 0; } */ -static void NewtWindows_requestFocus0 (JNIEnv *env, jobject window, Display *dpy, Window w, XWindowAttributes *xwa, - Bool reparented){ +static void NewtWindows_requestFocus (JNIEnv *env, jobject window, Display *dpy, Window w, + Bool reparented) { + XWindowAttributes xwa; Window focus_return; int revert_to_return; + + XGetWindowAttributes(dpy, w, &xwa); XGetInputFocus(dpy, &focus_return, &revert_to_return); if(reparented || focus_return!=w) { // Avoid 'BadMatch' errors from XSetInputFocus, ie if window is not viewable if( JNI_FALSE == (*env)->CallBooleanMethod(env, window, focusActionID) ) { - if(xwa->map_state == IsViewable) { + if(xwa.map_state == IsViewable) { XSetInputFocus(dpy, w, RevertToParent, CurrentTime); } } } -} - -static void NewtWindows_requestFocus1 (JNIEnv *env, jobject window, Display *dpy, Window w, - Bool reparented) { - XWindowAttributes xwa; - - XGetWindowAttributes(dpy, w, &xwa); - NewtWindows_requestFocus0 (env, window, dpy, w, &xwa, reparented); XSync(dpy, False); } @@ -904,7 +899,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CloseWindow0 XUnmapWindow(dpy, w); // Drain all events related to this window .. - JNICALL Java_com_jogamp_newt_impl_x11_X11Display_DispatchMessages0(env, obj, display, javaObjectAtom, wmDeleteAtom); + Java_com_jogamp_newt_impl_x11_X11Display_DispatchMessages0(env, obj, display, javaObjectAtom, wmDeleteAtom); XDestroyWindow(dpy, w); XSync(dpy, False); @@ -1028,9 +1023,6 @@ static void NewtWindows_reparentWindow if(JNI_TRUE == isVisible) { XMapRaised(dpy, w); XSync(dpy, False); - - NewtWindows_requestFocus0 ( env, obj, dpy, w, xwa, True ); - XSync(dpy, False); } DBG_PRINT( "X11: reparentWindow X\n"); @@ -1038,10 +1030,10 @@ static void NewtWindows_reparentWindow /* * Class: com_jogamp_newt_impl_x11_X11Window - * Method: setPosSizeDecor0 + * Method: reconfigureWindow0 * Signature: (JJIJIIIIZ)V */ -JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_setPosSizeDecor0 +JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_reconfigureWindow0 (JNIEnv *env, jobject obj, jlong jparent, jlong display, jint screen_index, jlong window, jint x, jint y, jint width, jint height, jboolean undecorated, jboolean isVisible) { @@ -1052,7 +1044,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_setPosSizeDecor0 XWindowChanges xwc; XWindowAttributes xwa; - DBG_PRINT( "X11: setPosSizeDecor0 dpy %p, parent %p, win %p, %d/%d %dx%d undec %d, visible %d\n", + DBG_PRINT( "X11: reconfigureWindow0 dpy %p, parent %p, win %p, %d/%d %dx%d undec %d, visible %d\n", (void*)dpy, (void*) jparent, (void*)w, x, y, width, height, undecorated, isVisible); if(dpy==NULL) { @@ -1110,9 +1102,9 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_reparentWindow0 * Signature: (JJ)V */ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_requestFocus0 - (JNIEnv *env, jobject obj, jlong display, jlong window) + (JNIEnv *env, jobject obj, jlong display, jlong window, jboolean bReparented) { - NewtWindows_requestFocus1 ( env, obj, (Display *) (intptr_t) display, (Window)window, False ) ; + NewtWindows_requestFocus ( env, obj, (Display *) (intptr_t) display, (Window)window, bReparented ) ; } /* -- cgit v1.2.3