diff options
Diffstat (limited to 'src/newt/classes/com')
68 files changed, 13419 insertions, 0 deletions
diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java new file mode 100644 index 000000000..bec014c0b --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -0,0 +1,223 @@ +/** + * 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.util.EDTUtil; +import com.jogamp.newt.impl.Debug; +import com.jogamp.newt.impl.DisplayImpl; + +import java.util.*; + +import javax.media.nativewindow.AbstractGraphicsDevice; + +public abstract class Display { + public static final boolean DEBUG = Debug.debug("Display"); + + /** return precomputed hashCode from FQN {@link #getFQName()} */ + public abstract int hashCode(); + + /** return true if obj is of type Display and both FQN {@link #getFQName()} equals */ + public boolean equals(Object obj) { + if (this == obj) { return true; } + if (obj instanceof Display) { + Display d = (Display)obj; + return d.getFQName().equals(getFQName()); + } + return false; + } + + /** + * @return true if the native display handle is valid and ready to operate, + * otherwise false. + * + * @see #destroy() + */ + public abstract boolean isNativeValid(); + + /** + * @return number of references by Screen + */ + public abstract int getReferenceCount(); + + public abstract void destroy(); + + /** + * @return the value set by {@link #setDestroyWhenUnused(boolean)} + * or the default <code>false</code>. + * + * @see #addReference() + * @see #removeReference() + */ + public abstract boolean getDestroyWhenUnused(); + + /** + * Handles the lifecycle of the native Display instance.<br> + * If set to <code>true</code>, the last {@link #removeReference()} call + * will destroy this instance, otherwise it will stay alive.<br> + * Default is <code>false</code>. + * + * @see #addReference() + * @see #removeReference() + */ + public abstract void setDestroyWhenUnused(boolean v); + + /** + * The 1st call will initiate native creation, + * since we follow the lazy creation pattern. + * + * @return number of references after adding one + * @see #removeReference() + */ + public abstract int addReference(); + + /** + * The last call may destroy this instance, + * if {@link #getDestroyWhenUnused()} returns <code>true</code>. + * + * @return number of references after removing one + * @see #addReference() + * @see #getDestroyWhenUnused() + * @see #setDestroyWhenUnused(boolean) + */ + public abstract int removeReference(); + + public abstract AbstractGraphicsDevice getGraphicsDevice(); + + /** + * @return the fully qualified Display name, + * which is a key of {@link #getType()} + {@link #getName()} + {@link #getId()} + */ + public abstract String getFQName(); + + public abstract long getHandle(); + + /** + * @return this display internal serial id + */ + public abstract int getId(); + + /** + * @return this display instance name as defined at creation time + */ + public abstract String getName(); + + /** + * @return the native display type, ie {@link javax.media.nativewindow.NativeWindowFactory#getNativeWindowType(boolean)} + */ + public abstract String getType(); + + public abstract EDTUtil getEDTUtil(); + + public abstract boolean isEDTRunning(); + + public abstract void dispatchMessages(); + + // Global Displays + protected static ArrayList displayList = new ArrayList(); + protected static int displaysActive = 0; + + public static void dumpDisplayList(String prefix) { + synchronized(displayList) { + Iterator i = displayList.iterator(); + System.err.println(prefix+" DisplayList[] entries: "+displayList.size()+" - "+getThreadName()); + for(int j=0; i.hasNext(); j++) { + DisplayImpl d = (DisplayImpl) i.next(); + System.err.println(" ["+j+"] : "+d); + } + } + } + + /** + * + * @param type + * @param name + * @param fromIndex start index, then increasing until found or end of list * + * @return + */ + public static Display getFirstDisplayOf(String type, String name, int fromIndex) { + return getDisplayOfImpl(type, name, fromIndex, 1); + } + + /** + * + * @param type + * @param name + * @param fromIndex start index, then decreasing until found or end of list. -1 is interpreted as size - 1. + * @return + */ + public static Display getLastDisplayOf(String type, String name, int fromIndex) { + return getDisplayOfImpl(type, name, fromIndex, -1); + } + + private static Display getDisplayOfImpl(String type, String name, int fromIndex, int incr) { + synchronized(displayList) { + int i = fromIndex >= 0 ? fromIndex : displayList.size() - 1 ; + while( ( incr > 0 ) ? i < displayList.size() : i >= 0 ) { + Display display = (Display) displayList.get(i); + if( display.getType().equals(type) && + display.getName().equals(name) ) { + return display; + } + i+=incr; + } + } + return null; + } + + /** Returns the global display collection */ + public static Collection getAllDisplays() { + ArrayList list; + synchronized(displayList) { + list = (ArrayList) displayList.clone(); + } + return list; + } + + public static int getActiveDisplayNumber() { + synchronized(displayList) { + return displaysActive; + } + } + + public static String getThreadName() { + return Thread.currentThread().getName(); + } + + public static String toHexString(int hex) { + return "0x" + Integer.toHexString(hex); + } + + public static String toHexString(long hex) { + return "0x" + Long.toHexString(hex); + } + + public static int hashCodeNullSafe(Object o) { + return ( null != o ) ? o.hashCode() : 0; + } +} diff --git a/src/newt/classes/com/jogamp/newt/NewtFactory.java b/src/newt/classes/com/jogamp/newt/NewtFactory.java new file mode 100644 index 000000000..e1b15da69 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/NewtFactory.java @@ -0,0 +1,288 @@ +/* + * 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; + +import javax.media.nativewindow.*; +import com.jogamp.common.jvm.JVMUtil; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.impl.DisplayImpl; +import com.jogamp.newt.impl.ScreenImpl; +import com.jogamp.newt.impl.WindowImpl; +import com.jogamp.newt.impl.Debug; + +public class NewtFactory { + public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); + + // Work-around for initialization order problems on Mac OS X + // between native Newt and (apparently) Fmod + static { + JVMUtil.initSingleton(); + NativeWindowFactory.initSingleton(false); // last resort .. + WindowImpl.init(NativeWindowFactory.getNativeWindowType(true)); + } + + public static Class getCustomClass(String packageName, String classBaseName) { + Class clazz = null; + if(packageName!=null || classBaseName!=null) { + String clazzName = packageName + "." + classBaseName ; + try { + clazz = Class.forName(clazzName); + } catch (Throwable t) {} + } + return clazz; + } + + private static boolean useEDT = true; + + /** + * Toggles the usage of an EventDispatchThread while creating a Display.<br> + * The default is enabled.<br> + * The EventDispatchThread is thread local to the Display instance.<br> + */ + public static synchronized void setUseEDT(boolean onoff) { + useEDT = onoff; + } + + /** @see #setUseEDT(boolean) */ + public static boolean useEDT() { return useEDT; } + + /** + * Create a Display entity, incl native creation + */ + public static Display createDisplay(String name) { + return createDisplay(name, true); + } + + public static Display createDisplay(String name, boolean reuse) { + return DisplayImpl.create(NativeWindowFactory.getNativeWindowType(true), name, 0, reuse); + } + + /** + * Create a Display entity using the given implementation type, incl native creation + */ + public static Display createDisplay(String type, String name) { + return createDisplay(type, name, true); + } + + public static Display createDisplay(String type, String name, boolean reuse) { + return DisplayImpl.create(type, name, 0, reuse); + } + + /** + * Create a Screen entity, incl native creation + */ + public static Screen createScreen(Display display, int index) { + return ScreenImpl.create(display, index); + } + + /** + * Create a top level Window entity, incl native creation.<br> + * The Display/Screen is created and owned, ie destructed atomatically.<br> + * A new Display is only created if no preexisting one could be found via {@link Display#getLastDisplayOf(java.lang.String, java.lang.String, int)}. + */ + public static Window createWindow(Capabilities caps) { + return createWindowImpl(NativeWindowFactory.getNativeWindowType(true), caps); + } + + /** + * Create a top level Window entity, incl native creation + */ + public static Window createWindow(Screen screen, Capabilities caps) { + return createWindowImpl(screen, caps); + } + + /** + * Create a child Window entity attached to the given parent, incl native creation.<br> + * The Screen and Display information is regenerated utilizing the parents information.<br> + * <p> + * In case <code>parentWindowObject</code> is a {@link com.jogamp.newt.Window} instance,<br> + * the new window is added to it's list of children.<br> + * This assures proper handling of visibility, creation and destruction.<br> + * {@link com.jogamp.newt.event.WindowEvent#EVENT_WINDOW_RESIZED} is not propagated to the child window for layout<br>, + * you have to add an appropriate {@link com.jogamp.newt.event.WindowListener} for this use case.<br> + * The parents visibility is passed to the new Window<br></p> + * <p> + * In case <code>parentWindowObject</code> is a different {@link javax.media.nativewindow.NativeWindow} implementation,<br> + * you have to handle all events appropriate.<br></p> + * <p> + * + * @param parentWindowObject either a NativeWindow instance + */ + public static Window createWindow(NativeWindow nParentWindow, Capabilities caps) { + final String type = NativeWindowFactory.getNativeWindowType(true); + + Screen screen = null; + Window parentWindow = null; + + if ( nParentWindow instanceof Window ) { + // use parent NEWT Windows Display/Screen + parentWindow = (Window) nParentWindow ; + screen = parentWindow.getScreen(); + } else { + // create a Display/Screen compatible to the NativeWindow + AbstractGraphicsConfiguration nParentConfig = nParentWindow.getGraphicsConfiguration(); + if(null!=nParentConfig) { + AbstractGraphicsScreen nParentScreen = nParentConfig.getScreen(); + AbstractGraphicsDevice nParentDevice = nParentScreen.getDevice(); + Display display = NewtFactory.createDisplay(type, nParentDevice.getHandle(), true); + screen = NewtFactory.createScreen(display, nParentScreen.getIndex()); + } else { + Display display = NewtFactory.createDisplay(type, null, true); // local display + screen = NewtFactory.createScreen(display, 0); // screen 0 + } + screen.setDestroyWhenUnused(true); + } + final Window win = createWindowImpl(nParentWindow, screen, caps); + + win.setSize(nParentWindow.getWidth(), nParentWindow.getHeight()); + if ( null != parentWindow ) { + parentWindow.addChild(win); + win.setVisible(parentWindow.isVisible()); + } + return win; + } + + protected static Window createWindowImpl(NativeWindow parentNativeWindow, Screen screen, Capabilities caps) { + return WindowImpl.create(parentNativeWindow, 0, screen, caps); + } + + protected static Window createWindowImpl(long parentWindowHandle, Screen screen, Capabilities caps) { + return WindowImpl.create(null, parentWindowHandle, screen, caps); + } + + protected static Window createWindowImpl(Screen screen, Capabilities caps) { + return WindowImpl.create(null, 0, screen, caps); + } + + protected static Window createWindowImpl(String type, Capabilities caps) { + Display display = NewtFactory.createDisplay(type, null, true); // local display + Screen screen = NewtFactory.createScreen(display, 0); // screen 0 + screen.setDestroyWhenUnused(true); + return WindowImpl.create(null, 0, screen, caps); + } + + /** + * Create a child Window entity attached to the given parent, incl native creation<br> + * + * @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) { + return createWindowImpl(parentWindowHandle, screen, caps); + } + + /** + * Ability to try a Window type with a constructor argument, if supported ..<p> + * Currently only valid is <code> AWTWindow(Frame frame) </code>, + * 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) { + return WindowImpl.create(cstrArguments, screen, caps); + } + + /** + * Instantiate a Display entity using the native handle. + */ + public static Display createDisplay(String type, long handle, boolean reuse) { + return DisplayImpl.create(type, null, handle, false); + } + + private static final boolean instanceOf(Object obj, String clazzName) { + Class clazz = obj.getClass(); + do { + if(clazz.getName().equals(clazzName)) { + return true; + } + clazz = clazz.getSuperclass(); + } while (clazz!=null); + return false; + } + + public static boolean isScreenCompatible(NativeWindow parent, Screen childScreen) { + // Get parent's NativeWindow details + AbstractGraphicsConfiguration parentConfig = (AbstractGraphicsConfiguration) parent.getGraphicsConfiguration(); + AbstractGraphicsScreen parentScreen = (AbstractGraphicsScreen) parentConfig.getScreen(); + AbstractGraphicsDevice parentDevice = (AbstractGraphicsDevice) parentScreen.getDevice(); + + DisplayImpl childDisplay = (DisplayImpl) childScreen.getDisplay(); + String parentDisplayName = childDisplay.validateDisplayName(null, parentDevice.getHandle()); + String childDisplayName = childDisplay.getName(); + if( ! parentDisplayName.equals( childDisplayName ) ) { + return false; + } + + if( parentScreen.getIndex() != childScreen.getIndex() ) { + return false; + } + return true; + } + + public static Screen createCompatibleScreen(NativeWindow parent) { + return createCompatibleScreen(parent, null); + } + + public static Screen createCompatibleScreen(NativeWindow parent, Screen childScreen) { + // Get parent's NativeWindow details + AbstractGraphicsConfiguration parentConfig = (AbstractGraphicsConfiguration) parent.getGraphicsConfiguration(); + AbstractGraphicsScreen parentScreen = (AbstractGraphicsScreen) parentConfig.getScreen(); + AbstractGraphicsDevice parentDevice = (AbstractGraphicsDevice) parentScreen.getDevice(); + + if(null != childScreen) { + // check if child Display/Screen is compatible already + DisplayImpl childDisplay = (DisplayImpl) childScreen.getDisplay(); + String parentDisplayName = childDisplay.validateDisplayName(null, parentDevice.getHandle()); + String childDisplayName = childDisplay.getName(); + boolean displayEqual = parentDisplayName.equals( childDisplayName ); + boolean screenEqual = parentScreen.getIndex() == childScreen.getIndex(); + if(DEBUG_IMPLEMENTATION) { + System.err.println("NewtFactory.createCompatibleScreen: Display: "+ + parentDisplayName+" =? "+childDisplayName+" : "+displayEqual+"; Screen: "+ + parentScreen.getIndex()+" =? "+childScreen.getIndex()+" : "+screenEqual); + } + if( displayEqual && screenEqual ) { + // match: display/screen + return childScreen; + } + } + + // Prep NEWT's Display and Screen according to the parent + final String type = NativeWindowFactory.getNativeWindowType(true); + Display display = NewtFactory.createDisplay(type, parentDevice.getHandle(), true); + return NewtFactory.createScreen(display, parentScreen.getIndex()); + } +} + diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java new file mode 100644 index 000000000..d7d6baea7 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/Screen.java @@ -0,0 +1,227 @@ +/** + * 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.ScreenModeListener; +import com.jogamp.newt.impl.Debug; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.media.nativewindow.AbstractGraphicsScreen; + +public abstract class Screen { + + /** + * A 10s timeout for screen mode change. It is observed, that some platforms + * need a notable amount of time for this task, especially in case of rotation change. + */ + public static final int SCREEN_MODE_CHANGE_TIMEOUT = 10000; + + public static final boolean DEBUG = Debug.debug("Screen"); + + /** return precomputed hashCode from FQN {@link #getFQName()} */ + public abstract int hashCode(); + + /** return true if obj is of type Display and both FQN {@link #getFQName()} equals */ + public boolean equals(Object obj) { + if (this == obj) { return true; } + if (obj instanceof Screen) { + Screen s = (Screen)obj; + return s.getFQName().equals(getFQName()); + } + return false; + } + + public abstract boolean isNativeValid(); + + /** + * + * @return number of references by Window + */ + public abstract int getReferenceCount(); + + public abstract void destroy(); + + /** + * @return {@link Display#getDestroyWhenUnused()} + * + * @see #addReference() + * @see #removeReference() + * @see Display#setDestroyWhenUnused(boolean) + */ + public abstract boolean getDestroyWhenUnused(); + + /** + * calls {@link Display#setDestroyWhenUnused(boolean)}. + * + * @see #addReference() + * @see #removeReference() + * @see Display#setDestroyWhenUnused(boolean) + */ + public abstract void setDestroyWhenUnused(boolean v); + + /** + * See {@link Display#addReference()} + * + * @see #removeReference() + * @see #setDestroyWhenUnused(boolean) + * @see #getDestroyWhenUnused() + */ + public abstract int addReference(); + + /** + * See {@link Display#removeReference()} + * + * @see #addReference() + * @see #setDestroyWhenUnused(boolean) + * @see #getDestroyWhenUnused() + */ + public abstract int removeReference(); + + public abstract AbstractGraphicsScreen getGraphicsScreen(); + + /** + * @return this Screen index of all Screens of {@link #getDisplay()}. + */ + public abstract int getIndex(); + + /** + * @return the current screen width + */ + public abstract int getWidth(); + + /** + * @return the current screen height + */ + public abstract int getHeight(); + + /** + * @return the associated Display + */ + public abstract Display getDisplay(); + + /** + * @return the screen fully qualified Screen name, + * which is a key of {@link com.jogamp.newt.Display#getFQName()} + {@link #getIndex()}. + */ + public abstract String getFQName(); + + /** + * @param sml ScreenModeListener to be added for ScreenMode change events + */ + public abstract void addScreenModeListener(ScreenModeListener sml); + + /** + * @param sml ScreenModeListener to be removed from ScreenMode change events + */ + public abstract void removeScreenModeListener(ScreenModeListener sml); + + /** + * Return a list of available {@link com.jogamp.newt.ScreenMode}s. + * @return a shallow copy of the internal immutable {@link com.jogamp.newt.ScreenMode}s, + * or null if not implemented for this native type {@link com.jogamp.newt.Display#getType()}. + */ + public abstract List/*<ScreenMode>*/ getScreenModes(); + + /** + * Return the original {@link com.jogamp.newt.ScreenMode}, as used at NEWT initialization. + * @return null if functionality not implemented, + * otherwise the original ScreenMode which is element of the list {@link #getScreenModes()}. + * + */ + public abstract ScreenMode getOriginalScreenMode(); + + /** + * Return the current {@link com.jogamp.newt.ScreenMode}. + * @return null if functionality not implemented, + * otherwise the current ScreenMode which is element of the list {@link #getScreenModes()}. + */ + public abstract ScreenMode getCurrentScreenMode(); + + /** + * Set the current {@link com.jogamp.newt.ScreenMode}. + * @param screenMode to be made current, must be element of the list {@link #getScreenModes()}. + * @return true if successful, otherwise false + */ + public abstract boolean setCurrentScreenMode(ScreenMode screenMode); + + // Global Screens + protected static ArrayList screenList = new ArrayList(); + protected static int screensActive = 0; + + /** + * + * @param type + * @param name + * @param fromIndex start index, then increasing until found or end of list * + * @return + */ + public static Screen getFirstScreenOf(Display display, int idx, int fromIndex) { + return getScreenOfImpl(display, idx, fromIndex, 1); + } + + /** + * + * @param type + * @param name + * @param fromIndex start index, then decreasing until found or end of list. -1 is interpreted as size - 1. + * @return + */ + public static Screen getLastScreenOf(Display display, int idx, int fromIndex) { + return getScreenOfImpl(display, idx, fromIndex, -1); + } + + private static Screen getScreenOfImpl(Display display, int idx, int fromIndex, int incr) { + synchronized(screenList) { + int i = fromIndex >= 0 ? fromIndex : screenList.size() - 1 ; + while( ( incr > 0 ) ? i < screenList.size() : i >= 0 ) { + Screen screen = (Screen) screenList.get(i); + if( screen.getDisplay().equals(display) && + screen.getIndex() == idx ) { + return screen; + } + i+=incr; + } + } + return null; + } + /** Returns the global display collection */ + public static Collection getAllScreens() { + ArrayList list; + synchronized(screenList) { + list = (ArrayList) screenList.clone(); + } + return list; + } + + public static int getActiveScreenNumber() { + synchronized(screenList) { + return screensActive; + } + } +} diff --git a/src/newt/classes/com/jogamp/newt/ScreenMode.java b/src/newt/classes/com/jogamp/newt/ScreenMode.java new file mode 100644 index 000000000..81ce70249 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/ScreenMode.java @@ -0,0 +1,189 @@ +/** + * 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.util.MonitorMode; + +/** Immutable ScreenMode Class, consisting of it's read only components:<br> + * <ul> + * <li>{@link com.jogamp.newt.util.MonitorMode}, non rotated values</li> + * <li><code>rotation</code>, measured counter clockwise (CCW)</li> + * </ul> + * + * <i>Aquire and filter ScreenModes</i><br> + * <ul> + * <li>A List of read only ScreenMode's is being returned by {@link com.jogamp.newt.Screen#getScreenModes()}.</li> + * <li>You may utilize {@link com.jogamp.newt.util.ScreenModeUtil} to filter and select a desired ScreenMode.</li> + * <li>The current ScreenMode can be obtained via {@link com.jogamp.newt.Screen#getCurrentScreenMode()}.</li> + * <li>The initial original ScreenMode (at startup) can be obtained via {@link com.jogamp.newt.Screen#getOriginalScreenMode()}.</li> + * </ul> + * <br> + * + * <i>Changing ScreenModes</i><br> + * <ul> + * <li> Use {@link com.jogamp.newt.Screen#setCurrentScreenMode(com.jogamp.newt.ScreenMode)}</li> + * to change the current ScreenMode of all Screen's referenced via the full qualified name (FQN) + * {@link com.jogamp.newt.Screen#getFQName()}.</li> + * <li> When the last FQN referenced Screen closes, the original ScreenMode ({@link com.jogamp.newt.Screen#getOriginalScreenMode()}) + * is restored.</li> + * </ul> + * <br> + * Example for changing the ScreenMode: + * <pre> + // determine target refresh rate + ScreenMode orig = screen.getOriginalScreenMode(); + int freq = orig.getMonitorMode().getRefreshRate(); + + // target resolution + Dimension res = new Dimension(800, 600); + + // target rotation + int rot = 0; + + // filter available ScreenModes + List screenModes = screen.getScreenModes(); + screenModes = ScreenModeUtil.filterByRate(screenModes, freq); // get the nearest ones + screenModes = ScreenModeUtil.filterByRotation(screenModes, rot); + screenModes = ScreenModeUtil.filterByResolution(screenModes, res); // get the nearest ones + screenModes = ScreenModeUtil.getHighestAvailableBpp(screenModes); + + // pick 1st one .. + screen.setCurrentScreenMode((ScreenMode) screenModes.get(0)); + * </pre> + * + * X11 / AMD just works<br> + * <br> + * X11 / NVidia difficulties + * <pre> + NVidia RANDR RefreshRate Bug + If NVidia's 'DynamicTwinView' is enabled, all refresh rates are + unique, ie consequent numbers starting with the default refresh, ie 50, 51, .. + The only way to workaround it is to disable 'DynamicTwinView'. + Read: http://us.download.nvidia.com/XFree86/Linux-x86/260.19.12/README/configtwinview.html + + Check to see if 'DynamicTwinView' is enable: + nvidia-settings -q :0/DynamicTwinview + + To disable it (workaround), add the following option to your xorg.conf device section: + Option "DynamicTwinView" "False" + + NVidia RANDR Rotation: + To enable it, add the following option to your xorg.conf device section: + Option "RandRRotation" "on" + * </pre> + * + */ +public class ScreenMode implements Cloneable { + /** zero rotation, compared to normal settings */ + public static final int ROTATE_0 = 0; + + /** 90 degrees CCW rotation */ + public static final int ROTATE_90 = 90; + + /** 180 degrees CCW rotation */ + public static final int ROTATE_180 = 180; + + /** 270 degrees CCW rotation */ + public static final int ROTATE_270 = 270; + + MonitorMode monitorMode; + int rotation; + + public static boolean isRotationValid(int rotation) { + return rotation == ScreenMode.ROTATE_0 || rotation == ScreenMode.ROTATE_90 || + rotation == ScreenMode.ROTATE_180 || rotation == ScreenMode.ROTATE_270 ; + } + + /** + * @param monitorMode the monitor mode + * @param rotation the screen rotation, measured counter clockwise (CCW) + */ + public ScreenMode(MonitorMode monitorMode, int rotation) { + if ( !isRotationValid(rotation) ) { + throw new RuntimeException("invalid rotation: "+rotation); + } + this.monitorMode = monitorMode; + this.rotation = rotation; + } + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + /** Returns the unrotated <code>MonitorMode</code> */ + public final MonitorMode getMonitorMode() { + return monitorMode; + } + + /** Returns the CCW rotation of this mode */ + public final int getRotation() { + return rotation; + } + + public final String toString() { + return "[ " + getMonitorMode() + ", " + rotation + " degr ]"; + } + + /** + * Tests equality of two <code>ScreenMode</code> objects + * by evaluating equality of it's components:<br> + * <ul> + * <li><code>monitorMode</code></li> + * <li><code>rotation</code></li> + * </ul> + * <br> + */ + public final boolean equals(Object obj) { + if (this == obj) { return true; } + if (obj instanceof ScreenMode) { + ScreenMode sm = (ScreenMode)obj; + return sm.getMonitorMode().equals(getMonitorMode()) && + sm.getRotation() == this.getRotation() ; + } + return false; + } + + /** + * Returns a combined hash code of it's elements:<br> + * <ul> + * <li><code>monitorMode</code></li> + * <li><code>rotation</code></li> + * </ul> + */ + public final int hashCode() { + // 31 * x == (x << 5) - x + int hash = 31 + getMonitorMode().hashCode(); + hash = ((hash << 5) - hash) + getRotation(); + return hash; + } +} diff --git a/src/newt/classes/com/jogamp/newt/Window.java b/src/newt/classes/com/jogamp/newt/Window.java new file mode 100644 index 000000000..ba7d51e67 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -0,0 +1,413 @@ +/** + * 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.WindowListener; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.ScreenModeListener; +import com.jogamp.newt.impl.Debug; +import javax.media.nativewindow.Capabilities; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.SurfaceUpdatedListener; +import javax.media.nativewindow.util.Insets; +import javax.media.nativewindow.util.Point; + +/** + * 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, ScreenModeListener { + 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"); + + /** A 1s timeout while waiting for a native action response, ie {@link #setVisible(boolean)}. */ + public static final long TIMEOUT_NATIVEWINDOW = 1000; + + // + // Lifecycle + // + + /** + * @return True if native window is valid, can be created or recovered. + * Otherwise false, ie this window is unrecoverable due to a <code>destroy(true)</code> call. + * + * @see #destroy(boolean) + * @see #setVisible(boolean) + */ + boolean isValid(); + + /** + * @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) + */ + boolean isNativeValid(); + + /** + * @return The associated Screen + */ + Screen getScreen(); + + /** + * @return The requested capabilities + */ + Capabilities getRequestedCapabilities(); + + Capabilities getChosenCapabilities(); + + /** + * + * <p> + * destroys the window and children and releases + * windowing related resources.<br></p> + * <p> + * all other resources and states are kept intact, + * ie listeners, parent handles, size, position and Screen reference.<br></p> + * + * @see #destroy(boolean) + * @see #invalidate() + */ + void destroy(); + + /** + * + * 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 <code>setVisible(true)</code>. + * @see #destroy() + * @see #invalidate(boolean) + * @see #setVisible(boolean) + */ + void destroy(boolean unrecoverable); + + /** + * <p> + * <code>setVisible</code> makes the window and children visible if <code>visible</code> is true, + * otherwise the window and children becomes invisible.<br></p> + * <p> + * The <code>setVisible(true)</code> is responsible to actual create the native window.<br></p> + * <p> + * Zero size semantics are respected, see {@link #setSize(int,int)}:<br> + * <pre> + * if ( 0 == windowHandle && visible ) { + * this.visible = visible; + * if( 0<width*height ) { + * createNative(); + * } + * } else if ( this.visible != visible ) { + * this.visible = visible; + * setNativeSizeImpl(); + * } + * </pre></p> + * <p> + * In case this window is a child window and a parent {@link javax.media.nativewindow.NativeWindow} is being used,<br> + * the parent's {@link javax.media.nativewindow.NativeWindow} handle is retrieved via {@link javax.media.nativewindow.NativeWindow#getWindowHandle()}.<br> + * If this action fails, ie if the parent {@link javax.media.nativewindow.NativeWindow} is not valid yet,<br> + * no native window is created yet and <code>setVisible(true)</code> shall be repeated when it is.<br></p> + */ + 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 + * Total size of the window will be + * {@code width+insets.left+insets.right, height+insets.top+insets.bottom}<br> + * <p> + * Zero size semantics are respected, see {@link #setVisible(boolean)}:<br> + * <pre> + * if ( 0 != windowHandle && 0>=width*height && visible ) { + * setVisible(false); + * } else if ( 0 == windowHandle && 0<width*height && visible ) { + * setVisible(true); + * } else { + * // as expected .. + * } + * </pre></p> + * <p> + * This call is ignored if in fullscreen mode.<br></p> + * + * @param width of the client area of the window + * @param height of the client area of the window + */ + 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; + } + + /** + * Change this window's parent window.<br> + * <P> + * In case the old parent is not null and a Window, + * this window is removed from it's list of children.<br> + * In case the new parent is not null and a Window, + * this window is added to it's list of children.<br></P> + * + * @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 + * decorations (so the client area will be placed at + * {@code x+insets.left,y+insets.top}.<br> + * + * This call is ignored if in fullscreen mode.<br> + * + * @param x coord of the top left corner + * @param y coord of the top left corner + */ + void setPosition(int x, int y); + + int getX(); + + int getY(); + + /** + * 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(); + + void setUndecorated(boolean value); + + boolean isUndecorated(); + + void setTitle(String title); + + 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(); + } + + /** + * 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); + + void requestFocus(); + + boolean hasFocus(); + + void windowRepaint(int x, int y, int width, int height); + + void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event); + + void runOnEDTIfAvail(boolean wait, final Runnable task); + + + // + // SurfaceUpdateListener + // + + /** + * Appends the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} to the end of + * the list. + */ + void addSurfaceUpdatedListener(SurfaceUpdatedListener l); + + /** + * + * Inserts the given {@link com.jogamp.newt.event.SurfaceUpdatedListener} at the + * specified position in the list.<br> + * + * @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 + */ + void addSurfaceUpdatedListener(int index, SurfaceUpdatedListener l) throws IndexOutOfBoundsException; + + void removeAllSurfaceUpdatedListener(); + + void removeSurfaceUpdatedListener(SurfaceUpdatedListener l); + + SurfaceUpdatedListener getSurfaceUpdatedListener(int index); + + SurfaceUpdatedListener[] getSurfaceUpdatedListeners(); + + + // + // WindowListener + // + + public void sendWindowEvent(int eventType); + + /** + * + * Appends the given {@link com.jogamp.newt.event.WindowListener} to the end of + * the list. + */ + void addWindowListener(WindowListener l); + + /** + * + * Inserts the given {@link com.jogamp.newt.event.WindowListener} at the + * specified position in the list.<br> + * + * @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 + */ + void addWindowListener(int index, WindowListener l) throws IndexOutOfBoundsException; + + void removeWindowListener(WindowListener l); + + WindowListener getWindowListener(int index); + + WindowListener[] getWindowListeners(); + + // + // KeyListener + // + + + /** + * + * Appends the given {@link com.jogamp.newt.event.KeyListener} to the end of + * the list. + */ + void addKeyListener(KeyListener l); + + /** + * + * Inserts the given {@link com.jogamp.newt.event.KeyListener} at the + * specified position in the list.<br> + * + * @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 + */ + void addKeyListener(int index, KeyListener l); + + void removeKeyListener(KeyListener l); + + KeyListener getKeyListener(int index); + + KeyListener[] getKeyListeners(); + + + // + // MouseListener + // + + /** + * + * Appends the given {@link com.jogamp.newt.event.MouseListener} to the end of + * the list. + */ + void addMouseListener(MouseListener l); + + /** + * + * Inserts the given {@link com.jogamp.newt.event.MouseListener} at the + * specified position in the list.<br> + * + * @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 + */ + void addMouseListener(int index, MouseListener l); + + void removeMouseListener(MouseListener l); + + MouseListener getMouseListener(int index); + + MouseListener[] getMouseListeners(); + +} diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java new file mode 100644 index 000000000..3ba721855 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/awt/NewtCanvasAWT.java @@ -0,0 +1,328 @@ +/** + * 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.awt; + +import com.jogamp.newt.Display; +import java.lang.reflect.*; +import java.security.*; + +import java.awt.Canvas; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.KeyboardFocusManager; + +import javax.media.nativewindow.*; + +import com.jogamp.newt.event.awt.AWTAdapter; +import com.jogamp.newt.event.awt.AWTParentWindowAdapter; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.Window; +import com.jogamp.newt.impl.Debug; + +public class NewtCanvasAWT extends java.awt.Canvas { + public static final boolean DEBUG = Debug.debug("Window"); + + NativeWindow nativeWindow = null; + Window newtChild = null; + AWTAdapter awtAdapter = null; + + /** + * Instantiates a NewtCanvas without a NEWT child.<br> + */ + public NewtCanvasAWT() { + super(); + } + + /** + * Instantiates a NewtCanvas with a NEWT child. + */ + public NewtCanvasAWT(Window child) { + super(); + setNEWTChild(child); + } + + class FocusAction implements Window.FocusRunnable { + public boolean run() { + if ( EventQueue.isDispatchThread() ) { + focusActionImpl.run(); + } else { + try { + EventQueue.invokeAndWait(focusActionImpl); + } catch (Exception e) { + throw new NativeWindowException(e); + } + } + return focusActionImpl.result; + } + + class FocusActionImpl implements Runnable { + public final boolean result = false; // NEWT shall always proceed requesting the native focus + public void run() { + if(DEBUG) { + System.err.println("FocusActionImpl.run() "+Display.getThreadName()); + } + NewtCanvasAWT.this.requestFocusAWTParent(); + KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); + kfm.clearGlobalFocusOwner(); + } + } + FocusActionImpl focusActionImpl = new FocusActionImpl(); + } + FocusAction focusAction = new FocusAction(); + + /** sets a new NEWT child, provoking reparenting on the NEWT level. */ + public NewtCanvasAWT setNEWTChild(Window child) { + if(newtChild!=child) { + newtChild = child; + if(null!=nativeWindow) { + java.awt.Container cont = getContainer(this); + // reparent right away, addNotify has been called already + reparentWindow( (null!=newtChild) ? true : false, cont ); + } + } + return this; + } + + /** @return the current NEWT child */ + public Window getNEWTChild() { + return newtChild; + } + + /** @return this AWT Canvas NativeWindow representation, may be null in case {@link #removeNotify()} has been called, + * or {@link #addNotify()} hasn't been called yet.*/ + public NativeWindow getNativeWindow() { return nativeWindow; } + + void setWindowAdapter(boolean attach) { + if(null!=awtAdapter) { + awtAdapter.removeFrom(this); + awtAdapter=null; + } + if(attach && null!=newtChild) { + awtAdapter = new AWTParentWindowAdapter(newtChild).addTo(this); + } + } + + static java.awt.Container getContainer(java.awt.Component comp) { + while( null != comp ) { + if( comp instanceof java.awt.Container ) { + return (java.awt.Container) comp; + } + comp = comp.getParent(); + } + return null; + } + + public void addNotify() { + super.addNotify(); + disableBackgroundErase(); + java.awt.Container cont = getContainer(this); + if(DEBUG) { + // if ( isShowing() == false ) -> Container was not visible yet. + // if ( isShowing() == true ) -> Container is already visible. + System.err.println("NewtCanvasAWT.addNotify: "+newtChild+", "+this+", visible "+isVisible()+", showing "+isShowing()+ + ", displayable "+isDisplayable()+" -> "+cont); + } + reparentWindow(true, cont); + } + + public void removeNotify() { + java.awt.Container cont = getContainer(this); + if(DEBUG) { + System.err.println("NewtCanvasAWT.removeNotify: "+newtChild+", from "+cont); + } + reparentWindow(false, cont); + super.removeNotify(); + } + + void reparentWindow(boolean add, java.awt.Container cont) { + if(null==newtChild) { + return; // nop + } + + newtChild.setFocusAction(null); // no AWT focus traversal .. + if(add) { + nativeWindow = NewtFactoryAWT.getNativeWindow(this, newtChild.getRequestedCapabilities()); + if(null!=nativeWindow) { + if(DEBUG) { + System.err.println("NewtCanvasAWT.reparentWindow: "+newtChild); + } + final int w = cont.getWidth(); + final int h = cont.getHeight(); + setSize(w, h); + newtChild.setSize(w, h); + newtChild.reparentWindow(nativeWindow); + newtChild.setVisible(true); + setWindowAdapter(true); + newtChild.sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout to listener + newtChild.windowRepaint(0, 0, w, h); + newtChild.setFocusAction(focusAction); // enable AWT focus traversal + } + } else { + setWindowAdapter(false); + nativeWindow = null; + newtChild.setVisible(false); + newtChild.reparentWindow(null); + } + } + + /** + * @see #destroy(boolean) + */ + public final void destroy() { + destroy(false); + } + + /** + * Destroys this resource: + * <ul> + * <li> Make the NEWT Child invisible </li> + * <li> Disconnects the NEWT Child from this Canvas NativeWindow, reparent to NULL </li> + * <li> Issues <code>destroy(unrecoverable)</code> on the NEWT Child</li> + * <li> Remove reference to the NEWT Child, if unrecoverable</li> + * <li> Remove this Canvas from it's parent.</li> + * </ul> + * @see Window#destroy() + * @see Window#destroy(boolean) + */ + public final void destroy(boolean unrecoverable) { + if(null!=newtChild) { + java.awt.Container cont = getContainer(this); + if(DEBUG) { + System.err.println("NewtCanvasAWT.destroy("+unrecoverable+"): "+newtChild+", from "+cont); + } + nativeWindow = null; + newtChild.setVisible(false); + newtChild.reparentWindow(null); + newtChild.destroy(unrecoverable); + if(unrecoverable) { + newtChild = null; + } + if(null!=cont) { + cont.remove(this); + } + } + } + + public void paint(Graphics g) { + if(null!=newtChild) { + newtChild.windowRepaint(0, 0, getWidth(), getHeight()); + } + } + public void update(Graphics g) { + if(null!=newtChild) { + newtChild.windowRepaint(0, 0, getWidth(), getHeight()); + } + } + + final void requestFocusAWTParent() { + super.requestFocus(); + } + + final void requestFocusNEWTChild() { + if(null!=newtChild) { + newtChild.setFocusAction(null); + newtChild.requestFocus(); + newtChild.setFocusAction(focusAction); + } + } + + public void requestFocus() { + requestFocusAWTParent(); + requestFocusNEWTChild(); + } + + public boolean requestFocus(boolean temporary) { + boolean res = super.requestFocus(temporary); + if(res) { + requestFocusNEWTChild(); + } + return res; + } + + public boolean requestFocusInWindow() { + boolean res = super.requestFocusInWindow(); + if(res) { + requestFocusNEWTChild(); + } + return res; + } + + public boolean requestFocusInWindow(boolean temporary) { + boolean res = super.requestFocusInWindow(temporary); + if(res) { + requestFocusNEWTChild(); + } + return res; + } + + // Disables the AWT's erasing of this Canvas's background on Windows + // in Java SE 6. This internal API is not available in previous + // releases, but the system property + // -Dsun.awt.noerasebackground=true can be specified to get similar + // results globally in previous releases. + private static boolean disableBackgroundEraseInitialized; + private static Method disableBackgroundEraseMethod; + private void disableBackgroundErase() { + if (!disableBackgroundEraseInitialized) { + try { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + Class clazz = getToolkit().getClass(); + while (clazz != null && disableBackgroundEraseMethod == null) { + try { + disableBackgroundEraseMethod = + clazz.getDeclaredMethod("disableBackgroundErase", + new Class[] { Canvas.class }); + disableBackgroundEraseMethod.setAccessible(true); + } catch (Exception e) { + clazz = clazz.getSuperclass(); + } + } + } catch (Exception e) { + } + return null; + } + }); + } catch (Exception e) { + } + disableBackgroundEraseInitialized = true; + } + if (disableBackgroundEraseMethod != null) { + try { + disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this }); + } catch (Exception e) { + // FIXME: workaround for 6504460 (incorrect backport of 6333613 in 5.0u10) + // throw new GLException(e); + } + } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java b/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java new file mode 100644 index 000000000..7b9130188 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/awt/NewtFactoryAWT.java @@ -0,0 +1,74 @@ +/** + * 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.awt; + + +import javax.media.nativewindow.*; +import javax.media.nativewindow.awt.*; + +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.impl.Debug; + +public class NewtFactoryAWT extends NewtFactory { + public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); + + /** + * Wraps an AWT component into a {@link javax.media.nativewindow.NativeWindow} utilizing the {@link javax.media.nativewindow.NativeWindowFactory},<br> + * using a configuration agnostic dummy {@link javax.media.nativewindow.DefaultGraphicsConfiguration}.<br> + * <p> + * The actual wrapping implementation is {@link com.jogamp.nativewindow.impl.jawt.JAWTWindow}.<br></p> + * <p> + * Purpose of this wrapping is to access the AWT window handle,<br> + * not to actually render into it.<br> + * Hence the dummy configuration only.</p> + * + * @param awtCompObject must be of type java.awt.Component + */ + public static NativeWindow getNativeWindow(Object awtCompObject, Capabilities capsRequested) { + if(null==awtCompObject) { + throw new NativeWindowException("Null AWT Component"); + } + if( ! (awtCompObject instanceof java.awt.Component) ) { + throw new NativeWindowException("AWT Component not a java.awt.Component"); + } + return getNativeWindow( (java.awt.Component) awtCompObject, capsRequested ); + } + + public static NativeWindow getNativeWindow(java.awt.Component awtComp, Capabilities capsRequested) { + DefaultGraphicsConfiguration config = + AWTGraphicsConfiguration.create(awtComp, (Capabilities) capsRequested.clone(), capsRequested); + NativeWindow awtNative = NativeWindowFactory.getNativeWindow(awtComp, config); // a JAWTWindow + if(DEBUG_IMPLEMENTATION) { + System.err.println("NewtFactoryAWT.getNativeWindow: "+awtComp+" -> "+awtNative); + } + return awtNative; + } +} + diff --git a/src/newt/classes/com/jogamp/newt/event/InputEvent.java b/src/newt/classes/com/jogamp/newt/event/InputEvent.java new file mode 100644 index 000000000..148787845 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/InputEvent.java @@ -0,0 +1,89 @@ +/* + * 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.event; + +public abstract class InputEvent extends NEWTEvent +{ + public static final int SHIFT_MASK = 1 << 0; + public static final int CTRL_MASK = 1 << 1; + public static final int META_MASK = 1 << 2; + public static final int ALT_MASK = 1 << 3; + public static final int ALT_GRAPH_MASK = 1 << 5; + public static final int BUTTON1_MASK = 1 << 6; + public static final int BUTTON2_MASK = 1 << 7; + public static final int BUTTON3_MASK = 1 << 8; + + protected InputEvent(int eventType, Object source, long when, int modifiers) { + super(eventType, source, when); + this.modifiers=modifiers; + } + + public int getModifiers() { + return modifiers; + } + public boolean isAltDown() { + return (modifiers&ALT_MASK)!=0; + } + public boolean isAltGraphDown() { + return (modifiers&ALT_GRAPH_MASK)!=0; + } + public boolean isControlDown() { + return (modifiers&CTRL_MASK)!=0; + } + public boolean isMetaDown() { + return (modifiers&META_MASK)!=0; + } + public boolean isShiftDown() { + return (modifiers&SHIFT_MASK)!=0; + } + + public boolean isButton1Down() { + return (modifiers&BUTTON1_MASK)!=0; + } + + public boolean isButton2Down() { + return (modifiers&BUTTON2_MASK)!=0; + } + + public boolean isButton3Down() { + return (modifiers&BUTTON3_MASK)!=0; + } + + public String toString() { + return "InputEvent[modifiers:"+modifiers+", "+super.toString()+"]"; + } + + private int modifiers; +} diff --git a/src/newt/classes/com/jogamp/newt/event/KeyAdapter.java b/src/newt/classes/com/jogamp/newt/event/KeyAdapter.java new file mode 100644 index 000000000..93c8409b1 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/KeyAdapter.java @@ -0,0 +1,41 @@ +/** + * Copyright 2010 JogAmp Community. 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: + * + * 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.event; + +public abstract class KeyAdapter implements KeyListener +{ + public void keyPressed(KeyEvent e) { + } + public void keyReleased(KeyEvent e) { + } + public void keyTyped(KeyEvent e) { + } +} + diff --git a/src/newt/classes/com/jogamp/newt/event/KeyEvent.java b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java new file mode 100644 index 000000000..852f77fcb --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/KeyEvent.java @@ -0,0 +1,736 @@ +/* + * 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.event; + +public class KeyEvent extends InputEvent +{ + public KeyEvent(int eventType, Object source, long when, int modifiers, int keyCode, char keyChar) { + super(eventType, source, when, modifiers); + this.keyCode=keyCode; + this.keyChar=keyChar; + } + + public char getKeyChar() { + return keyChar; + } + public int getKeyCode() { + return keyCode; + } + + public String toString() { + return "KeyEvent["+getEventTypeString(getEventType())+ + ", code "+keyCode+"("+toHexString(keyCode)+"), char <"+keyChar+"> ("+toHexString((int)keyChar)+"), isActionKey "+isActionKey()+", "+super.toString()+"]"; + } + + public static String getEventTypeString(int type) { + switch(type) { + case EVENT_KEY_PRESSED: return "EVENT_KEY_PRESSED"; + case EVENT_KEY_RELEASED: return "EVENT_KEY_RELEASED"; + case EVENT_KEY_TYPED: return "EVENT_KEY_TYPED"; + default: return "unknown (" + type + ")"; + } + } + + public boolean isActionKey() { + switch (keyCode) { + case VK_HOME: + case VK_END: + case VK_PAGE_UP: + case VK_PAGE_DOWN: + case VK_UP: + case VK_DOWN: + case VK_LEFT: + case VK_RIGHT: + + case VK_F1: + case VK_F2: + case VK_F3: + case VK_F4: + case VK_F5: + case VK_F6: + case VK_F7: + case VK_F8: + case VK_F9: + case VK_F10: + case VK_F11: + case VK_F12: + case VK_F13: + case VK_F14: + case VK_F15: + case VK_F16: + case VK_F17: + case VK_F18: + case VK_F19: + case VK_F20: + case VK_F21: + case VK_F22: + case VK_F23: + case VK_F24: + case VK_PRINTSCREEN: + case VK_CAPS_LOCK: + case VK_PAUSE: + case VK_INSERT: + + case VK_HELP: + case VK_WINDOWS: + return true; + } + return false; + } + + private int keyCode; + private char keyChar; + + public static final int EVENT_KEY_PRESSED = 300; + public static final int EVENT_KEY_RELEASED= 301; + public static final int EVENT_KEY_TYPED = 302; + + /* Virtual key codes. */ + + public static final int VK_ENTER = '\n'; + public static final int VK_BACK_SPACE = '\b'; + public static final int VK_TAB = '\t'; + public static final int VK_CANCEL = 0x03; + public static final int VK_CLEAR = 0x0C; + public static final int VK_SHIFT = 0x10; + public static final int VK_CONTROL = 0x11; + public static final int VK_ALT = 0x12; + public static final int VK_PAUSE = 0x13; + public static final int VK_CAPS_LOCK = 0x14; + public static final int VK_ESCAPE = 0x1B; + public static final int VK_SPACE = 0x20; + public static final int VK_PAGE_UP = 0x21; + public static final int VK_PAGE_DOWN = 0x22; + public static final int VK_END = 0x23; + public static final int VK_HOME = 0x24; + + /** + * Constant for the non-numpad <b>left</b> arrow key. + * @see #VK_KP_LEFT + */ + public static final int VK_LEFT = 0x25; + + /** + * Constant for the non-numpad <b>up</b> arrow key. + * @see #VK_KP_UP + */ + public static final int VK_UP = 0x26; + + /** + * Constant for the non-numpad <b>right</b> arrow key. + * @see #VK_KP_RIGHT + */ + public static final int VK_RIGHT = 0x27; + + /** + * Constant for the non-numpad <b>down</b> arrow key. + * @see #VK_KP_DOWN + */ + public static final int VK_DOWN = 0x28; + + /** + * Constant for the comma key, "," + */ + public static final int VK_COMMA = 0x2C; + + /** + * Constant for the minus key, "-" + * @since 1.2 + */ + public static final int VK_MINUS = 0x2D; + + /** + * Constant for the period key, "." + */ + public static final int VK_PERIOD = 0x2E; + + /** + * Constant for the forward slash key, "/" + */ + public static final int VK_SLASH = 0x2F; + + /** VK_0 thru VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */ + public static final int VK_0 = 0x30; + public static final int VK_1 = 0x31; + public static final int VK_2 = 0x32; + public static final int VK_3 = 0x33; + public static final int VK_4 = 0x34; + public static final int VK_5 = 0x35; + public static final int VK_6 = 0x36; + public static final int VK_7 = 0x37; + public static final int VK_8 = 0x38; + public static final int VK_9 = 0x39; + + /** + * Constant for the semicolon key, ";" + */ + public static final int VK_SEMICOLON = 0x3B; + + /** + * Constant for the equals key, "=" + */ + public static final int VK_EQUALS = 0x3D; + + /** VK_A thru VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ + public static final int VK_A = 0x41; + public static final int VK_B = 0x42; + public static final int VK_C = 0x43; + public static final int VK_D = 0x44; + public static final int VK_E = 0x45; + public static final int VK_F = 0x46; + public static final int VK_G = 0x47; + public static final int VK_H = 0x48; + public static final int VK_I = 0x49; + public static final int VK_J = 0x4A; + public static final int VK_K = 0x4B; + public static final int VK_L = 0x4C; + public static final int VK_M = 0x4D; + public static final int VK_N = 0x4E; + public static final int VK_O = 0x4F; + public static final int VK_P = 0x50; + public static final int VK_Q = 0x51; + public static final int VK_R = 0x52; + public static final int VK_S = 0x53; + public static final int VK_T = 0x54; + public static final int VK_U = 0x55; + public static final int VK_V = 0x56; + public static final int VK_W = 0x57; + public static final int VK_X = 0x58; + public static final int VK_Y = 0x59; + public static final int VK_Z = 0x5A; + + /** + * Constant for the open bracket key, "[" + */ + public static final int VK_OPEN_BRACKET = 0x5B; + + /** + * Constant for the back slash key, "\" + */ + public static final int VK_BACK_SLASH = 0x5C; + + /** + * Constant for the close bracket key, "]" + */ + public static final int VK_CLOSE_BRACKET = 0x5D; + + public static final int VK_NUMPAD0 = 0x60; + public static final int VK_NUMPAD1 = 0x61; + public static final int VK_NUMPAD2 = 0x62; + public static final int VK_NUMPAD3 = 0x63; + public static final int VK_NUMPAD4 = 0x64; + public static final int VK_NUMPAD5 = 0x65; + public static final int VK_NUMPAD6 = 0x66; + public static final int VK_NUMPAD7 = 0x67; + public static final int VK_NUMPAD8 = 0x68; + public static final int VK_NUMPAD9 = 0x69; + public static final int VK_MULTIPLY = 0x6A; + public static final int VK_ADD = 0x6B; + + /** + * This constant is obsolete, and is included only for backwards + * compatibility. + * @see #VK_SEPARATOR + */ + public static final int VK_SEPARATER = 0x6C; + + /** + * Constant for the Numpad Separator key. + * @since 1.4 + */ + public static final int VK_SEPARATOR = VK_SEPARATER; + + public static final int VK_SUBTRACT = 0x6D; + public static final int VK_DECIMAL = 0x6E; + public static final int VK_DIVIDE = 0x6F; + public static final int VK_DELETE = 0x7F; /* ASCII DEL */ + public static final int VK_NUM_LOCK = 0x90; + public static final int VK_SCROLL_LOCK = 0x91; + + /** Constant for the F1 function key. */ + public static final int VK_F1 = 0x70; + + /** Constant for the F2 function key. */ + public static final int VK_F2 = 0x71; + + /** Constant for the F3 function key. */ + public static final int VK_F3 = 0x72; + + /** Constant for the F4 function key. */ + public static final int VK_F4 = 0x73; + + /** Constant for the F5 function key. */ + public static final int VK_F5 = 0x74; + + /** Constant for the F6 function key. */ + public static final int VK_F6 = 0x75; + + /** Constant for the F7 function key. */ + public static final int VK_F7 = 0x76; + + /** Constant for the F8 function key. */ + public static final int VK_F8 = 0x77; + + /** Constant for the F9 function key. */ + public static final int VK_F9 = 0x78; + + /** Constant for the F10 function key. */ + public static final int VK_F10 = 0x79; + + /** Constant for the F11 function key. */ + public static final int VK_F11 = 0x7A; + + /** Constant for the F12 function key. */ + public static final int VK_F12 = 0x7B; + + /** + * Constant for the F13 function key. + * @since 1.2 + */ + /* F13 - F24 are used on IBM 3270 keyboard; use random range for constants. */ + public static final int VK_F13 = 0xF000; + + /** + * Constant for the F14 function key. + * @since 1.2 + */ + public static final int VK_F14 = 0xF001; + + /** + * Constant for the F15 function key. + * @since 1.2 + */ + public static final int VK_F15 = 0xF002; + + /** + * Constant for the F16 function key. + * @since 1.2 + */ + public static final int VK_F16 = 0xF003; + + /** + * Constant for the F17 function key. + * @since 1.2 + */ + public static final int VK_F17 = 0xF004; + + /** + * Constant for the F18 function key. + * @since 1.2 + */ + public static final int VK_F18 = 0xF005; + + /** + * Constant for the F19 function key. + * @since 1.2 + */ + public static final int VK_F19 = 0xF006; + + /** + * Constant for the F20 function key. + * @since 1.2 + */ + public static final int VK_F20 = 0xF007; + + /** + * Constant for the F21 function key. + * @since 1.2 + */ + public static final int VK_F21 = 0xF008; + + /** + * Constant for the F22 function key. + * @since 1.2 + */ + public static final int VK_F22 = 0xF009; + + /** + * Constant for the F23 function key. + * @since 1.2 + */ + public static final int VK_F23 = 0xF00A; + + /** + * Constant for the F24 function key. + * @since 1.2 + */ + public static final int VK_F24 = 0xF00B; + + public static final int VK_PRINTSCREEN = 0x9A; + public static final int VK_INSERT = 0x9B; + public static final int VK_HELP = 0x9C; + public static final int VK_META = 0x9D; + + public static final int VK_BACK_QUOTE = 0xC0; + public static final int VK_QUOTE = 0xDE; + + /** + * Constant for the numeric keypad <b>up</b> arrow key. + * @see #VK_UP + * @since 1.2 + */ + public static final int VK_KP_UP = 0xE0; + + /** + * Constant for the numeric keypad <b>down</b> arrow key. + * @see #VK_DOWN + * @since 1.2 + */ + public static final int VK_KP_DOWN = 0xE1; + + /** + * Constant for the numeric keypad <b>left</b> arrow key. + * @see #VK_LEFT + * @since 1.2 + */ + public static final int VK_KP_LEFT = 0xE2; + + /** + * Constant for the numeric keypad <b>right</b> arrow key. + * @see #VK_RIGHT + * @since 1.2 + */ + public static final int VK_KP_RIGHT = 0xE3; + + /* For European keyboards */ + /** @since 1.2 */ + public static final int VK_DEAD_GRAVE = 0x80; + /** @since 1.2 */ + public static final int VK_DEAD_ACUTE = 0x81; + /** @since 1.2 */ + public static final int VK_DEAD_CIRCUMFLEX = 0x82; + /** @since 1.2 */ + public static final int VK_DEAD_TILDE = 0x83; + /** @since 1.2 */ + public static final int VK_DEAD_MACRON = 0x84; + /** @since 1.2 */ + public static final int VK_DEAD_BREVE = 0x85; + /** @since 1.2 */ + public static final int VK_DEAD_ABOVEDOT = 0x86; + /** @since 1.2 */ + public static final int VK_DEAD_DIAERESIS = 0x87; + /** @since 1.2 */ + public static final int VK_DEAD_ABOVERING = 0x88; + /** @since 1.2 */ + public static final int VK_DEAD_DOUBLEACUTE = 0x89; + /** @since 1.2 */ + public static final int VK_DEAD_CARON = 0x8a; + /** @since 1.2 */ + public static final int VK_DEAD_CEDILLA = 0x8b; + /** @since 1.2 */ + public static final int VK_DEAD_OGONEK = 0x8c; + /** @since 1.2 */ + public static final int VK_DEAD_IOTA = 0x8d; + /** @since 1.2 */ + public static final int VK_DEAD_VOICED_SOUND = 0x8e; + /** @since 1.2 */ + public static final int VK_DEAD_SEMIVOICED_SOUND = 0x8f; + + /** @since 1.2 */ + public static final int VK_AMPERSAND = 0x96; + /** @since 1.2 */ + public static final int VK_ASTERISK = 0x97; + /** @since 1.2 */ + public static final int VK_QUOTEDBL = 0x98; + /** @since 1.2 */ + public static final int VK_LESS = 0x99; + + /** @since 1.2 */ + public static final int VK_GREATER = 0xa0; + /** @since 1.2 */ + public static final int VK_BRACELEFT = 0xa1; + /** @since 1.2 */ + public static final int VK_BRACERIGHT = 0xa2; + + /** + * Constant for the "@" key. + * @since 1.2 + */ + public static final int VK_AT = 0x0200; + + /** + * Constant for the ":" key. + * @since 1.2 + */ + public static final int VK_COLON = 0x0201; + + /** + * Constant for the "^" key. + * @since 1.2 + */ + public static final int VK_CIRCUMFLEX = 0x0202; + + /** + * Constant for the "$" key. + * @since 1.2 + */ + public static final int VK_DOLLAR = 0x0203; + + /** + * Constant for the Euro currency sign key. + * @since 1.2 + */ + public static final int VK_EURO_SIGN = 0x0204; + + /** + * Constant for the "!" key. + * @since 1.2 + */ + public static final int VK_EXCLAMATION_MARK = 0x0205; + + /** + * Constant for the inverted exclamation mark key. + * @since 1.2 + */ + public static final int VK_INVERTED_EXCLAMATION_MARK = 0x0206; + + /** + * Constant for the "(" key. + * @since 1.2 + */ + public static final int VK_LEFT_PARENTHESIS = 0x0207; + + /** + * Constant for the "#" key. + * @since 1.2 + */ + public static final int VK_NUMBER_SIGN = 0x0208; + + /** + * Constant for the "+" key. + * @since 1.2 + */ + public static final int VK_PLUS = 0x0209; + + /** + * Constant for the ")" key. + * @since 1.2 + */ + public static final int VK_RIGHT_PARENTHESIS = 0x020A; + + /** + * Constant for the "_" key. + * @since 1.2 + */ + public static final int VK_UNDERSCORE = 0x020B; + + /** + * Constant for the Microsoft Windows "Windows" key. + * It is used for both the left and right version of the key. + * @see #getKeyLocation() + * @since 1.5 + */ + public static final int VK_WINDOWS = 0x020C; + + /** + * Constant for the Microsoft Windows Context Menu key. + * @since 1.5 + */ + public static final int VK_CONTEXT_MENU = 0x020D; + + /* for input method support on Asian Keyboards */ + + /* not clear what this means - listed in Microsoft Windows API */ + public static final int VK_FINAL = 0x0018; + + /** Constant for the Convert function key. */ + /* Japanese PC 106 keyboard, Japanese Solaris keyboard: henkan */ + public static final int VK_CONVERT = 0x001C; + + /** Constant for the Don't Convert function key. */ + /* Japanese PC 106 keyboard: muhenkan */ + public static final int VK_NONCONVERT = 0x001D; + + /** Constant for the Accept or Commit function key. */ + /* Japanese Solaris keyboard: kakutei */ + public static final int VK_ACCEPT = 0x001E; + + /* not clear what this means - listed in Microsoft Windows API */ + public static final int VK_MODECHANGE = 0x001F; + + /* replaced by VK_KANA_LOCK for Microsoft Windows and Solaris; + might still be used on other platforms */ + public static final int VK_KANA = 0x0015; + + /* replaced by VK_INPUT_METHOD_ON_OFF for Microsoft Windows and Solaris; + might still be used for other platforms */ + public static final int VK_KANJI = 0x0019; + + /** + * Constant for the Alphanumeric function key. + * @since 1.2 + */ + /* Japanese PC 106 keyboard: eisuu */ + public static final int VK_ALPHANUMERIC = 0x00F0; + + /** + * Constant for the Katakana function key. + * @since 1.2 + */ + /* Japanese PC 106 keyboard: katakana */ + public static final int VK_KATAKANA = 0x00F1; + + /** + * Constant for the Hiragana function key. + * @since 1.2 + */ + /* Japanese PC 106 keyboard: hiragana */ + public static final int VK_HIRAGANA = 0x00F2; + + /** + * Constant for the Full-Width Characters function key. + * @since 1.2 + */ + /* Japanese PC 106 keyboard: zenkaku */ + public static final int VK_FULL_WIDTH = 0x00F3; + + /** + * Constant for the Half-Width Characters function key. + * @since 1.2 + */ + /* Japanese PC 106 keyboard: hankaku */ + public static final int VK_HALF_WIDTH = 0x00F4; + + /** + * Constant for the Roman Characters function key. + * @since 1.2 + */ + /* Japanese PC 106 keyboard: roumaji */ + public static final int VK_ROMAN_CHARACTERS = 0x00F5; + + /** + * Constant for the All Candidates function key. + * @since 1.2 + */ + /* Japanese PC 106 keyboard - VK_CONVERT + ALT: zenkouho */ + public static final int VK_ALL_CANDIDATES = 0x0100; + + /** + * Constant for the Previous Candidate function key. + * @since 1.2 + */ + /* Japanese PC 106 keyboard - VK_CONVERT + SHIFT: maekouho */ + public static final int VK_PREVIOUS_CANDIDATE = 0x0101; + + /** + * Constant for the Code Input function key. + * @since 1.2 + */ + /* Japanese PC 106 keyboard - VK_ALPHANUMERIC + ALT: kanji bangou */ + public static final int VK_CODE_INPUT = 0x0102; + + /** + * Constant for the Japanese-Katakana function key. + * This key switches to a Japanese input method and selects its Katakana input mode. + * @since 1.2 + */ + /* Japanese Macintosh keyboard - VK_JAPANESE_HIRAGANA + SHIFT */ + public static final int VK_JAPANESE_KATAKANA = 0x0103; + + /** + * Constant for the Japanese-Hiragana function key. + * This key switches to a Japanese input method and selects its Hiragana input mode. + * @since 1.2 + */ + /* Japanese Macintosh keyboard */ + public static final int VK_JAPANESE_HIRAGANA = 0x0104; + + /** + * Constant for the Japanese-Roman function key. + * This key switches to a Japanese input method and selects its Roman-Direct input mode. + * @since 1.2 + */ + /* Japanese Macintosh keyboard */ + public static final int VK_JAPANESE_ROMAN = 0x0105; + + /** + * Constant for the locking Kana function key. + * This key locks the keyboard into a Kana layout. + * @since 1.3 + */ + /* Japanese PC 106 keyboard with special Windows driver - eisuu + Control; Japanese Solaris keyboard: kana */ + public static final int VK_KANA_LOCK = 0x0106; + + /** + * Constant for the input method on/off key. + * @since 1.3 + */ + /* Japanese PC 106 keyboard: kanji. Japanese Solaris keyboard: nihongo */ + public static final int VK_INPUT_METHOD_ON_OFF = 0x0107; + + /* for Sun keyboards */ + /** @since 1.2 */ + public static final int VK_CUT = 0xFFD1; + /** @since 1.2 */ + public static final int VK_COPY = 0xFFCD; + /** @since 1.2 */ + public static final int VK_PASTE = 0xFFCF; + /** @since 1.2 */ + public static final int VK_UNDO = 0xFFCB; + /** @since 1.2 */ + public static final int VK_AGAIN = 0xFFC9; + /** @since 1.2 */ + public static final int VK_FIND = 0xFFD0; + /** @since 1.2 */ + public static final int VK_PROPS = 0xFFCA; + /** @since 1.2 */ + public static final int VK_STOP = 0xFFC8; + + /** + * Constant for the Compose function key. + * @since 1.2 + */ + public static final int VK_COMPOSE = 0xFF20; + + /** + * Constant for the AltGraph function key. + * @since 1.2 + */ + public static final int VK_ALT_GRAPH = 0xFF7E; + + /** + * Constant for the Begin key. + * @since 1.5 + */ + public static final int VK_BEGIN = 0xFF58; + + /** + * This value is used to indicate that the keyCode is unknown. + * KEY_TYPED events do not have a keyCode value; this value + * is used instead. + */ + public static final int VK_UNDEFINED = 0x0; +} + diff --git a/src/newt/classes/com/jogamp/newt/event/KeyListener.java b/src/newt/classes/com/jogamp/newt/event/KeyListener.java new file mode 100644 index 000000000..dae343d80 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/KeyListener.java @@ -0,0 +1,43 @@ +/* + * 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.event; + +public interface KeyListener extends NEWTEventListener +{ + public void keyPressed(KeyEvent e); + public void keyReleased(KeyEvent e); + public void keyTyped(KeyEvent e) ; +} + diff --git a/src/newt/classes/com/jogamp/newt/event/MouseAdapter.java b/src/newt/classes/com/jogamp/newt/event/MouseAdapter.java new file mode 100644 index 000000000..3607ae634 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/MouseAdapter.java @@ -0,0 +1,50 @@ +/** + * 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.event; + +public abstract class MouseAdapter implements MouseListener +{ + public void mouseClicked(MouseEvent e) { + } + public void mouseEntered(MouseEvent e) { + } + public void mouseExited(MouseEvent e) { + } + public void mousePressed(MouseEvent e) { + } + public void mouseReleased(MouseEvent e) { + } + public void mouseMoved(MouseEvent e) { + } + public void mouseDragged(MouseEvent e) { + } + public void mouseWheelMoved(MouseEvent e) { + } +} + diff --git a/src/newt/classes/com/jogamp/newt/event/MouseEvent.java b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java new file mode 100644 index 000000000..fbe32d41d --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/MouseEvent.java @@ -0,0 +1,110 @@ +/* + * 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.event; + +public class MouseEvent extends InputEvent +{ + public static final int BUTTON1 = 1; + public static final int BUTTON2 = 2; + public static final int BUTTON3 = 3; + public static final int BUTTON4 = 4; + public static final int BUTTON5 = 5; + public static final int BUTTON6 = 6; + public static final int BUTTON_NUMBER = 6; + + public static final int getClickTimeout() { + return 300; + } + + public MouseEvent(int eventType, Object source, long when, + int modifiers, int x, int y, int clickCount, int button, + int rotation) + { + super(eventType, source, when, modifiers); + this.x=x; + this.y=y; + this.clickCount=clickCount; + this.button=button; + this.wheelRotation = rotation; + } + + public int getButton() { + return button; + } + public int getClickCount() { + return clickCount; + } + public int getX() { + return x; + } + public int getY() { + return y; + } + public int getWheelRotation() { + return wheelRotation; + } + + public String toString() { + return "MouseEvent["+getEventTypeString(getEventType())+ + ", "+x+"/"+y+", button "+button+", count "+clickCount+ + ", wheel rotation "+wheelRotation+ + ", "+super.toString()+"]"; + } + + public static String getEventTypeString(int type) { + switch(type) { + case EVENT_MOUSE_CLICKED: return "EVENT_MOUSE_CLICKED"; + case EVENT_MOUSE_ENTERED: return "EVENT_MOUSE_ENTERED"; + case EVENT_MOUSE_EXITED: return "EVENT_MOUSE_EXITED"; + case EVENT_MOUSE_PRESSED: return "EVENT_MOUSE_PRESSED"; + case EVENT_MOUSE_RELEASED: return "EVENT_MOUSE_RELEASED"; + case EVENT_MOUSE_MOVED: return "EVENT_MOUSE_MOVED"; + case EVENT_MOUSE_DRAGGED: return "EVENT_MOUSE_DRAGGED"; + case EVENT_MOUSE_WHEEL_MOVED: return "EVENT_MOUSE_WHEEL_MOVED"; + default: return "unknown (" + type + ")"; + } + } + + private int x, y, clickCount, button, wheelRotation; + + public static final int EVENT_MOUSE_CLICKED = 200; + public static final int EVENT_MOUSE_ENTERED = 201; + public static final int EVENT_MOUSE_EXITED = 202; + public static final int EVENT_MOUSE_PRESSED = 203; + public static final int EVENT_MOUSE_RELEASED = 204; + public static final int EVENT_MOUSE_MOVED = 205; + public static final int EVENT_MOUSE_DRAGGED = 206; + public static final int EVENT_MOUSE_WHEEL_MOVED = 207; +} diff --git a/src/newt/classes/com/jogamp/newt/event/MouseListener.java b/src/newt/classes/com/jogamp/newt/event/MouseListener.java new file mode 100644 index 000000000..5ec086b94 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/MouseListener.java @@ -0,0 +1,48 @@ +/* + * 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.event; + +public interface MouseListener extends NEWTEventListener +{ + public void mouseClicked(MouseEvent e); + public void mouseEntered(MouseEvent e); + public void mouseExited(MouseEvent e); + public void mousePressed(MouseEvent e); + public void mouseReleased(MouseEvent e); + public void mouseMoved(MouseEvent e); + public void mouseDragged(MouseEvent e); + public void mouseWheelMoved(MouseEvent e); +} + diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java new file mode 100644 index 000000000..10673be3d --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/NEWTEvent.java @@ -0,0 +1,164 @@ +/* + * 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.event; + +/** + * NEWT events are provided for notification purposes ONLY;<br> + * The NEWT will automatically handle the event semantics internally, regardless of whether a program is receiving these events or not.<br> + * The actual event semantic is processed before the event is send.<br> + * + * Event type registry:<br> + * <ul> + * <li> WindowEvent <code>100..10x</code></li> + * <li> MouseEvent <code>200..20x</code></li> + * <li> KeyEvent <code>300..30x</code></li> + * </ul><br> + */ +public class NEWTEvent extends java.util.EventObject { + private boolean isSystemEvent; + private int eventType; + private long when; + private Object attachment; + + static final boolean DEBUG = false; + + // 0: NEWTEvent.java + // 1: InputEvent.java + // 2: KeyEvent.java + // 3: com.jogamp.newt.Window + // 3: com.jogamp.newt.event.awt.AWTNewtEventFactory + // 2: MouseEvent.java + // 3: com.jogamp.newt.Window + // 3: com.jogamp.newt.event.awt.AWTNewtEventFactory + // 1: WindowEvent.java + // 2: com.jogamp.newt.Window + // 2: com.jogamp.newt.event.awt.AWTNewtEventFactory + // + // FIXME: verify the isSystemEvent evaluation + // + static final String WindowClazzName = "com.jogamp.newt.Window" ; + static final String AWTNewtEventFactoryClazzName = "com.jogamp.newt.event.awt.AWTNewtEventFactory" ; + + /** + static final boolean evaluateIsSystemEvent(NEWTEvent event, Throwable t) { + StackTraceElement[] stack = t.getStackTrace(); + if(stack.length==0 || null==stack[0]) { + return false; + } + if(DEBUG) { + for (int i = 0; i < stack.length && i<5; i++) { + System.err.println(i+": " + stack[i].getClassName()+ "." + stack[i].getMethodName()); + } + } + + String clazzName = null; + + if( event instanceof com.jogamp.newt.event.WindowEvent ) { + if ( stack.length > 2 ) { + clazzName = stack[2].getClassName(); + } + } else if( (event instanceof com.jogamp.newt.event.MouseEvent) || + (event instanceof com.jogamp.newt.event.KeyEvent) ) { + if ( stack.length > 3 ) { + clazzName = stack[3].getClassName(); + } + } + + boolean res = null!=clazzName && ( + clazzName.equals(WindowClazzName) || + clazzName.equals(AWTNewtEventFactoryClazzName) ) ; + if(DEBUG) { + System.err.println("system: "+res); + } + return res; + } */ + + protected NEWTEvent(int eventType, Object source, long when) { + super(source); + // this.isSystemEvent = evaluateIsSystemEvent(this, new Throwable()); + this.isSystemEvent = false; // FIXME: Need a more efficient way to determine system events + this.eventType = eventType; + this.when = when; + this.attachment=null; + } + + /** Indicates whether this event was produced by the system or + generated by user code. */ + public final boolean isSystemEvent() { + return isSystemEvent; + } + + /** Returns the event type of this event. */ + public final int getEventType() { + return eventType; + } + + /** Returns the timestamp, in milliseconds, of this event. */ + public final long getWhen() { + return when; + } + + /** + * Attach the passed object to this event.<br> + * If an object was previously attached, it will be replaced.<br> + * Attachments to NEWT events allow users to pass on information + * from one custom listener to another, ie custom listener to listener + * communication. + * @param attachment User application specific object + */ + public final void setAttachment(Object attachment) { + this.attachment=attachment; + } + + /** + * @return The user application specific attachment, or null + */ + public final Object getAttachment() { + return attachment; + } + + public String toString() { + return "NEWTEvent[sys:"+isSystemEvent()+", source:"+getSource().getClass().getName()+", when:"+getWhen()+" d "+(System.currentTimeMillis()-getWhen())+"ms]"; + } + + public static String toHexString(int hex) { + return "0x" + Integer.toHexString(hex); + } + + public static String toHexString(long hex) { + return "0x" + Long.toHexString(hex); + } + +} diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEventConsumer.java b/src/newt/classes/com/jogamp/newt/event/NEWTEventConsumer.java new file mode 100644 index 000000000..6aa19e5f8 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/NEWTEventConsumer.java @@ -0,0 +1,40 @@ +/** + * 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.event; + +public interface NEWTEventConsumer { + + /** + * Consume the event + * + * @return true if the event has been consumed, + * otherwise it returns false for later propagation. + */ + public boolean consumeEvent(NEWTEvent event); +} diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEventFiFo.java b/src/newt/classes/com/jogamp/newt/event/NEWTEventFiFo.java new file mode 100644 index 000000000..fe224bba6 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/NEWTEventFiFo.java @@ -0,0 +1,62 @@ +/** + * 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.event; + +import java.util.LinkedList; + +public class NEWTEventFiFo +{ + private LinkedList/*<NEWTEvent>*/ events = new LinkedList/*<NEWTEvent>*/(); + + /** Add NEWTEvent to tail */ + public synchronized void put(NEWTEvent event) { + events.addLast(event); + notifyAll(); + } + + /** Remove NEWTEvent from head */ + public synchronized NEWTEvent get() { + if (0 == events.size()) { + return null; + } + + return (NEWTEvent) events.removeFirst(); + } + + /** Get NEWTEvents in queue */ + public synchronized int size() { + return events.size(); + } + + /** Clear all NEWTEvents from queue */ + public synchronized void clear() { + events.clear(); + } + +} diff --git a/src/newt/classes/com/jogamp/newt/event/NEWTEventListener.java b/src/newt/classes/com/jogamp/newt/event/NEWTEventListener.java new file mode 100644 index 000000000..677136573 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/NEWTEventListener.java @@ -0,0 +1,40 @@ +/* + * 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.event; + +public interface NEWTEventListener extends java.util.EventListener +{ +} + diff --git a/src/newt/classes/com/jogamp/newt/event/ScreenModeListener.java b/src/newt/classes/com/jogamp/newt/event/ScreenModeListener.java new file mode 100644 index 000000000..7bca23cfe --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/ScreenModeListener.java @@ -0,0 +1,39 @@ +/** + * 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.event; + +import com.jogamp.newt.ScreenMode; + +public interface ScreenModeListener { + /** called before the screen mode will be changed */ + void screenModeChangeNotify(ScreenMode sm); + + /** called after the screen mode has been changed */ + void screenModeChanged(ScreenMode sm, boolean success); +} diff --git a/src/newt/classes/com/jogamp/newt/event/TraceKeyAdapter.java b/src/newt/classes/com/jogamp/newt/event/TraceKeyAdapter.java new file mode 100644 index 000000000..98ba5a24d --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/TraceKeyAdapter.java @@ -0,0 +1,56 @@ +/** + * 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.event; + +public class TraceKeyAdapter implements KeyListener { + + KeyListener downstream; + + public TraceKeyAdapter() { + this.downstream = null; + } + + public TraceKeyAdapter(KeyListener downstream) { + this.downstream = downstream; + } + + public void keyPressed(KeyEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.keyPressed(e); } + } + public void keyReleased(KeyEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.keyReleased(e); } + } + public void keyTyped(KeyEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.keyTyped(e); } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/event/TraceMouseAdapter.java b/src/newt/classes/com/jogamp/newt/event/TraceMouseAdapter.java new file mode 100644 index 000000000..14ee633a0 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/TraceMouseAdapter.java @@ -0,0 +1,76 @@ +/** + * 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.event; + +public class TraceMouseAdapter implements MouseListener { + + MouseListener downstream; + + public TraceMouseAdapter() { + this.downstream = null; + } + + public TraceMouseAdapter(MouseListener downstream) { + this.downstream = downstream; + } + + public void mouseClicked(MouseEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.mouseClicked(e); } + } + public void mouseEntered(MouseEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.mouseEntered(e); } + } + public void mouseExited(MouseEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.mouseExited(e); } + } + public void mousePressed(MouseEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.mousePressed(e); } + } + public void mouseReleased(MouseEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.mouseReleased(e); } + } + public void mouseMoved(MouseEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.mouseMoved(e); } + } + public void mouseDragged(MouseEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.mouseDragged(e); } + } + public void mouseWheelMoved(MouseEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.mouseWheelMoved(e); } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/event/TraceWindowAdapter.java b/src/newt/classes/com/jogamp/newt/event/TraceWindowAdapter.java new file mode 100644 index 000000000..88b165a8d --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/TraceWindowAdapter.java @@ -0,0 +1,67 @@ +/** + * 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.event; + +public class TraceWindowAdapter implements WindowListener { + + WindowListener downstream; + + public TraceWindowAdapter() { + this.downstream = null; + } + + public TraceWindowAdapter(WindowListener downstream) { + this.downstream = downstream; + } + + public void windowResized(WindowEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.windowResized(e); } + } + public void windowMoved(WindowEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.windowMoved(e); } + } + public void windowDestroyNotify(WindowEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.windowDestroyNotify(e); } + } + public void windowGainedFocus(WindowEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.windowGainedFocus(e); } + } + public void windowLostFocus(WindowEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.windowLostFocus(e); } + } + public void windowRepaint(WindowUpdateEvent e) { + System.err.println(e); + if(null!=downstream) { downstream.windowRepaint(e); } + } +} diff --git a/src/newt/classes/com/jogamp/newt/event/WindowAdapter.java b/src/newt/classes/com/jogamp/newt/event/WindowAdapter.java new file mode 100644 index 000000000..a1ad43a13 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/WindowAdapter.java @@ -0,0 +1,45 @@ +/** + * 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.event; + +public abstract class WindowAdapter implements WindowListener +{ + public void windowResized(WindowEvent e) { + } + public void windowMoved(WindowEvent e) { + } + public void windowDestroyNotify(WindowEvent e) { + } + public void windowGainedFocus(WindowEvent e) { + } + public void windowLostFocus(WindowEvent e) { + } + public void windowRepaint(WindowUpdateEvent e) { + } +} diff --git a/src/newt/classes/com/jogamp/newt/event/WindowEvent.java b/src/newt/classes/com/jogamp/newt/event/WindowEvent.java new file mode 100644 index 000000000..2742e0d95 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/WindowEvent.java @@ -0,0 +1,69 @@ +/* + * 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.event; + +/** + * NEWT Window events are provided for notification purposes ONLY.<br> + * NEWT will automatically handle component moves and resizes internally, regardless of whether a program is receiving these events or not. <br> + * The actual event semantic, here move and resize, is processed before the event is send.<br> + */ +public class WindowEvent extends NEWTEvent { + public static final int EVENT_WINDOW_RESIZED = 100; + public static final int EVENT_WINDOW_MOVED = 101; + public static final int EVENT_WINDOW_DESTROY_NOTIFY = 102; + public static final int EVENT_WINDOW_GAINED_FOCUS = 103; + public static final int EVENT_WINDOW_LOST_FOCUS = 104; + public static final int EVENT_WINDOW_REPAINT = 105; + + public WindowEvent(int eventType, Object source, long when) { + super(eventType, source, when); + } + + public static String getEventTypeString(int type) { + switch(type) { + case EVENT_WINDOW_RESIZED: return "WINDOW_RESIZED"; + case EVENT_WINDOW_MOVED: return "WINDOW_MOVED"; + case EVENT_WINDOW_DESTROY_NOTIFY: return "EVENT_WINDOW_DESTROY_NOTIFY"; + case EVENT_WINDOW_GAINED_FOCUS: return "EVENT_WINDOW_GAINED_FOCUS"; + case EVENT_WINDOW_LOST_FOCUS: return "EVENT_WINDOW_LOST_FOCUS"; + case EVENT_WINDOW_REPAINT: return "EVENT_WINDOW_REPAINT"; + default: return "unknown (" + type + ")"; + } + } + public String toString() { + return "WindowEvent["+getEventTypeString(getEventType()) + + ", " + super.toString() + "]"; + } +} diff --git a/src/newt/classes/com/jogamp/newt/event/WindowListener.java b/src/newt/classes/com/jogamp/newt/event/WindowListener.java new file mode 100644 index 000000000..0d201a2a4 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/WindowListener.java @@ -0,0 +1,55 @@ +/* + * 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.event; + +public interface WindowListener extends NEWTEventListener { + /** Window is resized, your application shall respect the new window dimension. A repaint is recommended. */ + public void windowResized(WindowEvent e); + + /** Window has been moved. */ + public void windowMoved(WindowEvent e); + + /** Window will be destroyed. Release of resources is recommended. */ + public void windowDestroyNotify(WindowEvent e); + + /** Window gained focus. */ + public void windowGainedFocus(WindowEvent e); + + /** Window lost focus. */ + public void windowLostFocus(WindowEvent e); + + /** Window area shall be repainted. */ + public void windowRepaint(WindowUpdateEvent e); +} diff --git a/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java b/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java new file mode 100644 index 000000000..7cd6ee370 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/WindowUpdateEvent.java @@ -0,0 +1,49 @@ +/** + * 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.event; + +import javax.media.nativewindow.util.Rectangle; + +public class WindowUpdateEvent extends WindowEvent { + Rectangle bounds; + + public WindowUpdateEvent(int eventType, Object source, long when, Rectangle bounds) + { + super(eventType, source, when); + this.bounds = bounds; + } + + public Rectangle getBounds() { + return bounds; + } + + public String toString() { + return "WindowUpdateEvent["+super.toString()+", "+bounds+"]"; + } +} diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java new file mode 100644 index 000000000..c136946ac --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTAdapter.java @@ -0,0 +1,180 @@ +/** + * 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.event.awt; + +import com.jogamp.newt.impl.Debug; + +/** + * Convenient adapter forwarding AWT events to NEWT via the event listener model.<br> + * <p> + * You may attach an instance of this adapter to an AWT Component. When an event happens, + * it is converted to a NEWT event and the given NEWT listener is being called.<br></p> + * <p> + * This adapter fullfills three use cases. First as a plain utility to write code AWT agnostic, + * ie write an {@link javax.media.opengl.GLEvenListener} and some appropriate NEWT {@link com.jogamp.newt.event.NEWTEventListener}.<br></p> + * <p> + * Attach the {@link javax.media.opengl.GLEvenListener} to a NEWT {@link javax.media.opengl.GLAutoDrawable}, e.g. {@link com.jogamp.newt.opengl.GLWindow},<br> + * or to an AWT {@link javax.media.opengl.GLAutoDrawable}, e.g. {@link javax.media.opengl.awt.GLCanvas}.<br> + * <br> + * Attach the NEWT {@link com.jogamp.newt.event.NEWTEventListener} to a NEWT component, e.g. {@link com.jogamp.newt.Window},<br> + * or to an AWT component, e.g. {@link java.awt.Component}.<br></p> + * <p> + * Common:<br> + * <pre> + // your demo/render code + javax.media.opengl.GLEvenListener demo1 = new javax.media.opengl.GLEvenListener() { ... } ; + + // your AWT agnostic NEWT mouse listener code + com.jogamp.newt.event.MouseListener mouseListener = new com.jogamp.newt.event.MouseAdapter() { ... } ; + * </pre> </p> + * <p> + * Default NEWT use case, without using the AWTAdapter:<br> + * <pre> + // the NEWT GLAutoDrawable and Window + GLWindow glWindow = GLWindow.create(); + + // attach the renderer demo1 + glWindow.addGLEventListener(demo1); + + // attach the NEWT mouse event listener to glWindow + glWindow.addMouseListener(mouseListener); + * </pre> </p> + * <p> + * AWT use case, AWTAdapter used as an AWT event translator and forwarder to your NEWT listener:<br> + * <pre> + // the AWT GLAutoDrawable and Canvas + GLCanvas glCanvas = new GLCanvas(); + + // attach the renderer demo1 + glCanvas.addGLEventListener(demo1); + + // attach the AWTMouseAdapter to glCanvas, which translates and forwards events to the NEWT mouseListener + new AWTMouseAdapter(mouseListener).addTo(glCanvas); + * </pre> </p> + * <p> + * Previous code in detail:<br> + * <pre> + AWTMouseAdapter mouseAdapter = new AWTMouseAdapter(mouseListener); + glCanvas.addMouseListener(mouseAdapter); + glCanvas.addMouseMotionListener(mouseAdapter); + * </pre> </p> + * + * <p> + * Second use case is just a litte variation of the previous use case, where we pass a NEWT Window <br> + * to be used as the source of the event.<br></p> + * <p> + * <pre> + com.jogamp.newt.event.MouseListener mouseListener = new com.jogamp.newt.event.MouseAdapter() { ... } ;<br> + Component comp = ... ; // the AWT component<br> + GLWindow glWindow = GLWindow.create(); // the NEWT component<br> + <br> + new AWTMouseAdapter(mouseListener, glWindow).addTo(comp);<br> + * </pre> </p> + * + * Last but not least, the AWTAdapter maybe used as a general AWT event forwarder to NEWT.<br> + * + * <p> + * <pre> + com.jogamp.newt.event.MouseListener mouseListener = new com.jogamp.newt.event.MouseAdapter() { ... } ;<br> + Component comp = ... ; // the AWT component<br> + GLWindow glWindow = GLWindow.create(); // the NEWT component<br> + glWindow.addMouseListener(mouseListener); // add the custom EventListener to the NEWT component<br> + <br> + new AWTMouseAdapter(glWindow).addTo(comp); // forward all AWT events to glWindow, as NEWT events<br> + * </pre> </p> + * + * @see #attachTo + */ +public abstract class AWTAdapter implements java.util.EventListener +{ + public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); + + com.jogamp.newt.event.NEWTEventListener newtListener; + com.jogamp.newt.Window newtWindow; + + /** + * Simply wrap aroung a NEWT EventListener, exposed as an AWT EventListener.<br> + * The NEWT EventListener will be called when an event happens.<br> + */ + public AWTAdapter(com.jogamp.newt.event.NEWTEventListener newtListener) { + if(null==newtListener) { + throw new RuntimeException("Argument newtListener is null"); + } + this.newtListener = newtListener; + this.newtWindow = null; + } + + /** + * Wrap aroung a NEWT EventListener, exposed as an AWT EventListener,<br> + * where the given NEWT Window impersonates as the event's source. + * The NEWT EventListener will be called when an event happens.<br> + */ + public AWTAdapter(com.jogamp.newt.event.NEWTEventListener newtListener, com.jogamp.newt.Window newtProxy) { + if(null==newtListener) { + throw new RuntimeException("Argument newtListener is null"); + } + if(null==newtProxy) { + throw new RuntimeException("Argument newtProxy is null"); + } + this.newtListener = newtListener; + this.newtWindow = newtProxy; + } + + /** + * Create a pipeline adapter, AWT EventListener.<br> + * Once attached to an AWT component, it sends the converted AWT events to the NEWT downstream window.<br> + * This is only supported with EDT enabled! + */ + public AWTAdapter(com.jogamp.newt.Window downstream) { + if(null==downstream) { + throw new RuntimeException("Argument downstream is null"); + } + this.newtListener = null; + this.newtWindow = downstream; + if( null == newtWindow.getScreen().getDisplay().getEDTUtil() ) { + throw new RuntimeException("EDT not enabled"); + } + } + + /** + * Due to the fact that some NEWT {@link com.jogamp.newt.event.NEWTEventListener} + * are mapped to more than one {@link java.util.EventListener}, + * this method is for your convenience to use this Adapter as a listener for all types.<br> + * E.g. {@link com.jogamp.newt.event.MouseListener} is mapped to {@link java.awt.event.MouseListener} and {@link java.awt.event.MouseMotionListener}. + */ + public abstract AWTAdapter addTo(java.awt.Component awtComponent); + + /** @see #addTo(java.awt.Component) */ + public abstract AWTAdapter removeFrom(java.awt.Component awtComponent); + + void enqueueEvent(boolean wait, com.jogamp.newt.event.NEWTEvent event) { + newtWindow.enqueueEvent(wait, event); + } +} + diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java new file mode 100644 index 000000000..8fe6ff63a --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTKeyAdapter.java @@ -0,0 +1,82 @@ +/** + * 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.event.awt; + +public class AWTKeyAdapter extends AWTAdapter implements java.awt.event.KeyListener +{ + public AWTKeyAdapter(com.jogamp.newt.event.KeyListener newtListener) { + super(newtListener); + } + + public AWTKeyAdapter(com.jogamp.newt.event.KeyListener newtListener, com.jogamp.newt.Window newtProxy) { + super(newtListener, newtProxy); + } + + public AWTKeyAdapter(com.jogamp.newt.Window downstream) { + super(downstream); + } + + public AWTAdapter addTo(java.awt.Component awtComponent) { + awtComponent.addKeyListener(this); + return this; + } + + public AWTAdapter removeFrom(java.awt.Component awtComponent) { + awtComponent.removeKeyListener(this); + return this; + } + + public void keyPressed(java.awt.event.KeyEvent e) { + com.jogamp.newt.event.KeyEvent event = AWTNewtEventFactory.createKeyEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.KeyListener)newtListener).keyPressed(event); + } else { + enqueueEvent(false, event); + } + } + + public void keyReleased(java.awt.event.KeyEvent e) { + com.jogamp.newt.event.KeyEvent event = AWTNewtEventFactory.createKeyEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.KeyListener)newtListener).keyReleased(event); + } else { + enqueueEvent(false, event); + } + } + + public void keyTyped(java.awt.event.KeyEvent e) { + com.jogamp.newt.event.KeyEvent event = AWTNewtEventFactory.createKeyEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.KeyListener)newtListener).keyTyped(event); + } else { + enqueueEvent(false, event); + } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java new file mode 100644 index 000000000..bd421073a --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTMouseAdapter.java @@ -0,0 +1,120 @@ +/** + * 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.event.awt; + +public class AWTMouseAdapter extends AWTAdapter implements java.awt.event.MouseListener, java.awt.event.MouseMotionListener +{ + public AWTMouseAdapter(com.jogamp.newt.event.MouseListener newtListener) { + super(newtListener); + } + + public AWTMouseAdapter(com.jogamp.newt.event.MouseListener newtListener, com.jogamp.newt.Window newtProxy) { + super(newtListener, newtProxy); + } + + public AWTMouseAdapter(com.jogamp.newt.Window downstream) { + super(downstream); + } + + public AWTAdapter addTo(java.awt.Component awtComponent) { + awtComponent.addMouseListener(this); + awtComponent.addMouseMotionListener(this); + return this; + } + + public AWTAdapter removeFrom(java.awt.Component awtComponent) { + awtComponent.removeMouseListener(this); + awtComponent.removeMouseMotionListener(this); + return this; + } + + public void mouseClicked(java.awt.event.MouseEvent e) { + com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.MouseListener)newtListener).mouseClicked(event); + } else { + enqueueEvent(false, event); + } + } + + public void mouseEntered(java.awt.event.MouseEvent e) { + com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.MouseListener)newtListener).mouseEntered(event); + } else { + enqueueEvent(false, event); + } + } + + public void mouseExited(java.awt.event.MouseEvent e) { + com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.MouseListener)newtListener).mouseExited(event); + } else { + enqueueEvent(false, event); + } + } + + public void mousePressed(java.awt.event.MouseEvent e) { + com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.MouseListener)newtListener).mousePressed(event); + } else { + enqueueEvent(false, event); + } + } + + public void mouseReleased(java.awt.event.MouseEvent e) { + com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.MouseListener)newtListener).mouseReleased(event); + } else { + enqueueEvent(false, event); + } + } + + public void mouseDragged(java.awt.event.MouseEvent e) { + com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.MouseListener)newtListener).mouseDragged(event); + } else { + enqueueEvent(false, event); + } + } + + public void mouseMoved(java.awt.event.MouseEvent e) { + com.jogamp.newt.event.MouseEvent event = AWTNewtEventFactory.createMouseEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.MouseListener)newtListener).mouseMoved(event); + } else { + enqueueEvent(false, event); + } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTNewtEventFactory.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTNewtEventFactory.java new file mode 100644 index 000000000..8e33285bf --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTNewtEventFactory.java @@ -0,0 +1,146 @@ +/** + * 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.event.awt; + +import com.jogamp.common.util.IntIntHashMap; + +class AWTNewtEventFactory { + + protected static final IntIntHashMap eventTypeAWT2NEWT; + + static { + IntIntHashMap map = new IntIntHashMap(); + map.setKeyNotFoundValue(-1); + // n/a map.put(java.awt.event.WindowEvent.WINDOW_OPENED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_OPENED); + map.put(java.awt.event.WindowEvent.WINDOW_CLOSING, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_DESTROY_NOTIFY); + // n/a map.put(java.awt.event.WindowEvent.WINDOW_CLOSED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_CLOSED); + // n/a map.put(java.awt.event.WindowEvent.WINDOW_ICONIFIED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_ICONIFIED); + // n/a map.put(java.awt.event.WindowEvent.WINDOW_DEICONIFIED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_DEICONIFIED); + map.put(java.awt.event.WindowEvent.WINDOW_ACTIVATED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS); + map.put(java.awt.event.WindowEvent.WINDOW_GAINED_FOCUS, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS); + map.put(java.awt.event.FocusEvent.FOCUS_GAINED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_GAINED_FOCUS); + map.put(java.awt.event.WindowEvent.WINDOW_DEACTIVATED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_LOST_FOCUS); + map.put(java.awt.event.WindowEvent.WINDOW_LOST_FOCUS, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_LOST_FOCUS); + map.put(java.awt.event.FocusEvent.FOCUS_LOST, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_LOST_FOCUS); + // n/a map.put(java.awt.event.WindowEvent.WINDOW_STATE_CHANGED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_STATE_CHANGED); + + map.put(java.awt.event.ComponentEvent.COMPONENT_MOVED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_MOVED); + map.put(java.awt.event.ComponentEvent.COMPONENT_RESIZED, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_RESIZED); + // n/a map.put(java.awt.event.ComponentEvent.COMPONENT_SHOWN, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_SHOWN); + // n/a map.put(java.awt.event.ComponentEvent.COMPONENT_HIDDEN, com.jogamp.newt.event.WindowEvent.EVENT_WINDOW_HIDDEN); + + map.put(java.awt.event.MouseEvent.MOUSE_CLICKED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_CLICKED); + map.put(java.awt.event.MouseEvent.MOUSE_PRESSED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_PRESSED); + map.put(java.awt.event.MouseEvent.MOUSE_RELEASED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_RELEASED); + map.put(java.awt.event.MouseEvent.MOUSE_MOVED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_MOVED); + map.put(java.awt.event.MouseEvent.MOUSE_ENTERED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_ENTERED); + map.put(java.awt.event.MouseEvent.MOUSE_EXITED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_EXITED); + map.put(java.awt.event.MouseEvent.MOUSE_DRAGGED, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_DRAGGED); + map.put(java.awt.event.MouseEvent.MOUSE_WHEEL, com.jogamp.newt.event.MouseEvent.EVENT_MOUSE_WHEEL_MOVED); + + map.put(java.awt.event.KeyEvent.KEY_PRESSED, com.jogamp.newt.event.KeyEvent.EVENT_KEY_PRESSED); + map.put(java.awt.event.KeyEvent.KEY_RELEASED, com.jogamp.newt.event.KeyEvent.EVENT_KEY_RELEASED); + map.put(java.awt.event.KeyEvent.KEY_TYPED, com.jogamp.newt.event.KeyEvent.EVENT_KEY_TYPED); + + eventTypeAWT2NEWT = map; + } + + public static final int awtModifiers2Newt(int awtMods, boolean mouseHint) { + int newtMods = 0; + if ((awtMods & java.awt.event.InputEvent.SHIFT_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.SHIFT_MASK; + if ((awtMods & java.awt.event.InputEvent.CTRL_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.CTRL_MASK; + if ((awtMods & java.awt.event.InputEvent.META_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.META_MASK; + if ((awtMods & java.awt.event.InputEvent.ALT_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_MASK; + if ((awtMods & java.awt.event.InputEvent.ALT_GRAPH_MASK) != 0) newtMods |= com.jogamp.newt.event.InputEvent.ALT_GRAPH_MASK; + return newtMods; + } + + public static final int awtButton2Newt(int awtButton) { + switch (awtButton) { + case java.awt.event.MouseEvent.BUTTON1: return com.jogamp.newt.event.MouseEvent.BUTTON1; + case java.awt.event.MouseEvent.BUTTON2: return com.jogamp.newt.event.MouseEvent.BUTTON2; + case java.awt.event.MouseEvent.BUTTON3: return com.jogamp.newt.event.MouseEvent.BUTTON3; + } + return 0; + } + + static final com.jogamp.newt.event.WindowEvent createWindowEvent(java.awt.event.WindowEvent event, com.jogamp.newt.Window newtSource) { + int type = eventTypeAWT2NEWT.get(event.getID()); + if(-1 < type) { + return new com.jogamp.newt.event.WindowEvent(type, ((null==newtSource)?(Object)event.getComponent():(Object)newtSource), System.currentTimeMillis()); + } + return null; // no mapping .. + } + + static final com.jogamp.newt.event.WindowEvent createWindowEvent(java.awt.event.ComponentEvent event, com.jogamp.newt.Window newtSource) { + int type = eventTypeAWT2NEWT.get(event.getID()); + if(-1 < type) { + return new com.jogamp.newt.event.WindowEvent(type, (null==newtSource)?(Object)event.getComponent():(Object)newtSource, System.currentTimeMillis()); + } + return null; // no mapping .. + } + + static final com.jogamp.newt.event.WindowEvent createWindowEvent(java.awt.event.FocusEvent event, com.jogamp.newt.Window newtSource) { + int type = eventTypeAWT2NEWT.get(event.getID()); + if(-1 < type) { + return new com.jogamp.newt.event.WindowEvent(type, (null==newtSource)?(Object)event.getComponent():(Object)newtSource, System.currentTimeMillis()); + } + return null; // no mapping .. + } + + static final com.jogamp.newt.event.MouseEvent createMouseEvent(java.awt.event.MouseEvent event, com.jogamp.newt.Window newtSource) { + int type = eventTypeAWT2NEWT.get(event.getID()); + if(-1 < type) { + int rotation = 0; + if (event instanceof java.awt.event.MouseWheelEvent) { + rotation = ((java.awt.event.MouseWheelEvent)event).getWheelRotation(); + } + + return new com.jogamp.newt.event.MouseEvent( + type, (null==newtSource)?(Object)event.getComponent():(Object)newtSource, event.getWhen(), + awtModifiers2Newt(event.getModifiers(), true), + event.getX(), event.getY(), event.getClickCount(), + awtButton2Newt(event.getButton()), rotation); + } + return null; // no mapping .. + } + + static final com.jogamp.newt.event.KeyEvent createKeyEvent(java.awt.event.KeyEvent event, com.jogamp.newt.Window newtSource) { + int type = eventTypeAWT2NEWT.get(event.getID()); + if(-1 < type) { + return new com.jogamp.newt.event.KeyEvent( + type, (null==newtSource)?(Object)event.getComponent():(Object)newtSource, event.getWhen(), + awtModifiers2Newt(event.getModifiers(), false), + event.getKeyCode(), event.getKeyChar()); + } + return null; // no mapping .. + } + +} + diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTParentWindowAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTParentWindowAdapter.java new file mode 100644 index 000000000..68f2b3e0f --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTParentWindowAdapter.java @@ -0,0 +1,130 @@ +/** + * 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.event.awt; + +/** + * Specialized parent/client adapter, + * where the NEWT child window really gets resized, + * and the parent move window event gets discarded. */ +public class AWTParentWindowAdapter + extends AWTWindowAdapter + implements java.awt.event.HierarchyListener +{ + public AWTParentWindowAdapter(com.jogamp.newt.Window downstream) { + super(downstream); + } + + public AWTAdapter addTo(java.awt.Component awtComponent) { + awtComponent.addHierarchyListener(this); + return super.addTo(awtComponent); + } + + public AWTAdapter removeFrom(java.awt.Component awtComponent) { + awtComponent.removeHierarchyListener(this); + return super.removeFrom(awtComponent); + } + + public void focusGained(java.awt.event.FocusEvent e) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("AWT: focusGained: "+ e); + } + } + + public void focusLost(java.awt.event.FocusEvent e) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("AWT: focusLost: "+ e); + } + } + + public void componentResized(java.awt.event.ComponentEvent e) { + // Need to resize the NEWT child window + // the resized event will be send via the native window feedback. + final java.awt.Component comp = e.getComponent(); + if(DEBUG_IMPLEMENTATION) { + System.err.println("AWT: componentResized: "+comp); + } + if(newtWindow.isValid()) { + newtWindow.runOnEDTIfAvail(false, new Runnable() { + public void run() { + int cw = comp.getWidth(); + int ch = comp.getHeight(); + if( 0 < cw * ch ) { + if( newtWindow.getWidth() != cw || newtWindow.getHeight() != ch ) { + newtWindow.setSize(cw, ch); + if(comp.isVisible() != newtWindow.isVisible()) { + newtWindow.setVisible(comp.isVisible()); + } + } + } else if(newtWindow.isVisible()) { + newtWindow.setVisible(false); + } + }}); + } + } + + public void componentMoved(java.awt.event.ComponentEvent e) { + // no propagation to NEWT child window + } + + public void windowActivated(java.awt.event.WindowEvent e) { + // no propagation to NEWT child window + } + + public void windowDeactivated(java.awt.event.WindowEvent e) { + // no propagation to NEWT child window + } + + public void hierarchyChanged(java.awt.event.HierarchyEvent e) { + if( null == newtListener ) { + long bits = e.getChangeFlags(); + final java.awt.Component changed = e.getChanged(); + if( 0 != ( java.awt.event.HierarchyEvent.SHOWING_CHANGED & bits ) ) { + final boolean showing = changed.isShowing(); + if(DEBUG_IMPLEMENTATION) { + System.err.println("AWT: hierarchyChanged SHOWING_CHANGED: showing "+showing+", "+changed); + } + if(newtWindow.isValid()) { + newtWindow.runOnEDTIfAvail(false, new Runnable() { + public void run() { + if(newtWindow.isVisible() != showing) { + newtWindow.setVisible(showing); + } + }}); + } + } + if(DEBUG_IMPLEMENTATION) { + if( 0 != ( java.awt.event.HierarchyEvent.DISPLAYABILITY_CHANGED & bits ) ) { + final boolean displayability = changed.isDisplayable(); + System.err.println("AWT: hierarchyChanged DISPLAYABILITY_CHANGED: displayability "+displayability+", "+changed); + } + } + } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java b/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java new file mode 100644 index 000000000..85fe5407b --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/event/awt/AWTWindowAdapter.java @@ -0,0 +1,204 @@ +/** + * 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.event.awt; + +public class AWTWindowAdapter + extends AWTAdapter + implements java.awt.event.ComponentListener, java.awt.event.WindowListener, java.awt.event.FocusListener +{ + WindowClosingListener windowClosingListener; + + public AWTWindowAdapter(com.jogamp.newt.event.WindowListener newtListener) { + super(newtListener); + } + + public AWTWindowAdapter(com.jogamp.newt.event.WindowListener newtListener, com.jogamp.newt.Window newtProxy) { + super(newtListener, newtProxy); + } + + public AWTWindowAdapter(com.jogamp.newt.Window downstream) { + super(downstream); + } + + public AWTAdapter addTo(java.awt.Component awtComponent) { + java.awt.Window win = getWindow(awtComponent); + awtComponent.addComponentListener(this); + awtComponent.addFocusListener(this); + if( null == windowClosingListener ) { + windowClosingListener = new WindowClosingListener(); + } + if( null != win ) { + win.addWindowListener(windowClosingListener); + } + if(awtComponent instanceof java.awt.Window) { + ((java.awt.Window)awtComponent).addWindowListener(this); + } + return this; + } + + public AWTAdapter removeFrom(java.awt.Component awtComponent) { + awtComponent.removeFocusListener(this); + awtComponent.removeComponentListener(this); + java.awt.Window win = getWindow(awtComponent); + if( null != win && null != windowClosingListener ) { + win.removeWindowListener(windowClosingListener); + } + if(awtComponent instanceof java.awt.Window) { + ((java.awt.Window)awtComponent).removeWindowListener(this); + } + return this; + } + + static java.awt.Window getWindow(java.awt.Component comp) { + while( null != comp && !(comp instanceof java.awt.Window) ) { + comp = comp.getParent(); + } + if(comp instanceof java.awt.Window) { + return (java.awt.Window) comp; + } + return null; + } + + public void focusGained(java.awt.event.FocusEvent e) { + com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.WindowListener)newtListener).windowGainedFocus(event); + } else { + enqueueEvent(false, event); + } + } + + public void focusLost(java.awt.event.FocusEvent e) { + com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.WindowListener)newtListener).windowLostFocus(event); + } else { + enqueueEvent(false, event); + } + } + + public void componentResized(java.awt.event.ComponentEvent e) { + com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.WindowListener)newtListener).windowResized(event); + } else { + enqueueEvent(false, event); + } + } + + public void componentMoved(java.awt.event.ComponentEvent e) { + com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.WindowListener)newtListener).windowMoved(event); + } else { + enqueueEvent(false, event); + } + } + + public void componentShown(java.awt.event.ComponentEvent e) { + final java.awt.Component comp = e.getComponent(); + if(DEBUG_IMPLEMENTATION) { + System.err.println("AWT: componentShown: "+comp); + } + /** + if(null==newtListener) { + if(newtWindow.isValid()) { + newtWindow.runOnEDTIfAvail(false, new Runnable() { + public void run() { + newtWindow.setVisible(true); + } + }); + } + }*/ + } + + public void componentHidden(java.awt.event.ComponentEvent e) { + final java.awt.Component comp = e.getComponent(); + if(DEBUG_IMPLEMENTATION) { + System.err.println("AWT: componentHidden: "+comp); + } + /** + if(null==newtListener) { + if(newtWindow.isValid()) { + newtWindow.runOnEDTIfAvail(false, new Runnable() { + public void run() { + newtWindow.setVisible(false); + } + }); + } + }*/ + } + + public void windowActivated(java.awt.event.WindowEvent e) { + com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.WindowListener)newtListener).windowGainedFocus(event); + } else { + enqueueEvent(false, event); + } + } + + public void windowClosed(java.awt.event.WindowEvent e) { } + + public void windowClosing(java.awt.event.WindowEvent e) { } + + public void windowDeactivated(java.awt.event.WindowEvent e) { + com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.WindowListener)newtListener).windowLostFocus(event); + } else { + enqueueEvent(false, event); + } + } + + public void windowDeiconified(java.awt.event.WindowEvent e) { } + + public void windowIconified(java.awt.event.WindowEvent e) { } + + public void windowOpened(java.awt.event.WindowEvent e) { } + + class WindowClosingListener implements java.awt.event.WindowListener { + public void windowClosing(java.awt.event.WindowEvent e) { + com.jogamp.newt.event.WindowEvent event = AWTNewtEventFactory.createWindowEvent(e, newtWindow); + if(null!=newtListener) { + ((com.jogamp.newt.event.WindowListener)newtListener).windowDestroyNotify(event); + } else { + enqueueEvent(true, event); + } + } + + public void windowActivated(java.awt.event.WindowEvent e) { } + public void windowClosed(java.awt.event.WindowEvent e) { } + public void windowDeactivated(java.awt.event.WindowEvent e) { } + public void windowDeiconified(java.awt.event.WindowEvent e) { } + public void windowIconified(java.awt.event.WindowEvent e) { } + public void windowOpened(java.awt.event.WindowEvent e) { } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/Debug.java b/src/newt/classes/com/jogamp/newt/impl/Debug.java new file mode 100644 index 000000000..62c261d2e --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/Debug.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2003-2005 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. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.newt.impl; + +import java.security.*; + +/** Helper routines for logging and debugging. */ + +public class Debug { + // Some common properties + private static boolean verbose; + private static boolean debugAll; + private static AccessControlContext localACC; + + static { + localACC=AccessController.getContext(); + verbose = isPropertyDefined("newt.verbose", true); + debugAll = isPropertyDefined("newt.debug", true); + if (verbose) { + Package p = Package.getPackage("com.jogamp.newt"); + System.err.println("NEWT specification version " + p.getSpecificationVersion()); + System.err.println("NEWT implementation version " + p.getImplementationVersion()); + System.err.println("NEWT implementation vendor " + p.getImplementationVendor()); + } + } + + static int getIntProperty(final String property, final boolean jnlpAlias) { + return getIntProperty(property, jnlpAlias, localACC); + } + + public static int getIntProperty(final String property, final boolean jnlpAlias, final AccessControlContext acc) { + int i=0; + try { + Integer iv = Integer.valueOf(Debug.getProperty(property, jnlpAlias, acc)); + i = iv.intValue(); + } catch (NumberFormatException nfe) {} + return i; + } + + static boolean getBooleanProperty(final String property, final boolean jnlpAlias) { + return getBooleanProperty(property, jnlpAlias, localACC); + } + + public static boolean getBooleanProperty(final String property, final boolean jnlpAlias, final AccessControlContext acc) { + Boolean b = Boolean.valueOf(Debug.getProperty(property, jnlpAlias, acc)); + return b.booleanValue(); + } + + static boolean isPropertyDefined(final String property, final boolean jnlpAlias) { + return isPropertyDefined(property, jnlpAlias, localACC); + } + + public static boolean isPropertyDefined(final String property, final boolean jnlpAlias, final AccessControlContext acc) { + return (Debug.getProperty(property, jnlpAlias, acc) != null) ? true : false; + } + + static String getProperty(final String property, final boolean jnlpAlias) { + return getProperty(property, jnlpAlias, localACC); + } + + public static String getProperty(final String property, final boolean jnlpAlias, final AccessControlContext acc) { + String s=null; + if(null!=acc && acc.equals(localACC)) { + s = (String) AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + String val=null; + try { + val = System.getProperty(property); + } catch (Exception e) {} + if(null==val && jnlpAlias && !property.startsWith(jnlp_prefix)) { + try { + val = System.getProperty(jnlp_prefix + property); + } catch (Exception e) {} + } + return val; + } + }); + } else { + try { + s = System.getProperty(property); + } catch (Exception e) {} + if(null==s && jnlpAlias && !property.startsWith(jnlp_prefix)) { + try { + s = System.getProperty(jnlp_prefix + property); + } catch (Exception e) {} + } + } + return s; + } + public static final String jnlp_prefix = "jnlp." ; + + public static boolean verbose() { + return verbose; + } + + public static boolean debugAll() { + return debugAll; + } + + public static boolean debug(String subcomponent) { + return debugAll() || isPropertyDefined("newt.debug." + subcomponent, true); + } +} diff --git a/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java b/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java new file mode 100644 index 000000000..d7a22b92c --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java @@ -0,0 +1,325 @@ +/* + * Copyright (c) 2009 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. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +package com.jogamp.newt.impl; + +import com.jogamp.common.util.RunnableTask; +import com.jogamp.newt.Display; +import com.jogamp.newt.util.EDTUtil; +import java.util.*; + +public class DefaultEDTUtil implements EDTUtil { + public static final boolean DEBUG = Debug.debug("EDT"); + + private ThreadGroup threadGroup; + private EventDispatchThread edt = null; + private Object edtLock = new Object(); // locking the EDT start/stop state + private String name; + int start_iter=0; + private Runnable dispatchMessages; + + public DefaultEDTUtil(ThreadGroup tg, String name, Runnable dispatchMessages) { + this.threadGroup = tg; + this.name=new String(Thread.currentThread().getName()+"-"+name+"-EDT-"); + this.dispatchMessages=dispatchMessages; + this.edt = new EventDispatchThread(threadGroup, name); + } + + public final void reset() { + synchronized(edtLock) { + waitUntilStopped(); + if(DEBUG) { + if(edt.tasks.size()>0) { + String msg = Thread.currentThread()+": EDT reset, remaining tasks: "+edt.tasks.size()+" - "+edt; + System.err.println(msg); + // Throwable t = new Throwable(msg); + // t.printStackTrace(); + } + System.err.println(Thread.currentThread()+": EDT reset - edt: "+edt); + } + this.edt = new EventDispatchThread(threadGroup, name); + } + } + + public final void start() { + synchronized(edtLock) { + if(!edt.isRunning() && !edt.shouldStop) { + if(edt.isAlive()) { + throw new RuntimeException("EDT Thread.isAlive(): true, isRunning: "+edt.isRunning()+", edt: "+edt+", tasks: "+edt.tasks.size()); + } + start_iter++; + edt.setName(name+start_iter); + edt.shouldStop = false; + if(DEBUG) { + String msg = Thread.currentThread()+": EDT START - edt: "+edt; + System.err.println(msg); + // Throwable t = new Throwable(msg); + // t.printStackTrace(); + } + edt.start(); + } + } + } + + public final boolean isCurrentThreadEDT() { + return edt == Thread.currentThread(); + } + + public final boolean isRunning() { + return edt.isRunning() ; + } + + public final void invokeStop(Runnable task) { + invokeImpl(true, task, true); + } + + public final void invoke(boolean wait, Runnable task) { + invokeImpl(wait, task, false); + } + + private final void invokeImpl(boolean wait, Runnable task, boolean stop) { + if(task == null) { + throw new RuntimeException("Null Runnable"); + } + Throwable throwable = null; + RunnableTask rTask = null; + Object rTaskLock = new Object(); + synchronized(rTaskLock) { // lock the optional task execution + synchronized(edtLock) { // lock the EDT status + if( edt.shouldStop ) { + // drop task .. + if(DEBUG) { + Throwable t = new Throwable("Warning: EDT about (1) to stop, won't enqueue new task: "+edt); + t.printStackTrace(); + } + return; + } + // Exception ee = new Exception("XXX stop: "+stop+", tasks: "+edt.tasks.size()+", task: "+task); + // ee.printStackTrace(); + if(stop) { + edt.shouldStop = true; + if(DEBUG) { + String msg = Thread.currentThread()+": EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - edt: "+edt; + System.err.println(msg); + // Throwable t = new Throwable(msg); + // t.printStackTrace(); + } + } + if( isCurrentThreadEDT() ) { + task.run(); + wait = false; // running in same thread (EDT) -> no wait + if(stop && edt.tasks.size()>0) { + String msg = "Warning: EDT about (2) to stop, having remaining tasks: "+edt.tasks.size()+" - "+edt; + if(DEBUG) { + Throwable t = new Throwable(msg); + t.printStackTrace(); + } else { + System.err.println(msg); + } + } + } else { + synchronized(edt.tasks) { + start(); // start if not started yet and !shouldStop + wait = wait && edt.isRunning(); + rTask = new RunnableTask(task, + wait ? rTaskLock : null, + true /* always catch and report Exceptions, don't disturb EDT */); + if(stop) { + rTask.setAttachment(new Boolean(true)); // mark final task + } + // append task .. + edt.tasks.add(rTask); + edt.tasks.notifyAll(); + } + } + } + if( wait ) { + try { + rTaskLock.wait(); // free lock, allow execution of rTask + } catch (InterruptedException ie) { + throwable = ie; + } + if(null==throwable) { + throwable = rTask.getThrowable(); + } + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + } + if(DEBUG && stop) { + System.err.println(Thread.currentThread()+": EDT signal STOP X edt: "+edt); + } + } + + public void waitUntilIdle() { + if(edt.isRunning() && edt != Thread.currentThread()) { + synchronized(edt.tasks) { + while(edt.isRunning() && edt.tasks.size()>0) { + try { + edt.tasks.notifyAll(); + edt.tasks.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } + + public void waitUntilStopped() { + if(edt.isRunning() && edt != Thread.currentThread() ) { + synchronized(edtLock) { + if(edt.isRunning() && edt != Thread.currentThread() ) { + while(edt.isRunning()) { + try { + edtLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + } + } + + class EventDispatchThread extends Thread { + volatile boolean shouldStop = false; + volatile boolean isRunning = false; + ArrayList tasks = new ArrayList(); // one shot tasks + + public EventDispatchThread(ThreadGroup tg, String name) { + super(tg, name); + } + + public final boolean isRunning() { + return isRunning; + } + + public void start() throws IllegalThreadStateException { + isRunning = true; + super.start(); + } + + /** + * Utilizing locking only on tasks and its execution, + * not for event dispatching. + */ + public void run() { + if(DEBUG) { + System.err.println(getName()+": EDT run() START "+ getName()); + } + RuntimeException error = null; + try { + do { + // event dispatch + if(!shouldStop) { + dispatchMessages.run(); + } + // wait and work on tasks + RunnableTask task = null; + synchronized(tasks) { + // wait for tasks + if(!shouldStop && tasks.size()==0) { + try { + tasks.wait(defaultEDTPollGranularity); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + // execute one task, if available + if(tasks.size()>0) { + task = (RunnableTask) tasks.remove(0); + tasks.notifyAll(); + } + } + if(null!=task) { + // Exceptions are always catched, see RunnableTask creation above + task.run(); + } + } while(!shouldStop) ; + } catch (Throwable t) { + // handle errors .. + shouldStop = true; + if(t instanceof RuntimeException) { + error = (RuntimeException) t; + } else { + error = new RuntimeException("Within EDT", t); + } + } finally { + if(DEBUG) { + RunnableTask rt = ( tasks.size() > 0 ) ? (RunnableTask) tasks.get(0) : null ; + System.err.println(getName()+": EDT run() END "+ getName()+", tasks: "+tasks.size()+", "+rt+", "+error); + } + synchronized(edtLock) { + if(null==error) { + synchronized(tasks) { + // drain remaining tasks (stop not on EDT), + // while having tasks and no previous-task, or previous-task is non final + RunnableTask task = null; + while ( ( null == task || task.getAttachment() == null ) && tasks.size() > 0 ) { + task = ( RunnableTask ) tasks.remove(0); + task.run(); + tasks.notifyAll(); + } + if(DEBUG) { + if(null!=task && task.getAttachment()==null) { + Throwable t = new Throwable("Warning: EDT exit: Last task Not Final: "+tasks.size()+", "+task+" - "+edt); + t.printStackTrace(); + } else if(tasks.size()>0) { + Throwable t = new Throwable("Warning: EDT exit: Remaining tasks Post Final: "+tasks.size()); + t.printStackTrace(); + } + } + } + } + isRunning = !shouldStop; + if(!isRunning) { + edtLock.notifyAll(); + } + } + if(DEBUG) { + System.err.println(getName()+": EDT run() EXIT "+ getName()+", "+error); + } + if(null!=error) { + throw error; + } + } + } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java b/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java new file mode 100644 index 000000000..d22e9c7c4 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java @@ -0,0 +1,395 @@ +/* + * 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.Display; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.event.NEWTEvent; +import com.jogamp.newt.event.NEWTEventConsumer; +import com.jogamp.newt.impl.event.NEWTEventTask; +import com.jogamp.newt.util.EDTUtil; +import com.jogamp.newt.util.MainThread; +import java.util.ArrayList; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeWindowFactory; + +public abstract class DisplayImpl extends Display { + public static final boolean DEBUG_TEST_EDT_MAINTHREAD = Debug.isPropertyDefined("newt.test.EDTMainThread", true); // JAU EDT Test .. + + private static int serialno = 1; + + private static Class getDisplayClass(String type) + throws ClassNotFoundException + { + Class displayClass = NewtFactory.getCustomClass(type, "Display"); + if(null==displayClass) { + if (NativeWindowFactory.TYPE_EGL.equals(type)) { + displayClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDDisplay"); + } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { + displayClass = Class.forName("com.jogamp.newt.impl.windows.WindowsDisplay"); + } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { + displayClass = Class.forName("com.jogamp.newt.impl.macosx.MacDisplay"); + } else if (NativeWindowFactory.TYPE_X11.equals(type)) { + displayClass = Class.forName("com.jogamp.newt.impl.x11.X11Display"); + } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { + displayClass = Class.forName("com.jogamp.newt.impl.awt.AWTDisplay"); + } else { + throw new RuntimeException("Unknown display type \"" + type + "\""); + } + } + return displayClass; + } + + /** Make sure to reuse a Display with the same name */ + public static Display create(String type, String name, final long handle, boolean reuse) { + try { + Class displayClass = getDisplayClass(type); + DisplayImpl display = (DisplayImpl) displayClass.newInstance(); + name = display.validateDisplayName(name, handle); + synchronized(displayList) { + if(reuse) { + Display display0 = Display.getLastDisplayOf(type, name, -1); + if(null != display0) { + if(DEBUG) { + System.err.println("Display.create() REUSE: "+display0+" "+getThreadName()); + } + return display0; + } + } + display.name = name; + display.type=type; + display.destroyWhenUnused=false; + display.refCount=0; + display.id = serialno++; + display.fqname = getFQName(display.type, display.name, display.id); + display.hashCode = display.fqname.hashCode(); + displayList.add(display); + } + display.createEDTUtil(); + if(DEBUG) { + System.err.println("Display.create() NEW: "+display+" "+getThreadName()); + } + return display; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public int hashCode() { + return hashCode; + } + + protected synchronized final void createNative() { + if(null==aDevice) { + if(DEBUG) { + System.err.println("Display.createNative() START ("+getThreadName()+", "+this+")"); + } + final DisplayImpl f_dpy = this; + runOnEDTIfAvail(true, new Runnable() { + public void run() { + f_dpy.createNativeImpl(); + }}); + if(null==aDevice) { + throw new RuntimeException("Display.createNative() failed to instanciate an AbstractGraphicsDevice"); + } + if(DEBUG) { + System.err.println("Display.createNative() END ("+getThreadName()+", "+this+")"); + } + synchronized(displayList) { + displaysActive++; + } + } + } + + protected boolean shallRunOnEDT() { + return true; + } + + protected void createEDTUtil() { + if(NewtFactory.useEDT()) { + if ( ! DEBUG_TEST_EDT_MAINTHREAD ) { + Thread current = Thread.currentThread(); + edtUtil = new DefaultEDTUtil(current.getThreadGroup(), "Display-"+getFQName(), dispatchMessagesRunnable); + } else { + // Begin JAU EDT Test .. + MainThread.addPumpMessage(this, dispatchMessagesRunnable); + edtUtil = MainThread.getSingleton(); + // End JAU EDT Test .. + } + if(DEBUG) { + System.err.println("Display.createNative("+getFQName()+") Create EDTUtil: "+edtUtil.getClass().getName()); + } + } + } + + public final EDTUtil getEDTUtil() { + return edtUtil; + } + + private void stopEDT(final Runnable task) { + if( shallRunOnEDT() && null!=edtUtil ) { + edtUtil.invokeStop(task); + } else { + task.run(); + } + } + + public void runOnEDTIfAvail(boolean wait, final Runnable task) { + if( shallRunOnEDT() && null!=edtUtil ) { + edtUtil.invoke(wait, task); + } else { + task.run(); + } + } + + public synchronized final void destroy() { + if(DEBUG) { + dumpDisplayList("Display.destroy("+getFQName()+") BEGIN"); + } + synchronized(displayList) { + displayList.remove(this); + displaysActive--; + } + if(DEBUG) { + System.err.println("Display.destroy(): "+this+" "+getThreadName()); + } + final AbstractGraphicsDevice f_aDevice = aDevice; + final DisplayImpl f_dpy = this; + stopEDT( new Runnable() { + public void run() { + if ( null != f_aDevice ) { + f_dpy.closeNativeImpl(); + } + } + } ); + if(null!=edtUtil) { + if ( DEBUG_TEST_EDT_MAINTHREAD ) { + MainThread.removePumpMessage(this); // JAU EDT Test .. + } + edtUtil.waitUntilStopped(); + edtUtil.reset(); + } + aDevice = null; + refCount=0; + if(DEBUG) { + dumpDisplayList("Display.destroy("+getFQName()+") END"); + } + } + + public synchronized final int addReference() { + if(DEBUG) { + System.err.println("Display.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1)); + } + if ( 0 == refCount ) { + createNative(); + } + if(null == aDevice) { + throw new RuntimeException("Display.addReference() (refCount "+refCount+") null AbstractGraphicsDevice"); + } + return ++refCount; + } + + + public synchronized final int removeReference() { + if(DEBUG) { + System.err.println("Display.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); + } + refCount--; // could become < 0, in case of forced destruction without actual creation/addReference + if(0>=refCount && getDestroyWhenUnused()) { + 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 ; + } + + protected static final String getFQName(String type, String name, int id) { + 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 ArrayList/*<NEWTEvent>*/ events = new ArrayList(); + + 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 + + ArrayList/*<NEWTEvent>*/ _events = null; + + if(events.size()>0) { + // swap events list to free ASAP + synchronized(eventsLock) { + if(events.size()>0) { + _events = events; + events = new ArrayList(); + } + eventsLock.notifyAll(); + } + if( null != _events ) { + for (int i=0; i < _events.size(); i++) { + NEWTEventTask eventTask = (NEWTEventTask) _events.get(i); + 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(); + } + } + } + + // System.err.println("Display.dispatchMessages() NATIVE "+this+" "+getThreadName()); + dispatchMessagesNative(); + } + + public void enqueueEvent(boolean wait, NEWTEvent e) { + if(!isEDTRunning()) { + // oops .. we are already dead + if(DEBUG) { + Throwable t = new Throwable("Warning: EDT already stopped: wait:="+wait+", "+e); + t.printStackTrace(); + } + return; + } + Object lock = new Object(); + NEWTEventTask eTask = new NEWTEventTask(e, wait?lock:null); + synchronized(lock) { + synchronized(eventsLock) { + events.add(eTask); + eventsLock.notifyAll(); + } + if( wait ) { + try { + lock.wait(); + } catch (InterruptedException ie) { + throw new RuntimeException(ie); + } + } + } + } + + protected EDTUtil edtUtil = null; + protected int id; + protected String name; + protected String type; + protected String fqname; + protected int hashCode; + 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/NEWTJNILibLoader.java b/src/newt/classes/com/jogamp/newt/impl/NEWTJNILibLoader.java new file mode 100644 index 000000000..a4d234fd5 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/NEWTJNILibLoader.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2003 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. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + * + * Sun gratefully acknowledges that this software was originally authored + * and developed by Kenneth Bradley Russell and Christopher John Kline. + */ + +package com.jogamp.newt.impl; + +// FIXME: refactor Java SE dependencies +//import java.awt.Toolkit; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashSet; +import com.jogamp.common.jvm.JNILibLoaderBase; + +public class NEWTJNILibLoader extends JNILibLoaderBase { + + public static void loadNEWT() { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + loadLibrary("newt", null, true); + return null; + } + }); + } + +} 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..f3c7b8415 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/OffscreenWindow.java @@ -0,0 +1,127 @@ +/* + * 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.*; +import javax.media.nativewindow.util.Point; + +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, int x, int y, int width, int height) { + sizeChanged(width, height, false); + visibleChanged(visible); + } + + protected void requestFocusImpl(boolean reparented) { + } + + public void setSize(int width, int height) { + if(!visible) { + sizeChanged(width, height, false); + } + } + public void setPosition(int x, int y) { + // nop + } + public boolean setFullscreen(boolean fullscreen) { + // nop + return false; + } + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, boolean parentChange, int fullScreenChange, int decorationChange) { + shouldNotCallThis(); + return false; + } + + public Point getLocationOnScreen(Point storage) { + if(null!=storage) { + storage.setX(0); + storage.setY(0); + return storage; + } + return new Point(0,0); + } + + protected Point getLocationOnScreenImpl(int x, int y) { + return new Point(x,y); + } +} + 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..ebb496988 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java @@ -0,0 +1,503 @@ +/* + * 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.common.util.ArrayHashSet; +import com.jogamp.common.util.IntIntHashMap; +import com.jogamp.newt.Display; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Screen; +import com.jogamp.newt.ScreenMode; +import com.jogamp.newt.event.ScreenModeListener; +import com.jogamp.newt.util.ScreenModeUtil; + +import javax.media.nativewindow.*; + +import java.security.*; +import java.util.ArrayList; +import java.util.List; + +public abstract class ScreenImpl extends Screen implements ScreenModeListener { + protected static final boolean DisableScreenModeImpl = Debug.debug("Screen.DisableScreenModeImpl"); + protected DisplayImpl display; + protected int screen_idx; + protected String fqname; + protected int hashCode; + 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(); + private List/*<ScreenModeListener>*/ referencedScreenModeListener = new ArrayList(); + long t0; // creationTime + + 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 Screen create(Display display, final int idx) { + try { + if(usrWidth<0 || usrHeight<0) { + synchronized (Screen.class) { + 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); + } + } + } + } + synchronized(screenList) { + { + Screen screen0 = ScreenImpl.getLastScreenOf(display, idx, -1); + if(null != screen0) { + if(DEBUG) { + System.err.println("Screen.create() REUSE: "+screen0+" "+Display.getThreadName()); + } + return screen0; + } + } + Class screenClass = getScreenClass(display.getType()); + ScreenImpl screen = (ScreenImpl) screenClass.newInstance(); + screen.display = (DisplayImpl) display; + screen.screen_idx = idx; + screen.fqname = display.getFQName()+idx; + screen.hashCode = screen.fqname.hashCode(); + screenList.add(screen); + if(DEBUG) { + System.err.println("Screen.create() NEW: "+screen+" "+Display.getThreadName()); + } + return screen; + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + public int hashCode() { + return hashCode; + } + + protected synchronized final void createNative() { + if(null == aScreen) { + if(DEBUG) { + System.err.println("Screen.createNative() START ("+DisplayImpl.getThreadName()+", "+this+")"); + } + t0 = System.currentTimeMillis(); + 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+")"); + } + synchronized(screenList) { + screensActive++; + } + } + initScreenModeStatus(); + } + + public synchronized final void destroy() { + releaseScreenModeStatus(); + + synchronized(screenList) { + screenList.remove(this); + screensActive--; + } + + if ( null != aScreen ) { + closeNativeImpl(); + aScreen = null; + } + refCount = 0; + display.removeReference(); + } + + public 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; + } + + public synchronized final int removeReference() { + if(DEBUG) { + System.err.println("Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); + } + refCount--; // could become < 0, in case of forced destruction without actual creation/addReference + 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(); + + public final String getFQName() { + return fqname; + } + + 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 screen_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["+getFQName()+", idx "+screen_idx+", refCount "+refCount+", "+getWidth()+"x"+getHeight()+", "+aScreen+", "+display+"]"; + } + + public final List/*<ScreenMode>*/ getScreenModes() { + ArrayHashSet screenModes = getScreenModesOrig(); + if(null != screenModes && 0 < screenModes.size()) { + return screenModes.toArrayList(); + } + return null; + } + + public ScreenMode getOriginalScreenMode() { + ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName()); + return ( null != sms ) ? sms.getOriginalScreenMode() : null ; + } + + public ScreenMode getCurrentScreenMode() { + ScreenMode smU = null; + ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName()); + if(null != sms) { + ScreenMode sm0 = ( DisableScreenModeImpl ) ? null : getCurrentScreenModeImpl(); + if(null == sm0) { + return null; + } + sms.lock(); + try { + smU = (ScreenMode) sms.getScreenModes().get(sm0); // unify via value hash + if(null == smU) { + throw new RuntimeException(sm0+" could not be hashed from ScreenMode list"); + } + + // if mode has changed somehow, update it .. + if( sms.getCurrentScreenMode().hashCode() != smU.hashCode() ) { + sms.fireScreenModeChanged(smU, true); + } + } finally { + sms.unlock(); + } + } + return smU; + } + + public boolean setCurrentScreenMode(ScreenMode screenMode) { + ScreenMode smU = (ScreenMode) getScreenModesOrig().get(screenMode); // unify via value hash + ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName()); + if(null!=sms) { + sms.lock(); + try { + if(DEBUG) { + System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): 0.0 "+screenMode); + } + + sms.fireScreenModeChangeNotify(smU); + + if(DEBUG) { + System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): 0.1 "+screenMode); + } + + boolean success = setCurrentScreenModeImpl(smU); + if(success) { + setScreenSize(screenMode.getMonitorMode().getSurfaceSize().getResolution().getWidth(), + screenMode.getMonitorMode().getSurfaceSize().getResolution().getHeight()); + } + + if(DEBUG) { + System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): X.0 "+screenMode+", success: "+success); + } + + sms.fireScreenModeChanged(smU, success); + + if(DEBUG) { + System.err.println("Screen.setCurrentScreenMode ("+(System.currentTimeMillis()-t0)+"): X.X "+screenMode+", success: "+success); + } + + return success; + } finally { + sms.unlock(); + } + } + return false; + } + + public void screenModeChangeNotify(ScreenMode sm) { + for(int i=0; i<referencedScreenModeListener.size(); i++) { + ((ScreenModeListener)referencedScreenModeListener.get(i)).screenModeChangeNotify(sm); + } + } + + public void screenModeChanged(ScreenMode sm, boolean success) { + for(int i=0; i<referencedScreenModeListener.size(); i++) { + ((ScreenModeListener)referencedScreenModeListener.get(i)).screenModeChanged(sm, success); + } + } + + public synchronized final void addScreenModeListener(ScreenModeListener sml) { + referencedScreenModeListener.add(sml); + } + + public synchronized final void removeScreenModeListener(ScreenModeListener sml) { + referencedScreenModeListener.remove(sml); + } + + /** ScreenModeStatus bridge to native implementation */ + protected final ArrayHashSet getScreenModesOrig() { + ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName()); + if(null!=sms) { + return sms.getScreenModes(); + } + return null; + } + + /** ScreenModeStatus bridge to native implementation */ + protected final IntIntHashMap getScreenModesIdx2NativeIdx() { + ScreenModeStatus sms = ScreenModeStatus.getScreenModeStatus(this.getFQName()); + if(null!=sms) { + return sms.getScreenModesIdx2NativeIdx(); + } + return null; + } + + /** + * To be implemented by the native specification.<br> + * Is called within a thread safe environment.<br> + * Is called only to collect the ScreenModes, usually at startup setting up modes.<br> + * <br> + * <b>WARNING</b>: must be synchronized with {@link com.jogamp.newt.util.ScreenModeUtil#NUM_SCREEN_MODE_PROPERTIES}, + * ie {@link com.jogamp.newt.util.ScreenModeUtil#streamIn(com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, int[], int)}<br> + * <br> + * <b>Note</b>: Additional 1st element is native mode id. + */ + protected int[] getScreenModeFirstImpl() { + return null; + } + + /** + * To be implemented by the native specification.<br> + * Is called within a thread safe environment.<br> + * Is called only to collect the ScreenModes, usually at startup setting up modes.<br> + * <br> + * <b>WARNING</b>: must be synchronized with {@link com.jogamp.newt.util.ScreenModeUtil#NUM_SCREEN_MODE_PROPERTIES}, + * ie {@link com.jogamp.newt.util.ScreenModeUtil#streamIn(com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, com.jogamp.common.util.ArrayHashSet, int[], int)}<br> + * <br> + * <b>Note</b>: Additional 1st element is native mode id. + */ + protected int[] getScreenModeNextImpl() { + return null; + } + + /** + * To be implemented by the native specification.<br> + * Is called within a thread safe environment.<br> + */ + protected ScreenMode getCurrentScreenModeImpl() { + return null; + } + + /** + * To be implemented by the native specification.<br> + * Is called within a thread safe environment.<br> + */ + protected boolean setCurrentScreenModeImpl(ScreenMode screenMode) { + return false; + } + + private void initScreenModeStatus() { + ScreenModeStatus sms; + ScreenModeStatus.lockScreenModeStatus(); + try { + sms = ScreenModeStatus.getScreenModeStatus(this.getFQName()); + if(null==sms) { + IntIntHashMap screenModesIdx2NativeIdx = new IntIntHashMap(); + + ArrayHashSet screenModes = collectNativeScreenModes(screenModesIdx2NativeIdx); + sms = new ScreenModeStatus(screenModes, screenModesIdx2NativeIdx); + if(null!=screenModes && screenModes.size()>0) { + ScreenMode originalScreenMode = ( DisableScreenModeImpl ) ? null : getCurrentScreenModeImpl(); + if(null != originalScreenMode) { + ScreenMode originalScreenMode0 = (ScreenMode) screenModes.get(originalScreenMode); // unify via value hash + if(null == originalScreenMode0) { + throw new RuntimeException(originalScreenMode+" could not be hashed from ScreenMode list"); + } + sms.setOriginalScreenMode(originalScreenMode0); + } + } + ScreenModeStatus.mapScreenModeStatus(this.getFQName(), sms); + } + sms.addListener(this); + } finally { + ScreenModeStatus.unlockScreenModeStatus(); + } + } + + /** ignores bpp < 15 */ + private ArrayHashSet collectNativeScreenModes(IntIntHashMap screenModesIdx2NativeId) { + ArrayHashSet resolutionPool = new ArrayHashSet(); + ArrayHashSet surfaceSizePool = new ArrayHashSet(); + ArrayHashSet screenSizeMMPool = new ArrayHashSet(); + ArrayHashSet monitorModePool = new ArrayHashSet(); + ArrayHashSet screenModePool = null; + + screenModePool = new ArrayHashSet(); + + int[] smProps = null; + int num = 0; + final int idxBpp = 1 // native mode + + 1 // count + + ScreenModeUtil.NUM_RESOLUTION_PROPERTIES + + ScreenModeUtil.NUM_SURFACE_SIZE_PROPERTIES + - 1 ; // index 0 based + do { + if(DisableScreenModeImpl) { + smProps = null; + } else if(0 == num) { + smProps = getScreenModeFirstImpl(); + } else { + smProps = getScreenModeNextImpl(); + } + if(null != smProps && 0 < smProps.length && smProps[idxBpp] >= 15) { + int nativeId = smProps[0]; + int screenModeIdx = ScreenModeUtil.streamIn(resolutionPool, surfaceSizePool, screenSizeMMPool, + monitorModePool, screenModePool, smProps, 1); + if(screenModeIdx >= 0) { + screenModesIdx2NativeId.put(screenModeIdx, nativeId); + } + } + num++; + } while ( null != smProps && 0 < smProps.length ); + + if(DEBUG) { + System.err.println("ScreenImpl.collectNativeScreenModes: ScreenMode number : "+screenModePool.size()); + System.err.println("ScreenImpl.collectNativeScreenModes: MonitorMode number : "+monitorModePool.size()); + System.err.println("ScreenImpl.collectNativeScreenModes: ScreenSizeMM number: "+screenSizeMMPool.size()); + System.err.println("ScreenImpl.collectNativeScreenModes: SurfaceSize number : "+surfaceSizePool.size()); + System.err.println("ScreenImpl.collectNativeScreenModes: Resolution number : "+resolutionPool.size()); + } + + return screenModePool; + } + + private void releaseScreenModeStatus() { + ScreenModeStatus sms; + ScreenModeStatus.lockScreenModeStatus(); + try { + sms = ScreenModeStatus.getScreenModeStatus(this.getFQName()); + if(null != sms) { + sms.lock(); + try { + if(0 == sms.removeListener(this)) { + if(!sms.isOriginalMode()) { + setCurrentScreenMode(sms.getOriginalScreenMode()); + } + ScreenModeStatus.unmapScreenModeStatus(this.getFQName()); + } + } finally { + sms.unlock(); + } + } + } finally { + ScreenModeStatus.unlockScreenModeStatus(); + } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/ScreenModeStatus.java b/src/newt/classes/com/jogamp/newt/impl/ScreenModeStatus.java new file mode 100644 index 000000000..3ca9b638b --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/ScreenModeStatus.java @@ -0,0 +1,207 @@ +/** + * 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.impl; + +import com.jogamp.common.util.ArrayHashSet; +import com.jogamp.common.util.IntIntHashMap; +import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.newt.Screen; +import com.jogamp.newt.ScreenMode; +import com.jogamp.newt.event.ScreenModeListener; +import java.util.ArrayList; +import java.util.HashMap; + +public class ScreenModeStatus { + private static boolean DEBUG = Screen.DEBUG; + + private RecursiveLock lock = new RecursiveLock(); + private ArrayHashSet/*<ScreenMode>*/ screenModes; + private IntIntHashMap screenModesIdx2NativeIdx; + private ScreenMode currentScreenMode; + private ScreenMode originalScreenMode; + private ArrayList/*<ScreenModeChangeListener>*/ listener = new ArrayList(); + + private static HashMap screenFQN2ScreenModeStatus = new HashMap(); + private static RecursiveLock screen2ScreenModeStatusLock = new RecursiveLock(); + + protected static void mapScreenModeStatus(String screenFQN, ScreenModeStatus sms) { + screen2ScreenModeStatusLock.lock(); + try { + ScreenModeStatus _sms = (ScreenModeStatus) screenFQN2ScreenModeStatus.get(screenFQN); + if( null != _sms ) { + throw new RuntimeException("ScreenModeStatus "+_sms+" already mapped to "+screenFQN); + } + screenFQN2ScreenModeStatus.put(screenFQN, sms); + if(DEBUG) { + System.err.println("ScreenModeStatus.map "+screenFQN+" -> "+sms); + } + } finally { + screen2ScreenModeStatusLock.unlock(); + } + } + + /** + * @param screen the prev user + * @return true if mapping is empty, ie no more usage of the mapped ScreenModeStatus + */ + protected static void unmapScreenModeStatus(String screenFQN) { + screen2ScreenModeStatusLock.lock(); + try { + ScreenModeStatus sms = (ScreenModeStatus) screenFQN2ScreenModeStatus.remove(screenFQN); + if(DEBUG) { + System.err.println("ScreenModeStatus.unmap "+screenFQN+" -> "+sms); + } + } finally { + screen2ScreenModeStatusLock.unlock(); + } + } + + protected static ScreenModeStatus getScreenModeStatus(String screenFQN) { + screen2ScreenModeStatusLock.lock(); + try { + return (ScreenModeStatus) screenFQN2ScreenModeStatus.get(screenFQN); + } finally { + screen2ScreenModeStatusLock.unlock(); + } + } + + protected static void lockScreenModeStatus() { + screen2ScreenModeStatusLock.lock(); + } + + protected static void unlockScreenModeStatus() { + screen2ScreenModeStatusLock.unlock(); + } + + public ScreenModeStatus(ArrayHashSet/*<ScreenMode>*/ screenModes, + IntIntHashMap screenModesIdx2NativeIdx) { + this.screenModes = screenModes; + this.screenModesIdx2NativeIdx = screenModesIdx2NativeIdx; + } + + protected final void setOriginalScreenMode(ScreenMode originalScreenMode) { + this.originalScreenMode = originalScreenMode; + this.currentScreenMode = originalScreenMode; + } + + public final ScreenMode getOriginalScreenMode() { + return originalScreenMode; + } + + public final ScreenMode getCurrentScreenMode() { + lock(); + try { + return currentScreenMode; + } finally { + unlock(); + } + } + + public final boolean isOriginalMode() { + lock(); + try { + if(null != currentScreenMode && null != originalScreenMode) { + return currentScreenMode.hashCode() == originalScreenMode.hashCode(); + } + return true; + } finally { + unlock(); + } + } + + protected final ArrayHashSet/*<ScreenMode>*/ getScreenModes() { + return screenModes; + } + + protected final IntIntHashMap getScreenModesIdx2NativeIdx() { + return screenModesIdx2NativeIdx; + } + + protected final int addListener(ScreenModeListener l) { + lock(); + try { + listener.add(l); + if(DEBUG) { + System.err.println("ScreenModeStatus.addListener (size: "+listener.size()+"): "+l); + } + return listener.size(); + } finally { + unlock(); + } + } + + protected final int removeListener(ScreenModeListener l) { + lock(); + try { + if(!listener.remove(l)) { + throw new RuntimeException("ScreenModeListener "+l+" not contained"); + } + if(DEBUG) { + System.err.println("ScreenModeStatus.removeListener (size: "+listener.size()+"): "+l); + } + return listener.size(); + } finally { + unlock(); + } + } + + protected final void fireScreenModeChangeNotify(ScreenMode desiredScreenMode) { + lock(); + try { + for(int i=0; i<listener.size(); i++) { + ((ScreenModeListener)listener.get(i)).screenModeChangeNotify(desiredScreenMode); + } + } finally { + unlock(); + } + } + + protected void fireScreenModeChanged(ScreenMode currentScreenMode, boolean success) { + lock(); + try { + if(success) { + this.currentScreenMode = currentScreenMode; + } + for(int i=0; i<listener.size(); i++) { + ((ScreenModeListener)listener.get(i)).screenModeChanged(currentScreenMode, success); + } + } finally { + unlock(); + } + } + + protected final void lock() throws RuntimeException { + lock.lock(); + } + + protected final void unlock() throws RuntimeException { + lock.unlock(); + } + +} 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..d7504cfdf --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java @@ -0,0 +1,2128 @@ +/* + * 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.common.util.ReflectionUtil; +import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Display; +import com.jogamp.newt.Screen; +import com.jogamp.newt.Window; +import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.newt.ScreenMode; +import com.jogamp.newt.event.KeyEvent; +import com.jogamp.newt.event.KeyListener; +import com.jogamp.newt.event.MouseEvent; +import com.jogamp.newt.event.MouseListener; +import com.jogamp.newt.event.NEWTEvent; +import com.jogamp.newt.event.NEWTEventConsumer; +import com.jogamp.newt.event.ScreenModeListener; +import com.jogamp.newt.event.WindowEvent; +import com.jogamp.newt.event.WindowListener; +import com.jogamp.newt.event.WindowUpdateEvent; + +import java.util.ArrayList; +import java.lang.reflect.Method; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.Capabilities; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindow; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.SurfaceUpdatedListener; +import javax.media.nativewindow.util.DimensionReadOnly; +import javax.media.nativewindow.util.Insets; +import javax.media.nativewindow.util.Point; +import javax.media.nativewindow.util.Rectangle; + +public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenModeListener +{ + 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(NativeWindow parentWindow, long parentWindowHandle, Screen screen, Capabilities caps) { + try { + Class windowClass; + if(caps.isOnscreen()) { + windowClass = getWindowClass(screen.getDisplay().getType()); + } 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(Object[] cstrArguments, Screen screen, Capabilities caps) { + try { + Class windowClass = getWindowClass(screen.getDisplay().getType()); + 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.<br> + * Surface not locked yet.<br> + * Called not necessarily from EDT. + */ + void destroyActionPreLock(boolean unrecoverable); + + /** + * Invoked before Window destroy action, + * allows releasing of resources depending on the native Window.<br> + * Surface locked.<br> + * Called from EDT. + */ + void destroyActionInLock(boolean unrecoverable); + + /** + * Invoked for expensive modifications, ie while reparenting and ScreenMode change.<br> + * No lock is hold when invoked.<br> + * + * @see #resumeRenderingAction() + */ + void pauseRenderingAction(); + + /** + * Invoked for expensive modifications, ie while reparenting and ScreenMode change. + * No lock is hold when invoked.<br> + * + * @see #pauseRenderingAction() + */ + void resumeRenderingAction(); + } + + private LifecycleHook lifecycleHook = null; + private RecursiveLock windowLock = new RecursiveLock(); + 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, hasFocus; + protected int width, height, x, y; + protected int nfs_width, nfs_height, nfs_x, nfs_y; // non fullscreen dimensions .. + + protected String title = "Newt Window"; + protected boolean undecorated = false; + private boolean handleDestroyNotify = true; + + private final void destroyScreen() { + if(null!=screen) { + if(screenReferenced) { + screen.removeReference(); + screenReferenced = false; + } + screen = null; + } + } + private final void setScreen(ScreenImpl newScreen) { + if(screenReferenced) { + screenReferenced = false; + screen.removeReference(); + } + screen = newScreen; + } + + private boolean createNative() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.createNative() START ("+getThreadName()+", "+this+")"); + } + if( null != parentWindow && + NativeSurface.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, x, y, width, height); + screen.addScreenModeListener(this); + } + } 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 wasLocked = false; + if( NativeSurface.LOCK_SURFACE_NOT_READY < nativeWindow.lockSurface() ) { + wasLocked = true; + try { + 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 { + nativeWindow.unlockSurface(); + } + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.getNativeWindowHandle: locked "+wasLocked+", "+nativeWindow); + } + } + return handle; + } + + + //---------------------------------------------------------------------- + // NativeSurface: Native implementation + // + + protected int lockSurfaceImpl() { return LOCK_SUCCESS; } + + protected void unlockSurfaceImpl() { } + + //---------------------------------------------------------------------- + // Window: Native implementation + // + + /** + * The native implementation must set the native windowHandle.<br> + * + * The implementation should invoke the referenced java state callbacks + * to notify this Java object of state changes. + * + * @see #windowDestroyNotify() + * @see #focusChanged(boolean) + * @see #visibleChanged(boolean) + * @see #sizeChanged(int,int) + * @see #positionChanged(int,int) + * @see #windowDestroyNotify() + */ + protected abstract void createNativeImpl(); + + protected abstract void closeNativeImpl(); + + /** + * The native implementation must invoke {@link #focusChanged(boolean)} + * to change the focus state, if <code>force == false</code>. + * This may happen asynchronous within {@link #TIMEOUT_NATIVEWINDOW}. + * + * @param force if true, bypass {@link #focusChanged(boolean)} and force focus request + */ + protected abstract void requestFocusImpl(boolean force); + + /** + * The native implementation must invoke {@link #visibleChanged(boolean)} + * to change the visibility state. This may happen asynchronous within + * {@link #TIMEOUT_NATIVEWINDOW}. + */ + protected abstract void setVisibleImpl(boolean visible, int x, int y, int width, int height); + + /** + * The native implementation should invoke the referenced java state callbacks + * to notify this Java object of state changes. + * + * @param x -1 if no position change requested, otherwise greater than zero + * @param y -1 if no position change requested, otherwise greater than zero + * @param width -1 if no size change requested, otherwise greater than zero + * @param height -1 if no size change requested, otherwise greater than zero + * @param parentChange true if reparenting requested, otherwise false + * @param fullScreenChange 0 if unchanged, -1 fullscreen off, 1 fullscreen on + * @param decorationChange 0 if unchanged, -1 undecorated, 1 decorated + * + * @see #sizeChanged(int,int) + * @see #positionChanged(int,int) + */ + protected abstract boolean reconfigureWindowImpl(int x, int y, int width, int height, + boolean parentChange, int fullScreenChange, int decorationChange); + + protected void setTitleImpl(String title) {} + + /** + * Return screen coordinates of the given coordinates + * or null, in which case a NativeWindow traversal shall being used + * as demonstrated in {@link #getLocationOnScreen(javax.media.nativewindow.util.Point)}. + * + * @return if not null, the screen location of the given coordinates + */ + protected abstract Point getLocationOnScreenImpl(int x, int y); + + //---------------------------------------------------------------------- + // NativeSurface + // + + public final int lockSurface() { + int res = LOCK_SURFACE_NOT_READY; + + windowLock.lock(); + + AbstractGraphicsDevice adevice = screen.getDisplay().getGraphicsDevice(); + adevice.lock(); + try { + res = lockSurfaceImpl(); + } finally { + if(!isNativeValid()) { + adevice.unlock(); + windowLock.unlock(); + res = LOCK_SURFACE_NOT_READY; + } + } + + return res; + } + + public final void unlockSurface() { + // may throw RuntimeException if not locked + windowLock.validateLocked(); + + try { + unlockSurfaceImpl(); + } finally { + screen.getDisplay().getGraphicsDevice().unlock(); + } + windowLock.unlock(); + } + + public final boolean isSurfaceLockedByOtherThread() { + return windowLock.isLockedByOtherThread(); + } + + public final boolean isSurfaceLocked() { + return windowLock.isLocked(); + } + + public final Thread getSurfaceLockOwner() { + return windowLock.getOwner(); + } + + public long getSurfaceHandle() { + return windowHandle; // default: return window handle + } + + public boolean surfaceSwap() { + return false; + } + + public AbstractGraphicsConfiguration getGraphicsConfiguration() { + return config; + } + + public final long getDisplayHandle() { + return getScreen().getDisplay().getHandle(); + } + + public final int getScreenIndex() { + return getScreen().getIndex(); + } + + //---------------------------------------------------------------------- + // NativeWindow + // + + public final void destroy() { + destroy(false); + } + + public final NativeWindow getParent() { + return parentWindow; + } + + public final long getWindowHandle() { + return windowHandle; + } + + public Point getLocationOnScreen(Point storage) { + if(isNativeValid()) { + Point d; + windowLock.lock(); + try { + d = getLocationOnScreenImpl(0, 0); + } finally { + windowLock.unlock(); + } + if(null!=d) { + if(null!=storage) { + storage.translate(d.getX(),d.getY()); + return storage; + } + return d; + } + // fall through intended .. + } + + if(null!=storage) { + storage.translate(getX(),getY()); + } else { + storage = new Point(getX(),getY()); + } + if(null!=parentWindow) { + // traverse through parent list .. + parentWindow.getLocationOnScreen(storage); + } + return storage; + } + + //---------------------------------------------------------------------- + // Window + // + + public final boolean isNativeValid() { + return null != getScreen() && 0 != getWindowHandle() ; + } + + public final boolean isValid() { + return null != getScreen() ; + } + + public final Screen getScreen() { + return screen; + } + + 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(DEBUG_IMPLEMENTATION) { + String msg = new String("Window setVisible: START ("+getThreadName()+") "+x+"/"+y+" "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible: "+WindowImpl.this.visible+" -> "+visible+", parentWindowHandle "+toHexString(WindowImpl.this.parentWindowHandle)+", parentWindow "+(null!=WindowImpl.this.parentWindow)/*+", "+this*/); + System.err.println(msg); + } + if(!visible && childWindows.size()>0) { + synchronized(childWindowsLock) { + for(int i = 0; i < childWindows.size(); i++ ) { + NativeWindow nw = (NativeWindow) childWindows.get(i); + if(nw instanceof WindowImpl) { + ((WindowImpl)nw).setVisible(false); + } + } + } + } + if(0==windowHandle && visible) { + if( 0<width*height ) { + nativeWindowCreated = createNative(); + WindowImpl.this.waitForVisible(visible, true); + madeVisible = visible; + } + } else if(WindowImpl.this.visible != visible) { + if(0 != windowHandle) { + setVisibleImpl(visible, x, y, width, height); + WindowImpl.this.waitForVisible(visible, true); + madeVisible = visible; + } + } + + if(null!=lifecycleHook) { + lifecycleHook.setVisibleAction(visible, nativeWindowCreated); + } + + if(0!=windowHandle && visible && childWindows.size()>0) { + synchronized(childWindowsLock) { + for(int i = 0; i < childWindows.size(); i++ ) { + NativeWindow nw = (NativeWindow) childWindows.get(i); + 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(); + } + } + } + + public void setVisible(boolean visible) { + if(isValid()) { + if( 0==windowHandle && visible && 0>=width*height ) { + // fast-path: not realized yet, make visible, but zero size + return; + } + VisibleAction visibleAction = new VisibleAction(visible); + runOnEDTIfAvail(true, visibleAction); + if( visibleAction.getChanged() ) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + } + } + + class SetSizeActionImpl implements Runnable { + int visibleAction = 0; // 1 invisible, 2 visible (create) + int width, height; + + public int getVisibleAction() { + return visibleAction; + } + public SetSizeActionImpl(int w, int h) { + width = w; + height = h; + } + public void run() { + windowLock.lock(); + try { + if ( !fullscreen && ( width != WindowImpl.this.width || WindowImpl.this.height != height ) ) { + if(DEBUG_IMPLEMENTATION) { + String msg = new String("Window setSize: START "+WindowImpl.this.width+"x"+WindowImpl.this.height+" -> "+width+"x"+height+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)+", visible "+visible); + System.err.println(msg); + } + if ( 0 != windowHandle && 0>=width*height && visible ) { + visibleAction=1; // invisible + WindowImpl.this.width = 0; + WindowImpl.this.height = 0; + } else if ( 0 == windowHandle && 0<width*height && visible ) { + visibleAction = 2; // visible (create) + WindowImpl.this.width = width; + WindowImpl.this.height = height; + } else if ( 0 != windowHandle ) { + // this width/height will be set by windowChanged, called by the native implementation + reconfigureWindowImpl(x, y, width, height, false, 0, 0); + } else { + WindowImpl.this.width = width; + WindowImpl.this.height = height; + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setSize: END "+WindowImpl.this.width+"x"+WindowImpl.this.height+", visibleAction "+visibleAction); + } + } + } finally { + windowLock.unlock(); + } + } + } + + public void setSize(int width, int height) { + if(isValid()) { + SetSizeActionImpl setSizeAction = new SetSizeActionImpl(width, height); + runOnEDTIfAvail(true, setSizeAction); + switch(setSizeAction.getVisibleAction()) { + case 1: setVisible(false); break; + case 2: setVisible(true); break; + } + } + } + + 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.destroyActionInLock(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 ) { + screen.removeScreenModeListener(WindowImpl.this); + closeNativeImpl(); + } + invalidate(unrecoverable); + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.destroy(unrecoverable: "+unrecoverable+") END "+getThreadName()/*+", "+WindowImpl.this*/); + } + } finally { + windowLock.unlock(); + } + } + } + + 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(); + } + if(null!=lifecycleHook) { + lifecycleHook.destroyActionPreLock(unrecoverable); + } + DestroyAction destroyAction = new DestroyAction(unrecoverable); + runOnEDTIfAvail(true, destroyAction); + } + } + + /** + * <p> + * render all native window information invalid, + * as if the native window was destroyed.<br></p> + * <p> + * all other resources and states are kept intact, + * ie listeners, parent handles and size, position etc.<br></p> + * + * @see #destroy() + * @see #destroy(boolean) + * @see #invalidate(boolean) + */ + public final void invalidate() { + invalidate(false); + } + + /** + * @param unrecoverable If true, all states, size, position, parent handles, + * reference to it's Screen are reset. + * Otherwise you can recreate the window, via <code>setVisible(true)</code>. + * @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; + hasFocus = false; + + if(unrecoverable) { + destroyScreen(); + 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; + + // mirror pos/size so native change notification can get overwritten + int x = WindowImpl.this.x; + int y = WindowImpl.this.y; + int width = WindowImpl.this.width; + int height = WindowImpl.this.height; + + 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.hashCodeNullSafe(parentWindow)+", new parentWindow: "+Display.hashCodeNullSafe(newParentWindow)+", forceDestroyCreate "+forceDestroyCreate+", DEBUG_TEST_REPARENT_INCOMPATIBLE "+DEBUG_TEST_REPARENT_INCOMPATIBLE+" "+x+"/"+y+" "+width+"x"+height); + } + + if(null!=newParentWindow) { + // reset position to 0/0 within parent space + x = 0; + y = 0; + + // refit if size is bigger than parent + if( width > newParentWindow.getWidth() ) { + width = newParentWindow.getWidth(); + } + if( height > newParentWindow.getHeight() ) { + height = newParentWindow.getHeight(); + } + + // 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 != getParent()) { + // 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; + } + } + if( 0<width*height ) { + reparentAction = ACTION_NATIVE_CREATION; + } else { + reparentAction = ACTION_NATIVE_CREATION_PENDING; + } + } 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 { + if( null != parentWindow ) { + // child -> top + // put client to current parent+child position + Point p = getLocationOnScreen(null); + x = p.getX(); + y = p.getY(); + } + + // Case: Top Window + if( 0 == getParentWindowHandle() ) { + // Already Top Window + reparentAction = ACTION_UNCHANGED; + } else if( !isNativeValid() || DEBUG_TEST_REPARENT_INCOMPATIBLE || forceDestroyCreate ) { + // Destroy this window (handle screen + native), + // keep Screen/Display and mark it for creation. + destroy(false); + if( 0<width*height ) { + reparentAction = ACTION_NATIVE_CREATION; + } else { + reparentAction = ACTION_NATIVE_CREATION_PENDING; + } + } 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 ) { + DisplayImpl display = (DisplayImpl) screen.getDisplay(); + display.dispatchMessagesNative(); // status up2date + if(wasVisible) { + setVisibleImpl(false, x, y, width, height); + WindowImpl.this.waitForVisible(false, true); + } + + // Lock parentWindow only during reparenting (attempt) + NativeWindow parentWindowLocked = null; + if( null != parentWindow ) { + parentWindowLocked = parentWindow; + if( NativeSurface.LOCK_SURFACE_NOT_READY >= parentWindowLocked.lockSurface() ) { + throw new NativeWindowException("Parent surface lock: not ready: "+parentWindow); + } + } + boolean ok = false; + try { + // write back mirrored values, to be able to detect satisfaction + WindowImpl.this.x = x; + WindowImpl.this.y = y; + WindowImpl.this.width = width; + WindowImpl.this.height = height; + ok = reconfigureWindowImpl(x, y, width, height, true, 0, isUndecorated()?-1:1); + } finally { + if(null!=parentWindowLocked) { + parentWindowLocked.unlockSurface(); + } + } + + // set visible again, and revalidate 'ok', + // since it has been experience that in some cases the reparented window gets hidden + if(ok) { + display.dispatchMessagesNative(); // status up2date + if(wasVisible) { + setVisibleImpl(true, x, y, width, height); + ok = WindowImpl.this.waitForVisible(true, false); + display.dispatchMessagesNative(); // status up2date + if( ok && + ( WindowImpl.this.x != x || + WindowImpl.this.y != y || + WindowImpl.this.width != width || + WindowImpl.this.height != height ) ) + { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparent (reconfig)"); + } + // reset pos/size .. due to some native impl flakyness + reconfigureWindowImpl(x, y, width, height, false, 0, 0); + display.dispatchMessagesNative(); // status up2date + } + } + } + + if(ok) { + if(wasVisible) { + requestFocusImpl(true); + display.dispatchMessagesNative(); // status up2date + } + } else { + // 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 ; + } + } + + // write back mirrored values, ensuring persitence + // and not relying on native messaging + WindowImpl.this.x = x; + WindowImpl.this.y = y; + WindowImpl.this.width = width; + WindowImpl.this.height = height; + + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.reparentWindow: END ("+getThreadName()+") windowHandle "+toHexString(windowHandle)+", visible: "+visible+", parentWindowHandle "+toHexString(parentWindowHandle)+", parentWindow "+ Display.hashCodeNullSafe(parentWindow)+" "+x+"/"+y+" "+width+"x"+height); + } + } finally { + windowLock.unlock(); + } + + if( ACTION_NATIVE_CREATION == reparentAction && wasVisible ) { + // This may run on 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.hashCodeNullSafe(parentWindow)); + } + setVisible(true); // native creation + } 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) { + // pause animation + lifecycleHook.pauseRenderingAction(); + } + try { + ReparentActionImpl reparentAction = new ReparentActionImpl(newParent, forceDestroyCreate); + runOnEDTIfAvail(true, reparentAction); + reparentActionStrategy = reparentAction.getStrategy(); + } finally { + if(null!=lifecycleHook) { + // resume animation + lifecycleHook.resumeRenderingAction(); + } + } + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + 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); + } + } + + class DecorationActionImpl implements Runnable { + boolean undecorated; + + public DecorationActionImpl(boolean undecorated) { + this.undecorated = undecorated; + } + + public void run() { + windowLock.lock(); + try { + if(!fullscreen && isNativeValid() && WindowImpl.this.undecorated != undecorated) { + WindowImpl.this.undecorated = undecorated; + // mirror pos/size so native change notification can get overwritten + int x = WindowImpl.this.x; + int y = WindowImpl.this.y; + int width = WindowImpl.this.width; + int height = WindowImpl.this.height; + + if( 0 != windowHandle ) { + DisplayImpl display = (DisplayImpl) screen.getDisplay(); + display.dispatchMessagesNative(); // status up2date + boolean wasVisible = isVisible(); + setVisibleImpl(false, x, y, width, height); + WindowImpl.this.waitForVisible(false, true); + display.dispatchMessagesNative(); // status up2date + reconfigureWindowImpl(x, y, width, height, false, 0, undecorated?-1:1); + display.dispatchMessagesNative(); // status up2date + if(wasVisible) { + setVisibleImpl(true, x, y, width, height); + WindowImpl.this.waitForVisible(true, true); + display.dispatchMessagesNative(); // status up2date + if( WindowImpl.this.x != x || + WindowImpl.this.y != y || + WindowImpl.this.width != width || + WindowImpl.this.height != height ) + { + // reset pos/size .. due to some native impl flakyness + reconfigureWindowImpl(x, y, width, height, false, 0, 0); + display.dispatchMessagesNative(); // status up2date + } + requestFocusImpl(true); + display.dispatchMessagesNative(); // status up2date + } + } + } + } finally { + windowLock.unlock(); + } + } + } + + public void setUndecorated(boolean value) { + if(isValid()) { + DecorationActionImpl decorationAction = new DecorationActionImpl(value); + runOnEDTIfAvail(true, decorationAction); + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + } + + public boolean isUndecorated() { + return 0 != parentWindowHandle || undecorated || fullscreen ; + } + + public void requestFocus() { + enqueueRequestFocus(true); + } + + public boolean hasFocus() { + return hasFocus; + } + + 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.<br> + * 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 (int i = 0; i < surfaceUpdatedListeners.size(); i++ ) { + sb.append(surfaceUpdatedListeners.get(i)+", "); + } + sb.append("], WindowListeners num "+windowListeners.size()+" ["); + for (int i = 0; i < windowListeners.size(); i++ ) { + sb.append(windowListeners.get(i)+", "); + } + sb.append("], MouseListeners num "+mouseListeners.size()+" ["); + for (int i = 0; i < mouseListeners.size(); i++ ) { + sb.append(mouseListeners.get(i)+", "); + } + sb.append("], KeyListeners num "+keyListeners.size()+" ["); + for (int i = 0; i < keyListeners.size(); i++ ) { + sb.append(keyListeners.get(i)+", "); + } + 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() { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.RequestFocusAction: ("+getThreadName()+"): "+hasFocus+" -> true - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + } + WindowImpl.this.requestFocusImpl(false); + } + } + RequestFocusAction requestFocusAction = new RequestFocusAction(); + + protected 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(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; + + class SetPositionActionImpl implements Runnable { + int x, y; + + public SetPositionActionImpl(int x, int y) { + this.x = x; + this.y = y; + } + public void run() { + windowLock.lock(); + try { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window setPosition: "+WindowImpl.this.x+"/"+WindowImpl.this.y+" -> "+x+"/"+y+", fs "+fullscreen+", windowHandle "+toHexString(windowHandle)); + } + if ( WindowImpl.this.x != x || WindowImpl.this.y != y ) { + if(!fullscreen) { + if(0!=windowHandle) { + // this.x/this.y will be set by windowChanged, called by the native implementation + reconfigureWindowImpl(x, y, -1, -1, false, 0, 0); + } else { + WindowImpl.this.x = x; + WindowImpl.this.y = y; + } + } + } + } finally { + windowLock.unlock(); + } + } + } + + public void setPosition(int x, int y) { + if(isValid()) { + SetPositionActionImpl setPositionAction = new SetPositionActionImpl(x, y); + runOnEDTIfAvail(true, setPositionAction); + } + } + + class FullScreenActionImpl implements Runnable { + boolean fullscreen; + + public FullScreenActionImpl (boolean fullscreen) { + this.fullscreen = fullscreen; + } + + public void run() { + windowLock.lock(); + try { + if(isNativeValid() && WindowImpl.this.fullscreen != fullscreen) { + int x,y,w,h; + WindowImpl.this.fullscreen = fullscreen; + if(fullscreen) { + x = 0; y = 0; + w = screen.getWidth(); + h = screen.getHeight(); + nfs_width = width; + nfs_height = height; + nfs_x = x; + nfs_y = y; + } else { + x = nfs_x; + y = nfs_y; + w = nfs_width; + h = nfs_height; + } + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()+", "+screen); + } + + DisplayImpl display = (DisplayImpl) screen.getDisplay(); + display.dispatchMessagesNative(); // status up2date + boolean wasVisible = isVisible(); + setVisibleImpl(false, x, y, width, height); + WindowImpl.this.waitForVisible(false, true); + display.dispatchMessagesNative(); // status up2date + + // write back mirrored values, to be able to detect satisfaction + WindowImpl.this.x = x; + WindowImpl.this.y = y; + WindowImpl.this.width = w; + WindowImpl.this.height = h; + reconfigureWindowImpl(x, y, w, h, getParentWindowHandle()!=0, fullscreen?1:-1, isUndecorated()?-1:1); + display.dispatchMessagesNative(); // status up2date + + if(wasVisible) { + setVisibleImpl(true, x, y, width, height); + boolean ok = WindowImpl.this.waitForVisible(true, true, Screen.SCREEN_MODE_CHANGE_TIMEOUT); + display.dispatchMessagesNative(); // status up2date + if( ok && + ( WindowImpl.this.x != x || + WindowImpl.this.y != y || + WindowImpl.this.width != w || + WindowImpl.this.height != h ) ) + { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("Window fs (reconfig): "+x+"/"+y+" "+w+"x"+h+", "+screen); + } + // reset pos/size .. due to some native impl flakyness + reconfigureWindowImpl(x, y, width, height, false, 0, 0); + display.dispatchMessagesNative(); // status up2date + } + requestFocusImpl(true); + display.dispatchMessagesNative(); // status up2date + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("Window fs done"); + } + } + } + } finally { + windowLock.unlock(); + } + } + } + + public boolean setFullscreen(boolean fullscreen) { + if(isValid()) { + FullScreenActionImpl fullScreenAction = new FullScreenActionImpl(fullscreen); + runOnEDTIfAvail(true, fullScreenAction); + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + return this.fullscreen; + } + + public void screenModeChangeNotify(ScreenMode sm) { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("Window.screenModeChangeNotify: "+sm); + } + + if(null!=lifecycleHook) { + // pause animation + lifecycleHook.pauseRenderingAction(); + } + } + + public void screenModeChanged(ScreenMode sm, boolean success) { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("Window.screenModeChanged: "+sm+", success: "+success); + } + + if(success) { + DimensionReadOnly screenSize = sm.getMonitorMode().getSurfaceSize().getResolution(); + if ( getHeight() > screenSize.getHeight() || + getWidth() > screenSize.getWidth() ) { + setSize(screenSize.getWidth(), screenSize.getHeight()); + } + } + + if(null!=lifecycleHook) { + // resume animation + lifecycleHook.resumeRenderingAction(); + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener + } + } + + //---------------------------------------------------------------------- + // 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, NativeSurface ns, long when) { + synchronized(surfaceUpdatedListenersLock) { + for(int i = 0; i < surfaceUpdatedListeners.size(); i++ ) { + SurfaceUpdatedListener l = (SurfaceUpdatedListener) surfaceUpdatedListeners.get(i); + l.surfaceUpdated(updater, ns, 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 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-lastMousePressed<MouseEvent.getClickTimeout()) { + lastMouseClickCount++; + } else { + lastMouseClickCount=1; + } + lastMousePressed=when; + mouseButtonPressed=button; + e = new MouseEvent(eventType, this, when, + modifiers, x, y, lastMouseClickCount, button, 0); + } else if(MouseEvent.EVENT_MOUSE_RELEASED==eventType) { + e = new MouseEvent(eventType, this, when, + modifiers, x, y, lastMouseClickCount, button, 0); + if(when-lastMousePressed<MouseEvent.getClickTimeout()) { + eClicked = new MouseEvent(MouseEvent.EVENT_MOUSE_CLICKED, this, when, + modifiers, x, y, lastMouseClickCount, button, 0); + } else { + lastMouseClickCount=0; + lastMousePressed=0; + } + mouseButtonPressed=0; + } else if(MouseEvent.EVENT_MOUSE_MOVED==eventType) { + if (mouseButtonPressed>0) { + 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(int i = 0; i < mouseListeners.size(); i++ ) { + MouseListener l = (MouseListener) mouseListeners.get(i); + 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(int i = 0; i < keyListeners.size(); i++ ) { + KeyListener l = (KeyListener) keyListeners.get(i); + 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+", visible "+isVisible()+" "+getX()+"/"+getY()+" "+getWidth()+"x"+getHeight()); + } + for(int i = 0; i < windowListeners.size(); i++ ) { + WindowListener l = (WindowListener) windowListeners.get(i); + 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()+"): "+this.hasFocus+" -> "+focusGained+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + } + hasFocus = 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)); + } + this.visible = visible ; + } + + private boolean waitForVisible(boolean visible, boolean failFast) { + return waitForVisible(visible, failFast, TIMEOUT_NATIVEWINDOW); + } + + private boolean waitForVisible(boolean visible, boolean failFast, long timeOut) { + DisplayImpl display = (DisplayImpl) screen.getDisplay(); + for(long sleep = timeOut; 0<sleep && this.visible != visible; sleep-=10 ) { + display.dispatchMessagesNative(); // status up2date + try { + Thread.sleep(10); + } catch (InterruptedException ie) {} + sleep -=10; + } + if(this.visible != visible) { + if(failFast) { + throw new NativeWindowException("Visibility not reached as requested within "+timeOut+"ms : requested "+visible+", is "+this.visible); + } else if (DEBUG_IMPLEMENTATION) { + System.err.println("******* Visibility not reached as requested within "+timeOut+"ms : requested "+visible+", is "+this.visible); + } + } + return this.visible == visible; + } + + protected void sizeChanged(int newWidth, int newHeight, boolean force) { + if(force || width != newWidth || height != newHeight) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.sizeChanged: ("+getThreadName()+"): force "+force+", "+width+"x"+height+" -> "+newWidth+"x"+newHeight+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + } + width = newWidth; + height = newHeight; + if(isNativeValid()) { + sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); + } + } + } + + protected void positionChanged(int newX, int newY) { + if( 0==parentWindowHandle && ( x != newX || y != newY ) ) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.positionChanged: ("+getThreadName()+"): "+x+"/"+y+" -> "+newX+"/"+newY+" - windowHandle "+toHexString(windowHandle)+" parentWindowHandle "+toHexString(parentWindowHandle)); + } + x = newX; + y = newY; + 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); + // Exception ee = new Exception("Window.windowRepaint: "+" - "+x+"/"+y+" "+width+"x"+height); + // ee.printStackTrace(); + } + + if(isNativeValid()) { + 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 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<args.length; i++) { + if(!types[i].isInstance(args[i])) { + return i; + } + } + return args.length; + } + + private static String getArgsStrList(Object[] args) { + StringBuffer sb = new StringBuffer(); + for(int i=0; i<args.length; i++) { + sb.append(args[i].getClass()); + if(i<args.length) { + sb.append(", "); + } + } + return sb.toString(); + } + + private static String getTypeStrList(Class[] types) { + StringBuffer sb = new StringBuffer(); + for(int i=0; i<types.length; i++) { + sb.append(types[i]); + if(i<types.length) { + sb.append(", "); + } + } + return sb.toString(); + } + + protected final void shouldNotCallThis() { + throw new NativeWindowException("Should not call this"); + } + + public static String getThreadName() { + return Display.getThreadName(); + } + + public static String toHexString(int hex) { + return Display.toHexString(hex); + } + + public static String toHexString(long hex) { + return Display.toHexString(hex); + } +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTCanvas.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTCanvas.java new file mode 100644 index 000000000..9b0ec6907 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTCanvas.java @@ -0,0 +1,284 @@ +/* + * 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.impl.awt; + +import com.jogamp.newt.Window; + +import java.awt.Canvas; +import java.awt.GraphicsDevice; +import java.awt.GraphicsConfiguration; + +import javax.media.nativewindow.*; +import javax.media.nativewindow.awt.*; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedAction; + +public class AWTCanvas extends Canvas { + private GraphicsDevice device; + private GraphicsConfiguration chosen; + private AWTGraphicsConfiguration awtConfig; + + private Capabilities capabilities; + + private boolean displayConfigChanged=false; + + public AWTCanvas(Capabilities capabilities) { + super(); + + if(null==capabilities) { + throw new NativeWindowException("Capabilities null"); + } + this.capabilities=capabilities; + } + + public AWTGraphicsConfiguration getAWTGraphicsConfiguration() { + return awtConfig; + } + + public boolean hasDeviceChanged() { + boolean res = displayConfigChanged; + displayConfigChanged=false; + return res; + } + + public void addNotify() { + super.addNotify(); + + disableBackgroundErase(); + + GraphicsConfiguration gc = super.getGraphicsConfiguration(); + if(null!=gc) { + device = gc.getDevice(); + } + + /* + * Save the chosen capabilities for use in getGraphicsConfiguration(). + */ + awtConfig = chooseGraphicsConfiguration(capabilities, device); + if(Window.DEBUG_IMPLEMENTATION) { + Exception e = new Exception("Info: Created Config: "+awtConfig); + e.printStackTrace(); + } + if(null!=awtConfig) { + // update .. + chosen = awtConfig.getGraphicsConfiguration(); + } + if(null==awtConfig) { + throw new NativeWindowException("Error: AWTGraphicsConfiguration is null"); + } + } + + public void removeNotify() { + try { + dispose(); + } finally { + super.removeNotify(); + } + } + + private void dispose() { + if(null != awtConfig) { + AbstractGraphicsDevice adevice = awtConfig.getNativeGraphicsConfiguration().getScreen().getDevice(); + String adeviceMsg=null; + if(Window.DEBUG_IMPLEMENTATION) { + adeviceMsg = adevice.toString(); + } + boolean closed = adevice.close(); + if(Window.DEBUG_IMPLEMENTATION) { + System.err.println("AWTCanvas.dispose(): closed GraphicsDevice: "+adeviceMsg+", result: "+closed); + } + } + } + + /** + * Overridden to choose a GraphicsConfiguration on a parent container's + * GraphicsDevice because both devices + */ + public GraphicsConfiguration getGraphicsConfiguration() { + /* + * Workaround for problems with Xinerama and java.awt.Component.checkGD + * when adding to a container on a different graphics device than the + * one that this Canvas is associated with. + * + * GC will be null unless: + * - A native peer has assigned it. This means we have a native + * peer, and are already comitted to a graphics configuration. + * - This canvas has been added to a component hierarchy and has + * an ancestor with a non-null GC, but the native peer has not + * yet been created. This means we can still choose the GC on + * all platforms since the peer hasn't been created. + */ + final GraphicsConfiguration gc = super.getGraphicsConfiguration(); + /* + * chosen is only non-null on platforms where the GLDrawableFactory + * returns a non-null GraphicsConfiguration (in the GLCanvas + * constructor). + * + * if gc is from this Canvas' native peer then it should equal chosen, + * otherwise it is from an ancestor component that this Canvas is being + * added to, and we go into this block. + */ + if (gc != null && chosen != null && !chosen.equals(gc)) { + /* + * Check for compatibility with gc. If they differ by only the + * device then return a new GCconfig with the super-class' GDevice + * (and presumably the same visual ID in Xinerama). + * + */ + if (!chosen.getDevice().getIDstring().equals(gc.getDevice().getIDstring())) { + /* + * Here we select a GraphicsConfiguration on the alternate + * device that is presumably identical to the chosen + * configuration, but on the other device. + * + * Should really check to ensure that we select a configuration + * with the same X visual ID for Xinerama screens, otherwise the + * GLDrawable may have the wrong visual ID (I don't think this + * ever gets updated). May need to add a method to + * X11GLDrawableFactory to do this in a platform specific + * manner. + * + * However, on platforms where we can actually get into this + * block, both devices should have the same visual list, and the + * same configuration should be selected here. + */ + AWTGraphicsConfiguration config = chooseGraphicsConfiguration((Capabilities)awtConfig.getRequestedCapabilities(), gc.getDevice()); + final GraphicsConfiguration compatible = (null!=config)?config.getGraphicsConfiguration():null; + if(Window.DEBUG_IMPLEMENTATION) { + Exception e = new Exception("Info: Call Stack: "+Thread.currentThread().getName()); + e.printStackTrace(); + System.err.println("!!! Created Config (n): HAVE GC "+chosen); + System.err.println("!!! Created Config (n): THIS GC "+gc); + System.err.println("!!! Created Config (n): Choosen GC "+compatible); + System.err.println("!!! Created Config (n): HAVE CF "+awtConfig); + System.err.println("!!! Created Config (n): Choosen CF "+config); + System.err.println("!!! Created Config (n): EQUALS CAPS "+config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities())); + } + + if (compatible != null) { + /* + * Save the new GC for equals test above, and to return to + * any outside callers of this method. + */ + chosen = compatible; + if( !config.getChosenCapabilities().equals(awtConfig.getChosenCapabilities())) { + displayConfigChanged=true; + } + awtConfig = config; + } + } + + /* + * If a compatible GC was not found in the block above, this will + * return the GC that was selected in the constructor (and might + * cause an exception in Component.checkGD when adding to a + * container, but in this case that would be the desired behavior). + * + */ + return chosen; + } else if (gc == null) { + /* + * The GC is null, which means we have no native peer, and are not + * part of a (realized) component hierarchy. So we return the + * desired visual that was selected in the constructor (possibly + * null). + */ + return chosen; + } + + /* + * Otherwise we have not explicitly selected a GC in the constructor, so + * just return what Canvas would have. + */ + return gc; + } + + private static AWTGraphicsConfiguration chooseGraphicsConfiguration(Capabilities capabilities, + GraphicsDevice device) { + AbstractGraphicsScreen aScreen = AWTGraphicsScreen.createScreenDevice(device); + AWTGraphicsConfiguration config = (AWTGraphicsConfiguration) + GraphicsConfigurationFactory.getFactory(AWTGraphicsDevice.class).chooseGraphicsConfiguration(capabilities, + null, + aScreen); + if (config == null) { + throw new NativeWindowException("Error: Couldn't fetch AWTGraphicsConfiguration"); + } + + return config; + } + + // Disables the AWT's erasing of this Canvas's background on Windows + // in Java SE 6. This internal API is not available in previous + // releases, but the system property + // -Dsun.awt.noerasebackground=true can be specified to get similar + // results globally in previous releases. + private static boolean disableBackgroundEraseInitialized; + private static Method disableBackgroundEraseMethod; + private void disableBackgroundErase() { + if (!disableBackgroundEraseInitialized) { + try { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + Class clazz = getToolkit().getClass(); + while (clazz != null && disableBackgroundEraseMethod == null) { + try { + disableBackgroundEraseMethod = + clazz.getDeclaredMethod("disableBackgroundErase", + new Class[] { Canvas.class }); + disableBackgroundEraseMethod.setAccessible(true); + } catch (Exception e) { + clazz = clazz.getSuperclass(); + } + } + } catch (Exception e) { + } + return null; + } + }); + } catch (Exception e) { + } + disableBackgroundEraseInitialized = true; + } + if (disableBackgroundEraseMethod != null) { + try { + disableBackgroundEraseMethod.invoke(getToolkit(), new Object[] { this }); + } catch (Exception e) { + // FIXME: workaround for 6504460 (incorrect backport of 6333613 in 5.0u10) + // throw new GLException(e); + } + } + } +} diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTDisplay.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTDisplay.java new file mode 100644 index 000000000..0199d6c72 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTDisplay.java @@ -0,0 +1,63 @@ +/* + * 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.impl.awt; + +import java.awt.event.*; +import com.jogamp.newt.Display; +import com.jogamp.newt.Window; +import com.jogamp.newt.impl.DisplayImpl; +import javax.media.nativewindow.*; +import javax.media.nativewindow.awt.*; +import java.util.*; + +public class AWTDisplay extends DisplayImpl { + public AWTDisplay() { + } + + protected void createNativeImpl() { + aDevice = (AWTGraphicsDevice) AWTGraphicsDevice.createDevice(null); // default + } + + protected void setAWTGraphicsDevice(AWTGraphicsDevice d) { + aDevice = d; + } + + protected void closeNativeImpl() { } + + protected boolean shallRunOnEDT() { + return false; + } + protected void dispatchMessagesNative() { /* nop */ } +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java new file mode 100644 index 000000000..5e097fdc3 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java @@ -0,0 +1,65 @@ +/* + * 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.impl.awt; + +import com.jogamp.newt.*; +import com.jogamp.newt.impl.ScreenImpl; +import java.awt.DisplayMode; +import javax.media.nativewindow.*; +import javax.media.nativewindow.awt.*; + +public class AWTScreen extends ScreenImpl { + public AWTScreen() { + } + + protected void createNativeImpl() { + aScreen = new AWTGraphicsScreen((AWTGraphicsDevice)display.getGraphicsDevice()); + + DisplayMode mode = ((AWTGraphicsDevice)getDisplay().getGraphicsDevice()).getGraphicsDevice().getDisplayMode(); + int w = mode.getWidth(); + int h = mode.getHeight(); + setScreenSize(w, h); + } + + protected void setAWTGraphicsScreen(AWTGraphicsScreen s) { + aScreen = s; + } + + // done by AWTWindow .. + protected void setScreenSize(int w, int h) { + super.setScreenSize(w, h); + } + + protected void closeNativeImpl() { } +} diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java new file mode 100644 index 000000000..edd851451 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTWindow.java @@ -0,0 +1,289 @@ +/* + * 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.awt; + +import com.jogamp.newt.event.awt.*; +import com.jogamp.newt.util.EDTUtil; + +import java.awt.BorderLayout; +import java.awt.Container; +import java.awt.DisplayMode; +import java.awt.EventQueue; +import java.awt.Frame; +import com.jogamp.newt.impl.WindowImpl; +import java.awt.Insets; +import javax.media.nativewindow.*; +import javax.media.nativewindow.awt.*; +import javax.media.nativewindow.util.Point; + +/** An implementation of the Newt Window class built using the + AWT. This is provided for convenience of porting to platforms + supporting Java SE. */ + +public class AWTWindow extends WindowImpl { + + public AWTWindow() { + this(null); + } + + public static Class[] getCustomConstructorArgumentTypes() { + return new Class[] { Container.class } ; + } + + public AWTWindow(Container container) { + super(); + title = "AWT NewtWindow"; + this.container = container; + if(container instanceof Frame) { + frame = (Frame) container; + } + } + + private boolean owningFrame; + private Container container = null; + private Frame frame = null; // same instance as container, just for impl. convenience + private AWTCanvas canvas; + + protected void requestFocusImpl(boolean reparented) { + runOnEDT(true, new Runnable() { + public void run() { + container.requestFocus(); + } + }); + } + + protected void setTitleImpl(final String title) { + runOnEDT(true, new Runnable() { + public void run() { + if (frame != null) { + frame.setTitle(title); + } + } + }); + } + + protected void createNativeImpl() { + + if(0!=getParentWindowHandle()) { + throw new RuntimeException("Window parenting not supported in AWT, use AWTWindow(Frame) cstr for wrapping instead"); + } + + final AWTWindow awtWindow = this; + + runOnEDT(true, new Runnable() { + public void run() { + if(null==container) { + frame = new Frame(); + container = frame; + owningFrame=true; + } else { + owningFrame=false; + width = container.getWidth(); + height = container.getHeight(); + x = container.getX(); + y = container.getY(); + } + if(null!=frame) { + frame.setTitle(getTitle()); + } + container.setLayout(new BorderLayout()); + canvas = new AWTCanvas(caps); + + addWindowListener(new LocalWindowListener()); + + new AWTMouseAdapter(awtWindow).addTo(canvas); // fwd all AWT Mouse events to here + new AWTKeyAdapter(awtWindow).addTo(canvas); // fwd all AWT Key events to here + + // canvas.addComponentListener(listener); + container.add(canvas, BorderLayout.CENTER); + container.setSize(width, height); + container.setLocation(x, y); + new AWTWindowAdapter(awtWindow).addTo(container); // fwd all AWT Window events to here + + if(null!=frame) { + frame.setUndecorated(undecorated||fullscreen); + } + } + }); + setWindowHandle(1); // just a marker .. + } + + protected void closeNativeImpl() { + setWindowHandle(0); // just a marker .. + if(null!=container) { + runOnEDT(true, new Runnable() { + public void run() { + container.setVisible(false); + container.remove(canvas); + container.setEnabled(false); + canvas.setEnabled(false); + } + }); + } + if(owningFrame && null!=frame) { + runOnEDT(true, new Runnable() { + public void run() { + frame.dispose(); + owningFrame=false; + frame = null; + } + }); + } + } + + public boolean hasDeviceChanged() { + boolean res = canvas.hasDeviceChanged(); + if(res) { + config = canvas.getAWTGraphicsConfiguration(); + if (config == null) { + throw new NativeWindowException("Error Device change null GraphicsConfiguration: "+this); + } + updateDeviceData(); + } + return res; + } + + protected void setVisibleImpl(final boolean visible, int x, int y, int width, int height) { + runOnEDT(true, new Runnable() { + public void run() { + container.setVisible(visible); + } + }); + + reconfigureWindowImpl(x, y, width, height, false, 0, 0); + config = canvas.getAWTGraphicsConfiguration(); + + if (config == null) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + + updateDeviceData(); + visibleChanged(visible); + } + + private void updateDeviceData() { + // propagate new info .. + ((AWTScreen)getScreen()).setAWTGraphicsScreen((AWTGraphicsScreen)config.getScreen()); + ((AWTDisplay)getScreen().getDisplay()).setAWTGraphicsDevice((AWTGraphicsDevice)config.getScreen().getDevice()); + + DisplayMode mode = ((AWTGraphicsDevice)config.getScreen().getDevice()).getGraphicsDevice().getDisplayMode(); + int w = mode.getWidth(); + int h = mode.getHeight(); + ((AWTScreen)getScreen()).setScreenSize(w, h); + } + + public javax.media.nativewindow.util.Insets getInsets() { + final int insets[] = new int[] { 0, 0, 0, 0 }; + runOnEDT(true, new Runnable() { + public void run() { + Insets contInsets = container.getInsets(); + insets[0] = contInsets.top; + insets[1] = contInsets.left; + insets[2] = contInsets.bottom; + insets[3] = contInsets.right; + } + }); + return new javax.media.nativewindow.util.Insets(insets[0],insets[1],insets[2],insets[3]); + } + + protected boolean reconfigureWindowImpl(final int x, final int y, final int width, final int height, final boolean parentChange, final int fullScreenChange, final int decorationChange) { + /** An AWT event on setSize() would bring us in a deadlock situation, hence invokeLater() */ + runOnEDT(false, new Runnable() { + public void run() { + if(decorationChange!=0 && null!=frame) { + if(!container.isDisplayable()) { + frame.setUndecorated(isUndecorated()); + } else { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("AWTWindow can't undecorate already created frame"); + } + } + } + int _x=(x>=0)?x:AWTWindow.this.x; + int _y=(x>=0)?y:AWTWindow.this.y; + int _w=(width>0)?width:AWTWindow.this.width; + int _h=(height>0)?height:AWTWindow.this.height; + + container.setLocation(_x, _y); + Insets insets = container.getInsets(); + container.setSize(_w + insets.left + insets.right, + _h + insets.top + insets.bottom); + } + }); + return true; + } + + protected Point getLocationOnScreenImpl(int x, int y) { + java.awt.Point ap = canvas.getLocationOnScreen(); + ap.translate(x, y); + return new Point((int)(ap.getX()+0.5),(int)(ap.getY()+0.5)); + } + + public Object getWrappedWindow() { + return canvas; + } + + private void runOnEDT(boolean wait, Runnable r) { + EDTUtil edtUtil = getScreen().getDisplay().getEDTUtil(); + if ( ( null != edtUtil && edtUtil.isCurrentThreadEDT() ) || EventQueue.isDispatchThread() ) { + r.run(); + } else { + try { + if(wait) { + EventQueue.invokeAndWait(r); + } else { + EventQueue.invokeLater(r); + } + } catch (Exception e) { + throw new NativeWindowException(e); + } + } + } + + class LocalWindowListener extends com.jogamp.newt.event.WindowAdapter { + public void windowMoved(com.jogamp.newt.event.WindowEvent e) { + if(null!=container) { + x = container.getX(); + y = container.getY(); + } + } + public void windowResized(com.jogamp.newt.event.WindowEvent e) { + if(null!=canvas) { + width = canvas.getWidth(); + height = canvas.getHeight(); + } + } + } +} diff --git a/src/newt/classes/com/jogamp/newt/impl/event/NEWTEventTask.java b/src/newt/classes/com/jogamp/newt/impl/event/NEWTEventTask.java new file mode 100644 index 000000000..1b4bce4b0 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/event/NEWTEventTask.java @@ -0,0 +1,56 @@ +/** + * 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.impl.event; + +import com.jogamp.newt.event.NEWTEvent; + +/** + * Helper class to provide a NEWTEvent queue implementation with a NEWTEvent wrapper + * which notifies after sending the event for the <code>invokeAndWait()</code> semantics. + */ +public class NEWTEventTask { + NEWTEvent event; + Object notifyObject; + + public NEWTEventTask(NEWTEvent event, Object notifyObject) { + this.event = event ; + this.notifyObject = notifyObject ; + } + + public NEWTEvent get() { return event; } + + public void notifyIssuer() { + if(null != notifyObject) { + synchronized (notifyObject) { + notifyObject.notifyAll(); + } + } + } +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Display.java b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Display.java new file mode 100644 index 000000000..0bd4c3b5d --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Display.java @@ -0,0 +1,104 @@ +/* + * 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.impl.intel.gdl; + +import com.jogamp.newt.impl.*; +import javax.media.nativewindow.*; + +public class Display extends com.jogamp.newt.impl.DisplayImpl { + static int initCounter = 0; + + static { + NEWTJNILibLoader.loadNEWT(); + + if (!Screen.initIDs()) { + throw new NativeWindowException("Failed to initialize GDL Screen jmethodIDs"); + } + if (!Window.initIDs()) { + throw new NativeWindowException("Failed to initialize GDL Window jmethodIDs"); + } + } + + public static void initSingleton() { + // just exist to ensure static init has been run + } + + + public Display() { + } + + protected void createNativeImpl() { + synchronized(Display.class) { + if(0==initCounter) { + displayHandle = CreateDisplay(); + if(0==displayHandle) { + throw new NativeWindowException("Couldn't initialize GDL Display"); + } + } + initCounter++; + } + aDevice = new DefaultGraphicsDevice(NativeWindowFactory.TYPE_DEFAULT, displayHandle); + } + + protected void closeNativeImpl() { + if(0==displayHandle) { + throw new NativeWindowException("displayHandle null; initCnt "+initCounter); + } + synchronized(Display.class) { + if(initCounter>0) { + initCounter--; + if(0==initCounter) { + DestroyDisplay(displayHandle); + } + } + } + } + + protected void dispatchMessagesNative() { + if(0!=displayHandle) { + DispatchMessages(displayHandle, focusedWindow); + } + } + + protected void setFocus(Window focus) { + focusedWindow = focus; + } + + private long displayHandle = 0; + private Window focusedWindow = null; + private native long CreateDisplay(); + private native void DestroyDisplay(long displayHandle); + private native void DispatchMessages(long displayHandle, Window focusedWindow); +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java new file mode 100644 index 000000000..4abee350f --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java @@ -0,0 +1,68 @@ +/* + * 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.impl.intel.gdl; + +import com.jogamp.newt.impl.*; +import javax.media.nativewindow.*; + +public class Screen extends com.jogamp.newt.impl.ScreenImpl { + + static { + Display.initSingleton(); + } + + public Screen() { + } + + protected void createNativeImpl() { + AbstractGraphicsDevice adevice = getDisplay().getGraphicsDevice(); + GetScreenInfo(adevice.getHandle(), screen_idx); + aScreen = new DefaultGraphicsScreen(adevice, screen_idx); + } + + protected void closeNativeImpl() { } + + //---------------------------------------------------------------------- + // Internals only + // + + protected static native boolean initIDs(); + private native void GetScreenInfo(long displayHandle, int screen_idx); + + // called by GetScreenInfo() .. + private void screenCreated(int width, int height) { + setScreenSize(width, height); + } +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java new file mode 100644 index 000000000..749be8506 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Window.java @@ -0,0 +1,146 @@ +/* + * 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.impl.intel.gdl; + +import javax.media.nativewindow.*; +import javax.media.nativewindow.util.Point; + +public class Window extends com.jogamp.newt.impl.WindowImpl { + static { + Display.initSingleton(); + } + + public Window() { + } + + static long nextWindowHandle = 1; + + protected void createNativeImpl() { + if(0!=getParentWindowHandle()) { + throw new NativeWindowException("GDL Window does not support window parenting"); + } + AbstractGraphicsScreen aScreen = getScreen().getGraphicsScreen(); + AbstractGraphicsDevice aDevice = getScreen().getDisplay().getGraphicsDevice(); + + config = GraphicsConfigurationFactory.getFactory(aDevice).chooseGraphicsConfiguration(caps, null, aScreen); + if (config == null) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + + synchronized(Window.class) { + setWindowHandle(nextWindowHandle++); // just a marker + + surfaceHandle = CreateSurface(aDevice.getHandle(), getScreen().getWidth(), getScreen().getHeight(), x, y, width, height); + if (surfaceHandle == 0) { + throw new NativeWindowException("Error creating window"); + } + } + } + + protected void closeNativeImpl() { + if(0!=surfaceHandle) { + synchronized(Window.class) { + CloseSurface(getDisplayHandle(), surfaceHandle); + } + surfaceHandle = 0; + ((Display)getScreen().getDisplay()).setFocus(null); + } + } + + protected void setVisibleImpl(boolean visible, int x, int y, int width, int height) { + reconfigureWindowImpl(x, y, width, height, false, 0, 0); + if(visible) { + ((Display)getScreen().getDisplay()).setFocus(this); + } + this.visibleChanged(visible); + } + + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, boolean parentChange, int fullScreenChange, int decorationChange) { + Screen screen = (Screen) getScreen(); + + int _x=(x>=0)?x:this.x; + int _y=(x>=0)?y:this.y; + int _w=(width>0)?width:this.width; + int _h=(height>0)?height:this.height; + + if(_w>screen.getWidth()) { + _w=screen.getWidth(); + } + if(_h>screen.getHeight()) { + _h=screen.getHeight(); + } + if((_x+_w)>screen.getWidth()) { + _x=screen.getWidth()-_w; + } + if((_y+_h)>screen.getHeight()) { + _y=screen.getHeight()-_h; + } + + if(0!=surfaceHandle) { + SetBounds0(surfaceHandle, getScreen().getWidth(), getScreen().getHeight(), _x, _y, _w, _h); + } + + return true; + } + + protected void requestFocusImpl(boolean reparented) { + ((Display)getScreen().getDisplay()).setFocus(this); + } + + public final long getSurfaceHandle() { + return surfaceHandle; + } + + protected Point getLocationOnScreenImpl(int x, int y) { + return new Point(x,y); + } + + //---------------------------------------------------------------------- + // Internals only + // + + protected static native boolean initIDs(); + private native long CreateSurface(long displayHandle, int scrn_width, int scrn_height, int x, int y, int width, int height); + private native void CloseSurface(long displayHandle, long surfaceHandle); + private native void SetBounds0(long surfaceHandle, int scrn_width, int scrn_height, int x, int y, int width, int height); + + private void updateBounds(int x, int y, int width, int height) { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + private long surfaceHandle; +} diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java new file mode 100644 index 000000000..dc45f7479 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacDisplay.java @@ -0,0 +1,101 @@ +/* + * 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.impl.macosx; + +import javax.media.nativewindow.*; +import javax.media.nativewindow.macosx.*; +import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.newt.*; +import com.jogamp.newt.impl.*; +import com.jogamp.newt.util.EDTUtil; +import com.jogamp.newt.util.MainThread; + +public class MacDisplay extends DisplayImpl { + static { + NEWTJNILibLoader.loadNEWT(); + + if(!initNSApplication0()) { + throw new NativeWindowException("Failed to initialize native Application hook"); + } + if(!MacWindow.initIDs0()) { + throw new NativeWindowException("Failed to initialize jmethodIDs"); + } + if(DEBUG) { + System.err.println("MacDisplay.init App and IDs OK "+Thread.currentThread().getName()); + } + } + + public static void initSingleton() { + // just exist to ensure static init has been run + } + + public MacDisplay() { + } + + protected void dispatchMessagesNative() { + dispatchMessages0(); + } + + protected void createNativeImpl() { + aDevice = new MacOSXGraphicsDevice(); + } + + protected void closeNativeImpl() { } + + protected void createEDTUtil() { + if(NewtFactory.useEDT()) { + final Display f_dpy = this; + MainThread.addPumpMessage(this, + new Runnable() { + public void run() { + if(null!=f_dpy.getGraphicsDevice()) { + f_dpy.dispatchMessages(); + } } } ); + edtUtil = MainThread.getSingleton(); + edtUtil.start(); + } + } + + protected void releaseEDTUtil() { + if(null!=edtUtil) { + MainThread.removePumpMessage(this); + edtUtil.waitUntilStopped(); + edtUtil=null; + } + } + + private static native boolean initNSApplication0(); + protected native void dispatchMessages0(); +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java new file mode 100644 index 000000000..f0c388366 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java @@ -0,0 +1,57 @@ +/* + * 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.impl.macosx; + +import com.jogamp.newt.*; +import com.jogamp.newt.impl.ScreenImpl; +import javax.media.nativewindow.*; + +public class MacScreen extends ScreenImpl { + static { + MacDisplay.initSingleton(); + } + + public MacScreen() { + } + + protected void createNativeImpl() { + aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); + setScreenSize(getWidthImpl0(screen_idx), getHeightImpl0(screen_idx)); + } + + protected void closeNativeImpl() { } + + private static native int getWidthImpl0(int scrn_idx); + private static native int getHeightImpl0(int scrn_idx); +} diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java new file mode 100644 index 000000000..59b41c2aa --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacWindow.java @@ -0,0 +1,433 @@ +/* + * 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.macosx; + +import javax.media.nativewindow.*; +import com.jogamp.common.util.locks.RecursiveLock; + +import com.jogamp.newt.event.*; +import com.jogamp.newt.impl.*; +import javax.media.nativewindow.util.Insets; +import javax.media.nativewindow.util.Point; + +public class MacWindow extends WindowImpl { + + // Window styles + private static final int NSBorderlessWindowMask = 0; + private static final int NSTitledWindowMask = 1 << 0; + private static final int NSClosableWindowMask = 1 << 1; + private static final int NSMiniaturizableWindowMask = 1 << 2; + private static final int NSResizableWindowMask = 1 << 3; + + // Window backing store types + private static final int NSBackingStoreRetained = 0; + private static final int NSBackingStoreNonretained = 1; + private static final int NSBackingStoreBuffered = 2; + + // Key constants handled differently on Mac OS X than other platforms + private static final int NSUpArrowFunctionKey = 0xF700; + private static final int NSDownArrowFunctionKey = 0xF701; + private static final int NSLeftArrowFunctionKey = 0xF702; + private static final int NSRightArrowFunctionKey = 0xF703; + private static final int NSF1FunctionKey = 0xF704; + private static final int NSF2FunctionKey = 0xF705; + private static final int NSF3FunctionKey = 0xF706; + private static final int NSF4FunctionKey = 0xF707; + private static final int NSF5FunctionKey = 0xF708; + private static final int NSF6FunctionKey = 0xF709; + private static final int NSF7FunctionKey = 0xF70A; + private static final int NSF8FunctionKey = 0xF70B; + private static final int NSF9FunctionKey = 0xF70C; + private static final int NSF10FunctionKey = 0xF70D; + private static final int NSF11FunctionKey = 0xF70E; + private static final int NSF12FunctionKey = 0xF70F; + private static final int NSF13FunctionKey = 0xF710; + private static final int NSF14FunctionKey = 0xF711; + private static final int NSF15FunctionKey = 0xF712; + private static final int NSF16FunctionKey = 0xF713; + private static final int NSF17FunctionKey = 0xF714; + private static final int NSF18FunctionKey = 0xF715; + private static final int NSF19FunctionKey = 0xF716; + private static final int NSF20FunctionKey = 0xF717; + private static final int NSF21FunctionKey = 0xF718; + private static final int NSF22FunctionKey = 0xF719; + private static final int NSF23FunctionKey = 0xF71A; + private static final int NSF24FunctionKey = 0xF71B; + private static final int NSF25FunctionKey = 0xF71C; + private static final int NSF26FunctionKey = 0xF71D; + private static final int NSF27FunctionKey = 0xF71E; + private static final int NSF28FunctionKey = 0xF71F; + private static final int NSF29FunctionKey = 0xF720; + private static final int NSF30FunctionKey = 0xF721; + private static final int NSF31FunctionKey = 0xF722; + private static final int NSF32FunctionKey = 0xF723; + private static final int NSF33FunctionKey = 0xF724; + private static final int NSF34FunctionKey = 0xF725; + private static final int NSF35FunctionKey = 0xF726; + private static final int NSInsertFunctionKey = 0xF727; + private static final int NSDeleteFunctionKey = 0xF728; + private static final int NSHomeFunctionKey = 0xF729; + private static final int NSBeginFunctionKey = 0xF72A; + private static final int NSEndFunctionKey = 0xF72B; + private static final int NSPageUpFunctionKey = 0xF72C; + private static final int NSPageDownFunctionKey = 0xF72D; + private static final int NSPrintScreenFunctionKey = 0xF72E; + private static final int NSScrollLockFunctionKey = 0xF72F; + private static final int NSPauseFunctionKey = 0xF730; + private static final int NSSysReqFunctionKey = 0xF731; + private static final int NSBreakFunctionKey = 0xF732; + private static final int NSResetFunctionKey = 0xF733; + private static final int NSStopFunctionKey = 0xF734; + private static final int NSMenuFunctionKey = 0xF735; + private static final int NSUserFunctionKey = 0xF736; + private static final int NSSystemFunctionKey = 0xF737; + private static final int NSPrintFunctionKey = 0xF738; + private static final int NSClearLineFunctionKey = 0xF739; + private static final int NSClearDisplayFunctionKey = 0xF73A; + private static final int NSInsertLineFunctionKey = 0xF73B; + private static final int NSDeleteLineFunctionKey = 0xF73C; + private static final int NSInsertCharFunctionKey = 0xF73D; + private static final int NSDeleteCharFunctionKey = 0xF73E; + private static final int NSPrevFunctionKey = 0xF73F; + private static final int NSNextFunctionKey = 0xF740; + private static final int NSSelectFunctionKey = 0xF741; + private static final int NSExecuteFunctionKey = 0xF742; + private static final int NSUndoFunctionKey = 0xF743; + private static final int NSRedoFunctionKey = 0xF744; + private static final int NSFindFunctionKey = 0xF745; + private static final int NSHelpFunctionKey = 0xF746; + private static final int NSModeSwitchFunctionKey = 0xF747; + + private volatile long surfaceHandle; + + // non fullscreen dimensions .. + private final Insets insets = new Insets(0,0,0,0); + + static { + MacDisplay.initSingleton(); + } + + public MacWindow() { + } + + protected void createNativeImpl() { + config = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration(caps, null, getScreen().getGraphicsScreen()); + if (config == null) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + } + + protected void closeNativeImpl() { + nsViewLock.lock(); + try { + if(DEBUG_IMPLEMENTATION) { System.err.println("MacWindow.CloseAction "+Thread.currentThread().getName()); } + if (getWindowHandle() != 0) { + close0(getWindowHandle()); + } + } catch (Throwable t) { + if(DEBUG_IMPLEMENTATION) { + Exception e = new Exception("Warning: closeNative failed - "+Thread.currentThread().getName(), t); + e.printStackTrace(); + } + } finally { + setWindowHandle(0); + nsViewLock.unlock(); + } + windowDestroyed(); // No OSX hook for DidClose, so do it here + } + + public final long getSurfaceHandle() { + return surfaceHandle; + } + + public Insets getInsets() { + // in order to properly calculate insets we need the window to be + // created + nsViewLock.lock(); + try { + createWindow(false, getX(), getY(), getWidth(), getHeight(), isFullscreen()); + return (Insets) insets.clone(); + } finally { + nsViewLock.unlock(); + } + } + + private RecursiveLock nsViewLock = new RecursiveLock(); + + protected int lockSurfaceImpl() { + nsViewLock.lock(); + return LOCK_SUCCESS; + } + + protected void unlockSurfaceImpl() { + nsViewLock.unlock(); + } + + protected void setVisibleImpl(boolean visible, int x, int y, int width, int height) { + nsViewLock.lock(); + try { + if (visible) { + createWindow(false, x, y, width, height, isFullscreen()); + if (getWindowHandle() != 0) { + makeKeyAndOrderFront0(getWindowHandle()); + } + } else { + if (getWindowHandle() != 0) { + orderOut0(getWindowHandle()); + } + } + visibleChanged(visible); + } finally { + nsViewLock.unlock(); + } + } + + protected void setTitleImpl(final String title) { + // FIXME: move nsViewLock up to window lock + nsViewLock.lock(); + try { + setTitle0(getWindowHandle(), title); + } finally { + nsViewLock.unlock(); + } + } + + protected void requestFocusImpl(boolean reparented) { + // FIXME: move nsViewLock up to window lock + nsViewLock.lock(); + try { + makeKey0(getWindowHandle()); + } finally { + nsViewLock.unlock(); + } + } + + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, boolean parentChange, int fullScreenChange, int decorationChange) { + nsViewLock.lock(); + try { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("MacWindow reconfig: parentChange "+parentChange+", fullScreenChange "+fullScreenChange+", decorationChange "+decorationChange+" "+x+"/"+y+" "+width+"x"+height); + } + int _x=(x>=0)?x:this.x; + int _y=(x>=0)?y:this.y; + int _w=(width>0)?width:this.width; + int _h=(height>0)?height:this.height; + + if(decorationChange!=0 || parentChange || fullScreenChange!=0) { + createWindow(true, _x, _y, _w, _h, fullScreenChange>0); + if (getWindowHandle() != 0) { + makeKeyAndOrderFront0(getWindowHandle()); + } + } else { + if(x>=0 || y>=0) { + setFrameTopLeftPoint0(getParentWindowHandle(), getWindowHandle(), _x, _y); + } + if(width>0 || height>0) { + setContentSize0(getWindowHandle(), _w, _h); + } + } + } finally { + nsViewLock.unlock(); + } + return true; + } + + protected Point getLocationOnScreenImpl(int x, int y) { + return null; + } + + private void insetsChanged(int left, int top, int right, int bottom) { + if (DEBUG_IMPLEMENTATION) { + System.err.println(Thread.currentThread().getName()+ + " Insets changed to " + left + ", " + top + ", " + right + ", " + bottom); + } + if (left != -1 && top != -1 && right != -1 && bottom != -1) { + insets.left = left; + insets.top = top; + insets.right = right; + insets.bottom = bottom; + } + } + + private char convertKeyChar(char keyChar) { + if (keyChar == '\r') { + // Turn these into \n + return '\n'; + } + + if (keyChar >= NSUpArrowFunctionKey && keyChar <= NSModeSwitchFunctionKey) { + switch (keyChar) { + case NSUpArrowFunctionKey: return KeyEvent.VK_UP; + case NSDownArrowFunctionKey: return KeyEvent.VK_DOWN; + case NSLeftArrowFunctionKey: return KeyEvent.VK_LEFT; + case NSRightArrowFunctionKey: return KeyEvent.VK_RIGHT; + case NSF1FunctionKey: return KeyEvent.VK_F1; + case NSF2FunctionKey: return KeyEvent.VK_F2; + case NSF3FunctionKey: return KeyEvent.VK_F3; + case NSF4FunctionKey: return KeyEvent.VK_F4; + case NSF5FunctionKey: return KeyEvent.VK_F5; + case NSF6FunctionKey: return KeyEvent.VK_F6; + case NSF7FunctionKey: return KeyEvent.VK_F7; + case NSF8FunctionKey: return KeyEvent.VK_F8; + case NSF9FunctionKey: return KeyEvent.VK_F9; + case NSF10FunctionKey: return KeyEvent.VK_F10; + case NSF11FunctionKey: return KeyEvent.VK_F11; + case NSF12FunctionKey: return KeyEvent.VK_F12; + case NSF13FunctionKey: return KeyEvent.VK_F13; + case NSF14FunctionKey: return KeyEvent.VK_F14; + case NSF15FunctionKey: return KeyEvent.VK_F15; + case NSF16FunctionKey: return KeyEvent.VK_F16; + case NSF17FunctionKey: return KeyEvent.VK_F17; + case NSF18FunctionKey: return KeyEvent.VK_F18; + case NSF19FunctionKey: return KeyEvent.VK_F19; + case NSF20FunctionKey: return KeyEvent.VK_F20; + case NSF21FunctionKey: return KeyEvent.VK_F21; + case NSF22FunctionKey: return KeyEvent.VK_F22; + case NSF23FunctionKey: return KeyEvent.VK_F23; + case NSF24FunctionKey: return KeyEvent.VK_F24; + case NSInsertFunctionKey: return KeyEvent.VK_INSERT; + case NSDeleteFunctionKey: return KeyEvent.VK_DELETE; + case NSHomeFunctionKey: return KeyEvent.VK_HOME; + case NSBeginFunctionKey: return KeyEvent.VK_BEGIN; + case NSEndFunctionKey: return KeyEvent.VK_END; + case NSPageUpFunctionKey: return KeyEvent.VK_PAGE_UP; + case NSPageDownFunctionKey: return KeyEvent.VK_PAGE_DOWN; + case NSPrintScreenFunctionKey: return KeyEvent.VK_PRINTSCREEN; + case NSScrollLockFunctionKey: return KeyEvent.VK_SCROLL_LOCK; + case NSPauseFunctionKey: return KeyEvent.VK_PAUSE; + // Not handled: + // NSSysReqFunctionKey + // NSBreakFunctionKey + // NSResetFunctionKey + case NSStopFunctionKey: return KeyEvent.VK_STOP; + // Not handled: + // NSMenuFunctionKey + // NSUserFunctionKey + // NSSystemFunctionKey + // NSPrintFunctionKey + // NSClearLineFunctionKey + // NSClearDisplayFunctionKey + // NSInsertLineFunctionKey + // NSDeleteLineFunctionKey + // NSInsertCharFunctionKey + // NSDeleteCharFunctionKey + // NSPrevFunctionKey + // NSNextFunctionKey + // NSSelectFunctionKey + // NSExecuteFunctionKey + // NSUndoFunctionKey + // NSRedoFunctionKey + // NSFindFunctionKey + // NSHelpFunctionKey + // NSModeSwitchFunctionKey + default: break; + } + } + + // NSEvent's charactersIgnoringModifiers doesn't ignore the shift key + if (keyChar >= 'a' && keyChar <= 'z') { + return Character.toUpperCase(keyChar); + } + + return keyChar; + } + + public void enqueueKeyEvent(boolean wait, int eventType, int modifiers, int keyCode, char keyChar) { + int key = convertKeyChar(keyChar); + if(DEBUG_IMPLEMENTATION) System.err.println("MacWindow.enqueueKeyEvent "+Thread.currentThread().getName()); + // Note that we send the key char for the key code on this + // platform -- we do not get any useful key codes out of the system + super.enqueueKeyEvent(wait, eventType, modifiers, key, keyChar); + } + + private void createWindow(final boolean recreate, final int x, final int y, final int width, final int height, final boolean fullscreen) { + + if(0!=getWindowHandle() && !recreate) { + return; + } + + try { + //runOnEDTIfAvail(true, new Runnable() { + // public void run() { + if(0!=getWindowHandle()) { + // save the view .. close the window + surfaceHandle = changeContentView0(getParentWindowHandle(), getWindowHandle(), 0); + if(recreate && 0==surfaceHandle) { + throw new NativeWindowException("Internal Error - recreate, window but no view"); + } + close0(getWindowHandle()); + setWindowHandle(0); + } else { + surfaceHandle = 0; + } + setWindowHandle(createWindow0(getParentWindowHandle(), + x, y, width, height, fullscreen, + (isUndecorated() ? + NSBorderlessWindowMask : + NSTitledWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask), + NSBackingStoreBuffered, + getScreen().getIndex(), surfaceHandle)); + if (getWindowHandle() == 0) { + throw new NativeWindowException("Could create native window "+Thread.currentThread().getName()+" "+this); + } + surfaceHandle = contentView0(getWindowHandle()); + setTitle0(getWindowHandle(), getTitle()); + // don't make the window visible on window creation + // makeKeyAndOrderFront0(windowHandle); + // } } ); + } catch (Exception ie) { + ie.printStackTrace(); + } + + enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_MOVED); + enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_RESIZED); + enqueueWindowEvent(false, WindowEvent.EVENT_WINDOW_GAINED_FOCUS); + } + + protected static native boolean initIDs0(); + private native long createWindow0(long parentWindowHandle, int x, int y, int w, int h, + boolean fullscreen, int windowStyle, + int backingStoreType, + int screen_idx, long view); + private native void makeKeyAndOrderFront0(long window); + private native void makeKey0(long window); + private native void orderOut0(long window); + private native void close0(long window); + private native void setTitle0(long window, String title); + private native long contentView0(long window); + private native long changeContentView0(long parentWindowHandle, long window, long view); + private native void setContentSize0(long window, int w, int h); + private native void setFrameTopLeftPoint0(long parentWindowHandle, long window, int x, int y); +} diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Display.java b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Display.java new file mode 100644 index 000000000..18d058a9c --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Display.java @@ -0,0 +1,81 @@ +/* + * 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.impl.opengl.broadcom.egl; + +import com.jogamp.newt.impl.*; +import com.jogamp.opengl.impl.egl.*; +import javax.media.nativewindow.*; +import javax.media.nativewindow.egl.*; + +public class Display extends com.jogamp.newt.impl.DisplayImpl { + + static { + NEWTJNILibLoader.loadNEWT(); + + if (!Window.initIDs()) { + throw new NativeWindowException("Failed to initialize BCEGL Window jmethodIDs"); + } + } + + public static void initSingleton() { + // just exist to ensure static init has been run + } + + + public Display() { + } + + protected void createNativeImpl() { + long handle = CreateDisplay(Screen.fixedWidth, Screen.fixedHeight); + if (handle == EGL.EGL_NO_DISPLAY) { + throw new NativeWindowException("BC EGL CreateDisplay failed"); + } + aDevice = new EGLGraphicsDevice(handle); + } + + protected void closeNativeImpl() { + if (aDevice.getHandle() != EGL.EGL_NO_DISPLAY) { + DestroyDisplay(aDevice.getHandle()); + } + } + + protected void dispatchMessagesNative() { + // n/a .. DispatchMessages(); + } + + private native long CreateDisplay(int width, int height); + private native void DestroyDisplay(long dpy); + private native void DispatchMessages(); +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java new file mode 100644 index 000000000..144fe5e83 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Screen.java @@ -0,0 +1,62 @@ +/* + * 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.impl.opengl.broadcom.egl; + +import javax.media.nativewindow.*; + +public class Screen extends com.jogamp.newt.impl.ScreenImpl { + + static { + Display.initSingleton(); + } + + + public Screen() { + } + + protected void createNativeImpl() { + aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); + setScreenSize(fixedWidth, fixedHeight); + } + + protected void closeNativeImpl() { } + + //---------------------------------------------------------------------- + // Internals only + // + + static final int fixedWidth = 1920; + static final int fixedHeight = 1080; +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java new file mode 100644 index 000000000..ad903731b --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/broadcom/egl/Window.java @@ -0,0 +1,163 @@ +/* + * 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.impl.opengl.broadcom.egl; + +import com.jogamp.opengl.impl.egl.*; +import javax.media.nativewindow.*; +import javax.media.opengl.GLCapabilities; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.util.Point; + +public class Window extends com.jogamp.newt.impl.WindowImpl { + static { + Display.initSingleton(); + } + + public Window() { + } + + protected void createNativeImpl() { + if(0!=getParentWindowHandle()) { + throw new RuntimeException("Window parenting not supported (yet)"); + } + // query a good configuration .. even thought we drop this one + // and reuse the EGLUtil choosen one later. + config = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration(caps, null, getScreen().getGraphicsScreen()); + if (config == null) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + setSizeImpl(getScreen().getWidth(), getScreen().getHeight()); + + setWindowHandle(realizeWindow(true, width, height)); + if (0 == getWindowHandle()) { + throw new NativeWindowException("Error native Window Handle is null"); + } + } + + protected void closeNativeImpl() { + if(0!=windowHandleClose) { + CloseWindow(getDisplayHandle(), windowHandleClose); + } + } + + protected void setVisibleImpl(boolean visible, int x, int y, int width, int height) { + reconfigureWindowImpl(x, y, width, height, false, 0, 0); + visibleChanged(visible); + } + + protected void requestFocusImpl(boolean reparented) { } + + protected void setSizeImpl(int width, int height) { + if(0!=getWindowHandle()) { + // n/a in BroadcomEGL + System.err.println("BCEGL Window.setSizeImpl n/a in BroadcomEGL with realized window"); + } else { + this.width = width; + this.height = height; + } + } + + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, + boolean parentChange, int fullScreenChange, int decorationChange) { + if(0!=getWindowHandle()) { + if(0!=fullScreenChange) { + if( fullScreenChange > 0 ) { + // n/a in BroadcomEGL + System.err.println("setFullscreen n/a in BroadcomEGL"); + return false; + } + } + } + if(width>0 || height>0) { + if(0!=getWindowHandle()) { + // n/a in BroadcomEGL + System.err.println("BCEGL Window.setSizeImpl n/a in BroadcomEGL with realized window"); + } else { + this.width=(width>0)?width:this.width; + this.height=(height>0)?height:this.height; + } + } + if(x>=0 || y>=0) { + System.err.println("BCEGL Window.setPositionImpl n/a in BroadcomEGL"); + } + return true; + } + + protected Point getLocationOnScreenImpl(int x, int y) { + return new Point(x,y); + } + + + public boolean surfaceSwap() { + SwapWindow(getDisplayHandle(), getWindowHandle()); + return true; + } + + //---------------------------------------------------------------------- + // Internals only + // + + protected static native boolean initIDs(); + private native long CreateWindow(long eglDisplayHandle, boolean chromaKey, int width, int height); + private native void CloseWindow(long eglDisplayHandle, long eglWindowHandle); + private native void SwapWindow(long eglDisplayHandle, long eglWindowHandle); + + + private long realizeWindow(boolean chromaKey, int width, int height) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("BCEGL Window.realizeWindow() with: chroma "+chromaKey+", "+width+"x"+height+", "+config); + } + long handle = CreateWindow(getDisplayHandle(), chromaKey, width, height); + if (0 == handle) { + throw new NativeWindowException("Error native Window Handle is null"); + } + windowHandleClose = handle; + return handle; + } + + private void windowCreated(int cfgID, int width, int height) { + this.width = width; + this.height = height; + GLCapabilities capsReq = (GLCapabilities) config.getRequestedCapabilities(); + config = EGLGraphicsConfiguration.create(capsReq, getScreen().getGraphicsScreen(), cfgID); + if (config == null) { + throw new NativeWindowException("Error creating EGLGraphicsConfiguration from id: "+cfgID+", "+this); + } + if(DEBUG_IMPLEMENTATION) { + System.err.println("BCEGL Window.windowCreated(): "+toHexString(cfgID)+", "+width+"x"+height+", "+config); + } + } + + private long windowHandleClose; +} diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDDisplay.java b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDDisplay.java new file mode 100644 index 000000000..eab1816da --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDDisplay.java @@ -0,0 +1,84 @@ +/* + * 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.impl.opengl.kd; + +import com.jogamp.newt.*; +import com.jogamp.newt.impl.*; +import com.jogamp.opengl.impl.egl.*; +import javax.media.nativewindow.*; +import javax.media.nativewindow.egl.*; + +public class KDDisplay extends DisplayImpl { + + static { + NEWTJNILibLoader.loadNEWT(); + + if (!KDWindow.initIDs()) { + throw new NativeWindowException("Failed to initialize KDWindow jmethodIDs"); + } + } + + public static void initSingleton() { + // just exist to ensure static init has been run + } + + + public KDDisplay() { + } + + protected void createNativeImpl() { + // FIXME: map name to EGL_*_DISPLAY + long handle = EGL.eglGetDisplay(EGL.EGL_DEFAULT_DISPLAY); + if (handle == EGL.EGL_NO_DISPLAY) { + throw new NativeWindowException("eglGetDisplay failed"); + } + if (!EGL.eglInitialize(handle, null, null)) { + throw new NativeWindowException("eglInitialize failed"); + } + aDevice = new EGLGraphicsDevice(handle); + } + + protected void closeNativeImpl() { + if (aDevice.getHandle() != EGL.EGL_NO_DISPLAY) { + EGL.eglTerminate(aDevice.getHandle()); + } + } + + protected void dispatchMessagesNative() { + DispatchMessages(); + } + + private native void DispatchMessages(); +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java new file mode 100644 index 000000000..1a73d0e5d --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java @@ -0,0 +1,58 @@ +/* + * 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.impl.opengl.kd; + +import com.jogamp.newt.*; +import com.jogamp.newt.impl.ScreenImpl; +import javax.media.nativewindow.*; + +public class KDScreen extends ScreenImpl { + static { + KDDisplay.initSingleton(); + } + + public KDScreen() { + } + + protected void createNativeImpl() { + aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); + } + + protected void closeNativeImpl() { } + + // elevate access to this package .. + protected void setScreenSize(int w, int h) { + super.setScreenSize(w, h); + } +} diff --git a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java new file mode 100644 index 000000000..f0bc8587b --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDWindow.java @@ -0,0 +1,149 @@ +/* + * 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.impl.opengl.kd; + +import com.jogamp.newt.*; +import com.jogamp.newt.event.*; +import com.jogamp.newt.impl.*; +import com.jogamp.opengl.impl.egl.*; +import javax.media.nativewindow.*; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLProfile; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.util.Point; + +public class KDWindow extends WindowImpl { + private static final String WINDOW_CLASS_NAME = "NewtWindow"; + + static { + KDDisplay.initSingleton(); + } + + public KDWindow() { + } + + protected void createNativeImpl() { + if(0!=getParentWindowHandle()) { + throw new RuntimeException("Window parenting not supported (yet)"); + } + config = GraphicsConfigurationFactory.getFactory(getScreen().getDisplay().getGraphicsDevice()).chooseGraphicsConfiguration(caps, null, getScreen().getGraphicsScreen()); + if (config == null) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + + GLCapabilities eglCaps = (GLCapabilities)config.getChosenCapabilities(); + int[] eglAttribs = EGLGraphicsConfiguration.GLCapabilities2AttribList(eglCaps); + + eglWindowHandle = CreateWindow(getDisplayHandle(), eglAttribs); + if (eglWindowHandle == 0) { + throw new NativeWindowException("Error creating egl window: "+config); + } + setVisible0(eglWindowHandle, false); + setWindowHandle(RealizeWindow(eglWindowHandle)); + if (0 == getWindowHandle()) { + throw new NativeWindowException("Error native Window Handle is null"); + } + windowHandleClose = eglWindowHandle; + } + + protected void closeNativeImpl() { + if(0!=windowHandleClose) { + CloseWindow(windowHandleClose, windowUserData); + windowUserData=0; + } + } + + protected void setVisibleImpl(boolean visible, int x, int y, int width, int height) { + setVisible0(eglWindowHandle, visible); + reconfigureWindowImpl(x, y, width, height, false, 0, 0); + visibleChanged(visible); + } + + protected void requestFocusImpl(boolean reparented) { } + + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, + boolean parentChange, int fullScreenChange, int decorationChange) { + if(0!=eglWindowHandle) { + if(0!=fullScreenChange) { + boolean fs = fullScreenChange > 0; + setFullScreen0(eglWindowHandle, fs); + if(fs) { + return true; + } + } + // int _x=(x>=0)?x:this.x; + // int _y=(x>=0)?y:this.y; + int _w=(width>0)?width:this.width; + int _h=(height>0)?height:this.height; + if(width>0 || height>0) { + setSize0(eglWindowHandle, _w, _h); + } + if(x>=0 || y>=0) { + System.err.println("setPosition n/a in KD"); + } + } + return true; + } + + protected Point getLocationOnScreenImpl(int x, int y) { + return new Point(x,y); + } + + //---------------------------------------------------------------------- + // Internals only + // + + protected static native boolean initIDs(); + private native long CreateWindow(long displayHandle, int[] attributes); + private native long RealizeWindow(long eglWindowHandle); + private native int CloseWindow(long eglWindowHandle, long userData); + private native void setVisible0(long eglWindowHandle, boolean visible); + private native void setSize0(long eglWindowHandle, int width, int height); + private native void setFullScreen0(long eglWindowHandle, boolean fullscreen); + + private void windowCreated(long userData) { + windowUserData=userData; + } + + protected void sizeChanged(int newWidth, int newHeight, boolean force) { + if(fullscreen) { + ((KDScreen)getScreen()).setScreenSize(width, height); + } + super.sizeChanged(newWidth, newHeight, force); + } + + private long eglWindowHandle; + private long windowHandleClose; + private long windowUserData; +} diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsDisplay.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsDisplay.java new file mode 100644 index 000000000..fe86257ff --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsDisplay.java @@ -0,0 +1,105 @@ +/* + * 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.impl.windows; + +import javax.media.nativewindow.*; +import javax.media.nativewindow.windows.*; +import com.jogamp.newt.*; +import com.jogamp.newt.impl.*; + +public class WindowsDisplay extends DisplayImpl { + + protected static final String WINDOW_CLASS_NAME = "NewtWindowClass"; + private static int windowClassAtom; + private static long hInstance; + + static { + NEWTJNILibLoader.loadNEWT(); + + if (!WindowsWindow.initIDs0()) { + throw new NativeWindowException("Failed to initialize WindowsWindow jmethodIDs"); + } + } + + public static void initSingleton() { + // just exist to ensure static init has been run + } + + + public WindowsDisplay() { + } + + protected void createNativeImpl() { + aDevice = new WindowsGraphicsDevice(); + } + + protected void closeNativeImpl() { + // Can't do .. only at application shutdown + // UnregisterWindowClass0(getWindowClassAtom(), getHInstance()); + } + + protected void dispatchMessagesNative() { + DispatchMessages0(); + } + + protected static synchronized int getWindowClassAtom() { + if(0 == windowClassAtom) { + windowClassAtom = RegisterWindowClass0(WINDOW_CLASS_NAME, getHInstance()); + if (0 == windowClassAtom) { + throw new NativeWindowException("Error while registering window class"); + } + } + return windowClassAtom; + } + + protected static synchronized long getHInstance() { + if(0 == hInstance) { + hInstance = LoadLibraryW0("newt"); + if (0 == hInstance) { + throw new NativeWindowException("Error finding HINSTANCE for \"newt\""); + } + } + return hInstance; + } + + //---------------------------------------------------------------------- + // Internals only + // + private static native long LoadLibraryW0(String libraryName); + private static native int RegisterWindowClass0(String windowClassName, long hInstance); + private static native void UnregisterWindowClass0(int wndClassAtom, long hInstance); + + private static native void DispatchMessages0(); +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java new file mode 100644 index 000000000..e15a40e7b --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java @@ -0,0 +1,114 @@ +/* + * 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.impl.windows; + +import com.jogamp.common.util.ArrayHashSet; +import java.util.ArrayList; + +import com.jogamp.newt.*; +import com.jogamp.newt.impl.ScreenImpl; +import com.jogamp.newt.ScreenMode; +import com.jogamp.newt.impl.ScreenModeStatus; +import com.jogamp.newt.util.ScreenModeUtil; + +import javax.media.nativewindow.*; + +public class WindowsScreen extends ScreenImpl { + + static { + WindowsDisplay.initSingleton(); + } + + public WindowsScreen() { + } + + protected void createNativeImpl() { + aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); + setScreenSize(getWidthImpl0(screen_idx), getHeightImpl0(screen_idx)); + } + + protected void closeNativeImpl() { + } + + private int[] getScreenModeIdx(int idx) { + int[] modeProps = getScreenMode0(screen_idx, idx); + if (null == modeProps || 0 == modeProps.length) { + return null; + } + if(modeProps.length < ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL) { + throw new RuntimeException("properties array too short, should be >= "+ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+modeProps.length); + } + return modeProps; + } + + private int nativeModeIdx; + + protected int[] getScreenModeFirstImpl() { + nativeModeIdx = 0; + return getScreenModeNextImpl(); + } + + protected int[] getScreenModeNextImpl() { + int[] modeProps = getScreenModeIdx(nativeModeIdx); + if (null != modeProps && 0 < modeProps.length) { + nativeModeIdx++; + return modeProps; + } + return null; + } + + protected ScreenMode getCurrentScreenModeImpl() { + int[] modeProps = getScreenModeIdx(-1); + if (null != modeProps && 0 < modeProps.length) { + return ScreenModeUtil.streamIn(modeProps, 0); + } + return null; + } + + protected boolean setCurrentScreenModeImpl(ScreenMode sm) { + return setScreenMode0(screen_idx, + sm.getMonitorMode().getSurfaceSize().getResolution().getWidth(), + sm.getMonitorMode().getSurfaceSize().getResolution().getHeight(), + sm.getMonitorMode().getSurfaceSize().getBitsPerPixel(), + sm.getMonitorMode().getRefreshRate(), + sm.getRotation()); + } + + // Native calls + private native int getWidthImpl0(int scrn_idx); + + private native int getHeightImpl0(int scrn_idx); + + private native int[] getScreenMode0(int screen_index, int mode_index); + private native boolean setScreenMode0(int screen_index, int width, int height, int bits, int freq, int rot); +} diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java new file mode 100644 index 000000000..daa09b034 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsWindow.java @@ -0,0 +1,208 @@ +/* + * 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.windows; + +import javax.media.nativewindow.*; +import com.jogamp.newt.impl.WindowImpl; +import javax.media.nativewindow.util.Insets; +import javax.media.nativewindow.util.Point; + +public class WindowsWindow extends WindowImpl { + + private long hmon; + private long hdc; + private long windowHandleClose; + private final Insets insets = new Insets(0, 0, 0, 0); + + static { + WindowsDisplay.initSingleton(); + } + + public WindowsWindow() { + } + + protected int lockSurfaceImpl() { + if( 0 != getWindowHandle() && 0 == hdc ) { + hdc = GetDC0(getWindowHandle()); + hmon = MonitorFromWindow0(getWindowHandle()); + } + return LOCK_SUCCESS; + } + + protected void unlockSurfaceImpl() { + if ( 0 != hdc && 0 != getWindowHandle() && getWindowLockRecursionCount() == 0) { + ReleaseDC0(getWindowHandle(), hdc); + hdc=0; + } + } + + public final long getSurfaceHandle() { + return hdc; + } + + public boolean hasDeviceChanged() { + if(0!=getWindowHandle()) { + long _hmon = MonitorFromWindow0(getWindowHandle()); + if (hmon != _hmon) { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + Exception e = new Exception("Info: Window Device Changed "+Thread.currentThread().getName()+ + ", HMON "+toHexString(hmon)+" -> "+toHexString(_hmon)); + e.printStackTrace(); + } + hmon = _hmon; + return true; + } + } + return false; + } + + protected void createNativeImpl() { + WindowsScreen screen = (WindowsScreen) getScreen(); + WindowsDisplay display = (WindowsDisplay) screen.getDisplay(); + config = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice()).chooseGraphicsConfiguration(caps, null, screen.getGraphicsScreen()); + if (config == null) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + setWindowHandle(CreateWindow0(getParentWindowHandle(), + display.getWindowClassAtom(), display.WINDOW_CLASS_NAME, display.getHInstance(), + 0, undecorated, x, y, width, height)); + if (getWindowHandle() == 0) { + throw new NativeWindowException("Error creating window"); + } + windowHandleClose = getWindowHandle(); + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + Exception e = new Exception("Info: Window new window handle "+Thread.currentThread().getName()+ + " (Parent HWND "+toHexString(getParentWindowHandle())+ + ") : HWND "+toHexString(getWindowHandle())+", "+Thread.currentThread()); + e.printStackTrace(); + } + } + + protected void closeNativeImpl() { + if (hdc != 0) { + if(windowHandleClose != 0) { + try { + ReleaseDC0(windowHandleClose, hdc); + } catch (Throwable t) { + if(DEBUG_IMPLEMENTATION) { + Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t); + e.printStackTrace(); + } + } + } + hdc = 0; + } + if(windowHandleClose != 0) { + try { + DestroyWindow0(windowHandleClose); + } catch (Throwable t) { + if(DEBUG_IMPLEMENTATION) { + Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t); + e.printStackTrace(); + } + } finally { + windowHandleClose = 0; + } + } + } + + protected void windowDestroyed() { + windowHandleClose = 0; + super.windowDestroyed(); + } + + protected void setVisibleImpl(boolean visible, int x, int y, int width, int height) { + setVisible0(getWindowHandle(), visible, (getParentWindowHandle()==0)?true:false, x, y, width, height); + visibleChanged(visible); + } + + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, + boolean parentChange, int fullScreenChange, int decorationChange) { + reconfigureWindow0( (fullScreenChange>0)?0:getParentWindowHandle(), + getWindowHandle(), x, y, width, height, isVisible(), parentChange, fullScreenChange, decorationChange); + return true; + } + + protected void requestFocusImpl(boolean force) { + requestFocus0(getWindowHandle(), force); + } + + protected void setTitleImpl(final String title) { + setTitle0(getWindowHandle(), title); + } + + public Insets getInsets() { + return (Insets)insets.clone(); + } + + protected Point getLocationOnScreenImpl(int x, int y) { + return (Point) getRelativeLocation0( getWindowHandle(), 0 /*root win*/, x, y); + } + + //---------------------------------------------------------------------- + // Internals only + // + protected static native boolean initIDs0(); + private native long CreateWindow0(long parentWindowHandle, + int wndClassAtom, String wndName, + long hInstance, long visualID, + boolean isUndecorated, + int x, int y, int width, int height); + private native void DestroyWindow0(long windowHandle); + private native long GetDC0(long windowHandle); + private native void ReleaseDC0(long windowHandle, long hdc); + private native long MonitorFromWindow0(long windowHandle); + private native void setVisible0(long windowHandle, boolean visible, boolean top, int x, int y, int width, int height); + private native void reconfigureWindow0(long parentWindowHandle, long windowHandle, + int x, int y, int width, int height, boolean isVisible, + boolean parentChange, int fullScreenChange, int decorationChange); + private static native void setTitle0(long windowHandle, String title); + private native void requestFocus0(long windowHandle, boolean force); + private native Object getRelativeLocation0(long src_win, long dest_win, int src_x, int src_y); + + private void insetsChanged(int left, int top, int right, int bottom) { + if (left != -1 && top != -1 && right != -1 && bottom != -1) { + if (left != insets.left || top != insets.top || right != insets.right || bottom != insets.bottom) { + insets.left = left; + insets.top = top; + insets.right = right; + insets.bottom = bottom; + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window.insetsChanged: "+insets); + } + } + } + } +} diff --git a/src/newt/classes/com/jogamp/newt/impl/x11/X11Display.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Display.java new file mode 100644 index 000000000..a24d0953e --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Display.java @@ -0,0 +1,115 @@ +/* + * 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.impl.x11; + +import javax.media.nativewindow.*; +import javax.media.nativewindow.x11.*; +import com.jogamp.newt.impl.*; +import com.jogamp.nativewindow.impl.x11.X11Util; + +public class X11Display extends DisplayImpl { + + static { + NEWTJNILibLoader.loadNEWT(); + + if ( !initIDs0() ) { + throw new NativeWindowException("Failed to initialize X11Display jmethodIDs"); + } + + if (!X11Window.initIDs0()) { + throw new NativeWindowException("Failed to initialize X11Window jmethodIDs"); + } + } + + public static void initSingleton() { + // just exist to ensure static init has been run + } + + + public X11Display() { + } + + public String validateDisplayName(String name, long handle) { + return X11Util.validateDisplayName(name, handle); + } + + protected void createNativeImpl() { + long handle = X11Util.createDisplay(name); + if( 0 == handle ) { + throw new RuntimeException("Error creating display: "+name); + } + try { + CompleteDisplay0(handle); + } catch(RuntimeException e) { + X11Util.closeDisplay(handle); + throw e; + } + aDevice = new X11GraphicsDevice(handle, NativeWindowFactory.getNullToolkitLock()); + // aDevice = new X11GraphicsDevice(handle, NativeWindowFactory.createDefaultToolkitLockNoAWT(NativeWindowFactory.TYPE_X11, handle)); + // aDevice = new X11GraphicsDevice(handle); + + } + + protected void closeNativeImpl() { + X11Util.closeDisplay(getHandle()); + } + + protected void dispatchMessagesNative() { + if(0==getHandle()) { + throw new RuntimeException("display handle null"); + } + DispatchMessages0(getHandle(), javaObjectAtom, windowDeleteAtom); + } + + protected long getJavaObjectAtom() { return javaObjectAtom; } + protected long getWindowDeleteAtom() { return windowDeleteAtom; } + + //---------------------------------------------------------------------- + // Internals only + // + private static native boolean initIDs0(); + + private native void CompleteDisplay0(long handle); + + private native void DispatchMessages0(long display, long javaObjectAtom, long windowDeleteAtom); + + private void displayCompleted(long javaObjectAtom, long windowDeleteAtom) { + this.javaObjectAtom=javaObjectAtom; + this.windowDeleteAtom=windowDeleteAtom; + } + + private long windowDeleteAtom; + private long javaObjectAtom; +} + diff --git a/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java new file mode 100644 index 000000000..5e89a9972 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java @@ -0,0 +1,270 @@ +/* + * 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.impl.x11; + +import com.jogamp.nativewindow.impl.x11.X11Util; +import com.jogamp.newt.impl.ScreenImpl; +import com.jogamp.newt.ScreenMode; +import com.jogamp.newt.util.ScreenModeUtil; +import java.util.List; + +import javax.media.nativewindow.x11.*; + +public class X11Screen extends ScreenImpl { + + static { + X11Display.initSingleton(); + } + + public X11Screen() { + } + + protected void createNativeImpl() { + long handle = GetScreen0(display.getHandle(), screen_idx); + if (handle == 0) { + throw new RuntimeException("Error creating screen: " + screen_idx); + } + aScreen = new X11GraphicsScreen((X11GraphicsDevice) getDisplay().getGraphicsDevice(), screen_idx); + setScreenSize(getWidth0(display.getHandle(), screen_idx), + getHeight0(display.getHandle(), screen_idx)); + } + + protected void closeNativeImpl() { + } + + private int[] nrotations; + private int nrotation_index; + private int nres_number; + private int nres_index; + private int[] nrates; + private int nrate_index; + private int nmode_number; + + protected int[] getScreenModeFirstImpl() { + // initialize iterators and static data + nrotations = getAvailableScreenModeRotations0(display.getHandle(), screen_idx); + if(null==nrotations || 0==nrotations.length) { + return null; + } + nrotation_index = 0; + + nres_number = getNumScreenModeResolutions0(display.getHandle(), screen_idx); + if(0==nres_number) { + return null; + } + nres_index = 0; + + nrates = getScreenModeRates0(display.getHandle(), screen_idx, nres_index); + if(null==nrates || 0==nrates.length) { + return null; + } + nrate_index = 0; + + nmode_number = 0; + + return getScreenModeNextImpl(); + } + + protected int[] getScreenModeNextImpl() { + // assemble: w x h x bpp x f x r + + /** + System.err.println("******** mode: "+nmode_number); + System.err.println("rot "+nrotation_index); + System.err.println("rate "+nrate_index); + System.err.println("res "+nres_index); */ + + int[] res = getScreenModeResolution0(display.getHandle(), screen_idx, nres_index); + if(null==res || 0==res.length) { + return null; + } + if(0>=res[0] || 0>=res[1]) { + throw new InternalError("invalid resolution: "+res[0]+"x"+res[1]+" for res idx "+nres_index+"/"+nres_number); + } + int bpp = 32; // FIXME + int rate = nrates[nrate_index]; + if(0>=rate) { + throw new InternalError("invalid rate: "+rate+" at index "+nrate_index+"/"+nrates.length); + } + int rotation = nrotations[nrotation_index]; + + int[] props = new int[ 1 + ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL ]; + int i = 0; + props[i++] = nres_index; // use resolution index, not unique for native -> ScreenMode + props[i++] = 0; // set later for verification of iterator + props[i++] = res[0]; // width + props[i++] = res[1]; // height + props[i++] = bpp; // bpp + props[i++] = res[2]; // widthmm + props[i++] = res[3]; // heightmm + props[i++] = rate; // rate + props[i++] = rotation; + props[i - ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL] = i - 1; // count without extra element + + nmode_number++; + + // iteration: r -> f -> bpp -> [w x h] + nrotation_index++; + if(nrotation_index == nrotations.length) { + nrotation_index=0; + nrate_index++; + if(null == nrates || nrate_index == nrates.length){ + nres_index++; + if(nres_index == nres_number) { + // done + nrates=null; + nrotations=null; + return null; + } + + nrates = getScreenModeRates0(display.getHandle(), screen_idx, nres_index); + if(null==nrates || 0==nrates.length) { + return null; + } + nrate_index = 0; + } + } + + return props; + } + + protected ScreenMode getCurrentScreenModeImpl() { + int resNumber = getNumScreenModeResolutions0(display.getHandle(), screen_idx); + if(0==resNumber) { + return null; + } + int resIdx = getCurrentScreenResolutionIndex0(display.getHandle(), screen_idx); + if(0>resIdx) { + return null; + } + if(resIdx>=resNumber) { + throw new RuntimeException("Invalid resolution index: ! "+resIdx+" < "+resNumber); + } + int[] res = getScreenModeResolution0(display.getHandle(), screen_idx, resIdx); + if(null==res || 0==res.length) { + return null; + } + if(0>=res[0] || 0>=res[1]) { + throw new InternalError("invalid resolution: "+res[0]+"x"+res[1]+" for res idx "+resIdx+"/"+resNumber); + } + int rate = getCurrentScreenRate0(display.getHandle(), screen_idx); + if(0>rate) { + return null; + } + int rot = getCurrentScreenRotation0(display.getHandle(), screen_idx); + if(0>rot) { + return null; + } + + int[] props = new int[ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL]; + int i = 0; + props[i++] = 0; // set later for verification of iterator + props[i++] = res[0]; // width + props[i++] = res[1]; // height + props[i++] = 32; // FIXME: bpp + props[i++] = res[2]; // widthmm + props[i++] = res[3]; // heightmm + props[i++] = rate; // rate + props[i++] = rot; + props[i - ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL] = i; // count + return ScreenModeUtil.streamIn(props, 0); + } + + protected boolean setCurrentScreenModeImpl(ScreenMode screenMode) { + List screenModes = this.getScreenModesOrig(); + int screenModeIdx = screenModes.indexOf(screenMode); + if(0>screenModeIdx) { + throw new RuntimeException("ScreenMode not element of ScreenMode list: "+screenMode); + } + int resNumber = getNumScreenModeResolutions0(display.getHandle(), screen_idx); + int resIdx = getScreenModesIdx2NativeIdx().get(screenModeIdx); + if(0>resIdx || resIdx>=resNumber) { + throw new RuntimeException("Invalid resolution index: ! 0 < "+resIdx+" < "+resNumber+", screenMode["+screenModeIdx+"] "+screenMode); + } + + long dpy = X11Util.createDisplay(display.getName()); + if( 0 == dpy ) { + throw new RuntimeException("Error creating display: "+display.getName()); + } + + boolean done = false; + long t0 = System.currentTimeMillis(); + try { + int f = screenMode.getMonitorMode().getRefreshRate(); + int r = screenMode.getRotation(); + if( setCurrentScreenModeStart0(dpy, screen_idx, resIdx, f, r) ) { + while(!done && System.currentTimeMillis()-t0 < SCREEN_MODE_CHANGE_TIMEOUT) { + done = setCurrentScreenModePollEnd0(dpy, screen_idx, resIdx, f, r); + if(!done) { + Thread.yield(); + } + } + } + } finally { + X11Util.closeDisplay(dpy); + } + + if(!done) { + System.err.println("X11Screen.setCurrentScreenModeImpl: TO ("+SCREEN_MODE_CHANGE_TIMEOUT+") reached: "+ + (System.currentTimeMillis()-t0)+"ms"); + } + return done; + } + + //---------------------------------------------------------------------- + // Internals only + // + private static native long GetScreen0(long dpy, int scrn_idx); + + private static native int getWidth0(long display, int scrn_idx); + + private static native int getHeight0(long display, int scrn_idx); + + /** @return int[] { rot1, .. } */ + private static native int[] getAvailableScreenModeRotations0(long display, int screen_index); + + private static native int getNumScreenModeResolutions0(long display, int screen_index); + + /** @return int[] { width, height, widthmm, heightmm } */ + private static native int[] getScreenModeResolution0(long display, int screen_index, int mode_index); + + private static native int[] getScreenModeRates0(long display, int screen_index, int mode_index); + + private static native int getCurrentScreenResolutionIndex0(long display, int screen_index); + private static native int getCurrentScreenRate0(long display, int screen_index); + private static native int getCurrentScreenRotation0(long display, int screen_index); + + /** needs own Display connection for XRANDR event handling */ + private static native boolean setCurrentScreenModeStart0(long display, int screen_index, int mode_index, int freq, int rot); + private static native boolean setCurrentScreenModePollEnd0(long display, int screen_index, int mode_index, int freq, int rot); +} diff --git a/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java new file mode 100644 index 000000000..06c7dfa99 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java @@ -0,0 +1,148 @@ +/* + * 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.impl.x11; + +import com.jogamp.newt.impl.WindowImpl; +import javax.media.nativewindow.*; +import javax.media.nativewindow.x11.*; +import javax.media.nativewindow.util.Point; + +public class X11Window extends WindowImpl { + private static final String WINDOW_CLASS_NAME = "NewtWindow"; + + static { + X11Display.initSingleton(); + } + + public X11Window() { + } + + protected void createNativeImpl() { + X11Screen screen = (X11Screen) getScreen(); + X11Display display = (X11Display) screen.getDisplay(); + config = GraphicsConfigurationFactory.getFactory(display.getGraphicsDevice()).chooseGraphicsConfiguration(caps, null, screen.getGraphicsScreen()); + if (config == null) { + throw new NativeWindowException("Error choosing GraphicsConfiguration creating window: "+this); + } + X11GraphicsConfiguration x11config = (X11GraphicsConfiguration) config; + long visualID = x11config.getVisualID(); + long w = CreateWindow0(getParentWindowHandle(), + display.getHandle(), screen.getIndex(), visualID, + display.getJavaObjectAtom(), display.getWindowDeleteAtom(), + x, y, width, height, isUndecorated()); + if (w == 0) { + throw new NativeWindowException("Error creating window: "+w); + } + setWindowHandle(w); + windowHandleClose = w; + } + + protected void closeNativeImpl() { + if(0!=windowHandleClose && null!=getScreen() ) { + X11Display display = (X11Display) getScreen().getDisplay(); + try { + CloseWindow0(display.getHandle(), windowHandleClose, + display.getJavaObjectAtom(), display.getWindowDeleteAtom()); + } catch (Throwable t) { + if(DEBUG_IMPLEMENTATION) { + Exception e = new Exception("Warning: closeNativeImpl failed - "+Thread.currentThread().getName(), t); + e.printStackTrace(); + } + } finally { + windowHandleClose = 0; + } + } + } + + protected void windowDestroyed() { + windowHandleClose = 0; + super.windowDestroyed(); + } + + protected void setVisibleImpl(boolean visible, int x, int y, int width, int height) { + setVisible0(getDisplayHandle(), getWindowHandle(), visible, x, y, width, height); + } + + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, + boolean parentChange, int fullScreenChange, int decorationChange) { + reparentHandle=0; + reparentCount=0; + long reqNewParentHandle = ( fullScreenChange > 0 ) ? 0 : getParentWindowHandle() ; + + reconfigureWindow0( getDisplayHandle(), getScreenIndex(), reqNewParentHandle, getWindowHandle(), + x, y, width, height, isVisible(), parentChange, fullScreenChange, decorationChange); + return true; + } + + protected void requestFocusImpl(boolean force) { + requestFocus0(getDisplayHandle(), getWindowHandle(), force); + } + + protected void setTitleImpl(String title) { + setTitle0(getDisplayHandle(), getWindowHandle(), title); + } + + protected Point getLocationOnScreenImpl(int x, int y) { + return (Point) getRelativeLocation0( getDisplayHandle(), getScreenIndex(), getWindowHandle(), 0 /*root win*/, x, y); + } + + //---------------------------------------------------------------------- + // Internals only + // + + protected static native boolean initIDs0(); + private native long CreateWindow0(long parentWindowHandle, long display, int screen_index, + long visualID, long javaObjectAtom, long windowDeleteAtom, + int x, int y, int width, int height, boolean undecorated); + private native void CloseWindow0(long display, long windowHandle, long javaObjectAtom, long windowDeleteAtom); + private native void setVisible0(long display, long windowHandle, boolean visible, int x, int y, int width, int height); + private native void reconfigureWindow0(long display, int screen_index, long parentWindowHandle, long windowHandle, + int x, int y, int width, int height, boolean isVisible, + boolean parentChange, int fullScreenChange, int decorationChange); + private native void setTitle0(long display, long windowHandle, String title); + private native void requestFocus0(long display, long windowHandle, boolean force); + private native Object getRelativeLocation0(long display, int screen_index, long src_win, long dest_win, int src_x, int src_y); + + private void windowReparented(long gotParentHandle) { + reparentHandle = gotParentHandle; + reparentCount++; + if(DEBUG_IMPLEMENTATION) { + System.err.println("******** new parent ("+reparentCount+"): " + toHexString(reparentHandle) ); + } + } + + private long windowHandleClose; + private volatile long reparentHandle; + private volatile int reparentCount; +} diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java new file mode 100644 index 000000000..36302c55a --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -0,0 +1,843 @@ +/* + * 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.opengl; + +import com.jogamp.newt.*; +import com.jogamp.newt.event.*; +import com.jogamp.newt.impl.WindowImpl; +import javax.media.nativewindow.*; +import javax.media.nativewindow.util.Point; +import javax.media.opengl.*; +import com.jogamp.opengl.impl.GLDrawableHelper; +import javax.media.nativewindow.util.Insets; + +/** + * An implementation of {@link javax.media.opengl.GLAutoDrawable} interface, + * using an aggregation of a {@link com.jogamp.newt.Window} implementation. + * <P> + * This implementation does not make the OpenGL context current<br> + * before calling the various input EventListener callbacks, ie {@link com.jogamp.newt.event.MouseListener} etc.<br> + * This design decision is made in favor of a more performant and simplified + * implementation. Also the event dispatcher shall be implemented OpenGL agnostic.<br> + * To be able to use OpenGL commands from within such input {@link com.jogamp.newt.event.NEWTEventListener},<br> + * you can inject {@link javax.media.opengl.GLRunnable} objects + * via {@link #invoke(boolean, javax.media.opengl.GLRunnable)} to the OpenGL command stream.<br> + * <p> + */ +public class GLWindow implements GLAutoDrawable, Window { + private WindowImpl window; + + /** + * Constructor. Do not call this directly -- use {@link #create()} instead. + */ + protected GLWindow(Window window) { + resetCounter(); + this.window = (WindowImpl) window; + ((WindowImpl)this.window).setHandleDestroyNotify(false); + window.addWindowListener(new WindowAdapter() { + public void windowRepaint(WindowUpdateEvent e) { + if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { + display(); + } + } + + public void windowResized(WindowEvent e) { + sendReshape = true; + if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { + display(); + } + } + + public void windowDestroyNotify(WindowEvent e) { + if( !GLWindow.this.window.isSurfaceLockedByOtherThread() && !GLWindow.this.helper.isExternalAnimatorAnimating() ) { + destroy(); + } else { + sendDestroy = true; + } + } + }); + this.window.setLifecycleHook(new GLLifecycleHook()); + } + + /** + * Creates a new GLWindow attaching a new Window referencing a new Screen + * with the given GLCapabilities. + * <P> + * The resulting GLWindow owns the Window, Screen and Device, ie it will be destructed. + */ + public static GLWindow create(GLCapabilities caps) { + return new GLWindow(NewtFactory.createWindow(caps)); + } + + /** + * Creates a new GLWindow attaching a new Window referencing the given Screen + * with the given GLCapabilities. + * <P> + * 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)); + } + + /** + * Creates a new GLWindow attaching the given window. + * <P> + * 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); + } + + /** + * Creates a new GLWindow attaching a new child Window + * of the given <code>parentNativeWindow</code> with the given GLCapabilities. + * <P> + * The Display/Screen will be compatible with the <code>parentNativeWindow</code>, + * or even identical in case it's a Newt Window. + * <P> + * 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)); + } + + //---------------------------------------------------------------------- + // Window Access + // + + public final Capabilities getChosenCapabilities() { + if (drawable == null) { + return window.getChosenCapabilities(); + } + + return drawable.getChosenGLCapabilities(); + } + + public final Capabilities getRequestedCapabilities() { + return window.getRequestedCapabilities(); + } + + public final Window getWindow() { + return window; + } + + public final NativeWindow getParent() { + return window.getParent(); + } + + public final Screen getScreen() { + return window.getScreen(); + } + + public final void setTitle(String title) { + window.setTitle(title); + } + + public final String getTitle() { + return window.getTitle(); + } + + public final void setUndecorated(boolean value) { + window.setUndecorated(value); + } + + public final boolean isUndecorated() { + return window.isUndecorated(); + } + + public final void setFocusAction(FocusRunnable focusAction) { + window.setFocusAction(focusAction); + } + + public final void requestFocus() { + window.requestFocus(); + } + + public boolean hasFocus() { + return window.hasFocus(); + } + + public final Insets getInsets() { + return window.getInsets(); + } + + public final void setPosition(int x, int y) { + window.setPosition(x, y); + } + + public final boolean setFullscreen(boolean fullscreen) { + return window.setFullscreen(fullscreen); + } + + public final boolean isFullscreen() { + return window.isFullscreen(); + } + + public final boolean isVisible() { + return window.isVisible(); + } + + public final String toString() { + return "NEWT-GLWindow[ \n\tHelper: " + helper + ", \n\tDrawable: " + drawable + + ", \n\tContext: " + context + /** ", \n\tWindow: "+window+", \n\tFactory: "+factory+ */ "]"; + } + + public final int reparentWindow(NativeWindow newParent) { + return window.reparentWindow(newParent); + } + + public final int reparentWindow(NativeWindow newParent, boolean forceDestroyCreate) { + return window.reparentWindow(newParent, forceDestroyCreate); + } + + public final void removeChild(NativeWindow win) { + window.removeChild(win); + } + + public final void addChild(NativeWindow win) { + window.addChild(win); + } + + public void screenModeChangeNotify(ScreenMode sm) { + window.screenModeChangeNotify(sm); + } + + public void screenModeChanged(ScreenMode sm, boolean success) { + window.screenModeChanged(sm, success); + } + + //---------------------------------------------------------------------- + // Window.LifecycleHook Implementation + // + + public final void destroy(boolean unrecoverable) { + window.destroy(unrecoverable); + } + + public final void setVisible(boolean visible) { + window.setVisible(visible); + } + + public final void setSize(int width, int height) { + window.setSize(width, height); + } + + public final boolean isValid() { + return window.isValid(); + } + + public final boolean isNativeValid() { + return window.isNativeValid(); + } + + public Point getLocationOnScreen(Point storage) { + return window.getLocationOnScreen(storage); + } + + // Hide methods here .. + protected class GLLifecycleHook implements WindowImpl.LifecycleHook { + + class DisposeAction implements Runnable { + public void run() { + // Lock: Covered by DestroyAction .. + helper.dispose(GLWindow.this); + } + } + DisposeAction disposeAction = new DisposeAction(); + + /** Window.LifecycleHook */ + public synchronized void destroyActionPreLock(boolean unrecoverable) { + GLAnimatorControl animator = GLWindow.this.getAnimator(); + if(null!=animator) { + if(unrecoverable) { + if(animator.isStarted()) { + animator.stop(); + } + } else if(animator.isAnimating()) { + animator.pause(); + } + } + } + + /** Window.LifecycleHook */ + public synchronized void destroyActionInLock(boolean unrecoverable) { + if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { + String msg = new String("GLWindow.destroy("+unrecoverable+") "+Thread.currentThread()+", start"); + System.err.println(msg); + //Exception e1 = new Exception(msg); + //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(); + } + drawable.setRealized(false); + } + context = null; + drawable = null; + + if(unrecoverable) { + helper=null; + } + + if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { + System.err.println("GLWindow.destroy("+unrecoverable+") "+Thread.currentThread()+", fin"); + } + } + + /** Window.LifecycleHook */ + public synchronized void setVisibleAction(boolean visible, boolean nativeWindowCreated) { + if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { + String msg = new String("GLWindow.setVisibleAction("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", start"); + System.err.println(msg); + // Exception e1 = new Exception(msg); + // e1.printStackTrace(); + } + + /* if (nativeWindowCreated && null != context) { + throw new GLException("InternalError: Native Windows has been just created, but context wasn't destroyed (is not null)"); + } */ + if (null == context && visible && 0 != window.getWindowHandle() && 0<getWidth()*getHeight()) { + NativeWindow nw; + if (window.getWrappedWindow() != null) { + nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getGraphicsConfiguration()); + } else { + nw = window; + } + GLCapabilities glCaps = (GLCapabilities) nw.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + if(null==factory) { + factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); + } + if(null==drawable) { + drawable = factory.createGLDrawable(nw); + } + drawable.setRealized(true); + context = drawable.createContext(null); + resetCounter(); + } else if(!visible) { + resetCounter(); + } + if(Window.DEBUG_WINDOW_EVENT || Window.DEBUG_IMPLEMENTATION) { + String msg = new String("GLWindow.setVisibleAction("+visible+", "+nativeWindowCreated+") "+Thread.currentThread()+", fin"); + System.err.println(msg); + //Exception e1 = new Exception(msg); + //e1.printStackTrace(); + } + } + + boolean animatorPaused = false; + + public synchronized void pauseRenderingAction() { + GLAnimatorControl ctrl = GLWindow.this.getAnimator(); + if ( null!=ctrl && ctrl.isAnimating() && ctrl.getThread() != Thread.currentThread() ) { + animatorPaused = true; + ctrl.pause(); + } + } + + public synchronized void resumeRenderingAction() { + resetCounter(); + GLAnimatorControl ctrl = GLWindow.this.getAnimator(); + if ( null!=ctrl && animatorPaused ) { + animatorPaused = false; + ctrl.resume(); + } + } + } + + //---------------------------------------------------------------------- + // OpenGL-related methods and state + // + + private GLDrawableFactory factory; + private GLDrawable drawable; + private GLContext context; + private GLDrawableHelper helper = new GLDrawableHelper(); + // To make reshape events be sent immediately before a display event + private boolean sendReshape=false; + private boolean sendDestroy=false; + private boolean perfLog = false; + private long startTime, curTime, lastCheck; + private int totalFrames, lastFrames; + + public GLDrawableFactory getFactory() { + return factory; + } + + public void setContext(GLContext newCtx) { + context = newCtx; + } + + public GLContext getContext() { + return context; + } + + public GL getGL() { + if (context == null) { + return null; + } + return context.getGL(); + } + + public GL setGL(GL gl) { + if (context != null) { + context.setGL(gl); + return gl; + } + return null; + } + + public void addGLEventListener(GLEventListener listener) { + if(null!=helper) { + helper.addGLEventListener(listener); + } + } + + public void addGLEventListener(int index, GLEventListener listener) { + if(null!=helper) { + helper.addGLEventListener(index, listener); + } + } + + public void removeGLEventListener(GLEventListener listener) { + if(null!=helper) { + helper.removeGLEventListener(listener); + } + } + + public void setAnimator(GLAnimatorControl animatorControl) { + if(null!=helper) { + helper.setAnimator(animatorControl); + } + } + + public GLAnimatorControl getAnimator() { + if(null!=helper) { + return helper.getAnimator(); + } + return null; + } + + public boolean getPerfLogEnabled() { return perfLog; } + + public void enablePerfLog(boolean v) { + perfLog = v; + } + + public void invoke(boolean wait, GLRunnable glRunnable) { + if(null!=helper) { + helper.invoke(this, wait, glRunnable); + } + } + + public void display() { + display(false); + } + + public void display(boolean forceReshape) { + if( null == window ) { return; } + + if(sendDestroy || ( null!=window && window.hasDeviceChanged() && GLAutoDrawable.SCREEN_CHANGE_ACTION_ENABLED ) ) { + sendDestroy=false; + destroy(); + return; + } + + if( null == context && isVisible() && 0<getWidth()*getHeight() ) { + // retry native window and drawable/context creation + setVisible(true); + } + + if( isVisible() && isNativeValid() && null != context ) { + if(forceReshape) { + sendReshape = true; + } + if( NativeSurface.LOCK_SURFACE_NOT_READY < lockSurface() ) { + try { + helper.invokeGL(drawable, context, displayAction, initAction); + } finally { + unlockSurface(); + } + } + } + } + + /** This implementation uses a static value */ + public void setAutoSwapBufferMode(boolean onOrOff) { + if(null!=helper) { + helper.setAutoSwapBufferMode(onOrOff); + } + } + + /** This implementation uses a static value */ + public boolean getAutoSwapBufferMode() { + if(null!=helper) { + return helper.getAutoSwapBufferMode(); + } + return false; + } + + public void swapBuffers() { + if(drawable!=null && context != null) { + // Lock: Locked Surface/Window by MakeCurrent/Release + if (context != GLContext.getCurrent()) { + // Assume we should try to make the context current before swapping the buffers + helper.invokeGL(drawable, context, swapBuffersAction, initAction); + } else { + drawable.swapBuffers(); + } + } + } + + class InitAction implements Runnable { + public void run() { + // Lock: Locked Surface/Window by MakeCurrent/Release + helper.init(GLWindow.this); + resetCounter(); + } + } + private InitAction initAction = new InitAction(); + + class DisplayAction implements Runnable { + public void run() { + // Lock: Locked Surface/Window by display _and_ MakeCurrent/Release + if (sendReshape) { + helper.reshape(GLWindow.this, 0, 0, getWidth(), getHeight()); + sendReshape = false; + } + + helper.display(GLWindow.this); + + curTime = System.currentTimeMillis(); + totalFrames++; + + if(perfLog) { + long dt0, dt1; + lastFrames++; + dt0 = curTime-lastCheck; + if ( dt0 > 5000 ) { + dt1 = curTime-startTime; + 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; + } + } + } + } + private DisplayAction displayAction = new DisplayAction(); + + /** + * @return Time of the first display call in milliseconds. + * This value is reset if becoming visible again or reparenting. + */ + public final long getStartTime() { + return startTime; + } + + /** + * @return Time of the last display call in milliseconds. + * This value is reset if becoming visible again or reparenting. + */ + public final long getCurrentTime() { + return curTime; + } + + /** + * @return Duration <code>getCurrentTime() - getStartTime()</code>. + * + * @see #getStartTime() + * @see #getCurrentTime() + */ + public final long getDuration() { + return getCurrentTime()-getStartTime(); + } + + /** + * @return Number of frames displayed since the first display call, ie <code>getStartTime()</code>. + * This value is reset if becoming visible again or reparenting. + */ + public final int getTotalFrames() { + return totalFrames; + } + + /** Reset all counter (startTime, currentTime, frame number) */ + public synchronized void resetCounter() { + startTime = System.currentTimeMillis(); // overwrite startTime to real init one + curTime = startTime; + lastCheck = startTime; + totalFrames = 0; lastFrames = 0; + } + + class SwapBuffersAction implements Runnable { + public void run() { + drawable.swapBuffers(); + } + } + private SwapBuffersAction swapBuffersAction = new SwapBuffersAction(); + + //---------------------------------------------------------------------- + // GLDrawable methods + // + + public final NativeSurface getNativeSurface() { + return null!=drawable ? drawable.getNativeSurface() : null; + } + + public final long getHandle() { + return null!=drawable ? drawable.getHandle() : 0; + } + + public final void destroy() { + window.destroy(); + } + + public final int getX() { + return window.getX(); + } + + public final int getY() { + return window.getY(); + } + + public final int getWidth() { + return window.getWidth(); + } + + public final int getHeight() { + return window.getHeight(); + } + + //---------------------------------------------------------------------- + // GLDrawable methods that are not really needed + // + + public final GLContext createContext(GLContext shareWith) { + return drawable.createContext(shareWith); + } + + public final void setRealized(boolean realized) { + } + + public final boolean isRealized() { + return ( null != drawable ) ? drawable.isRealized() : false; + } + + public final GLCapabilities getChosenGLCapabilities() { + if (drawable == null) { + throw new GLException("No drawable yet"); + } + + return drawable.getChosenGLCapabilities(); + } + + 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 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, NativeSurface ns, long when) { + window.surfaceUpdated(updater, ns, when); + } +} diff --git a/src/newt/classes/com/jogamp/newt/util/EDTUtil.java b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java new file mode 100644 index 000000000..d1a11a788 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/util/EDTUtil.java @@ -0,0 +1,115 @@ +/** + * 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.util; + +/** + * EDT stands for Event Dispatch Thread. + * <p> + * EDTUtil comprises the functionality of: + * <ul> + * <li> Periodically issuing an event dispatch command on the EDT.</li> + * <li> Ability to enqueue tasks, executed on the EDT.</li> + * <li> Controlling the EDT, ie start and stop in a sane manner.</li> + * </ul> + * The EDT pattern is a common tool to comply with todays windowing toolkits, + * where the common denominator in regards to multithreading is to: + * <ul> + * <li> Create a Window on one thread </li> + * <li> Modify the Window within the same thread </li> + * <li> Handle incoming events from within the same thread </li> + * </ul> + * Note: This is not true on MacOSX, where all these actions have to be + * performed by a unique, so called main thread.<br> + */ +public interface EDTUtil { + + public static final long defaultEDTPollGranularity = 10; // 10ms, 1/100s + + /** + * Create a new EDT. One should invoke <code>reset()</code><br> + * after <code>invokeStop(..)</code> in case another <code>start()</code> or <code>invoke(..)</code> + * is expected. + * + * @see #start() + * @see #invoke(boolean, java.lang.Runnable) + * @see #invokeStop(java.lang.Runnable) + */ + public void reset(); + + /** + * Start the EDT + */ + public void start(); + + /** + * @return True if the current thread is the EDT thread + */ + public boolean isCurrentThreadEDT(); + + /** + * @return True if EDT is running + */ + public boolean isRunning(); + + /** + * Append the final task to the EDT task queue, + * signals EDT to stop and wait until stopped.<br> + * Due to the nature of this method: + * <ul> + * <li>All previous queued tasks will be finished.</li> + * <li>No new tasks are allowed, an Exception is thrown.</li> + * <li>Can be issued from within EDT, ie from within an enqueued task.</li> + * <li>{@link #reset()} may follow immediately, ie creating a new EDT</li> + * </ul> + */ + public void invokeStop(Runnable finalTask); + + /** + * Append task to the EDT task queue.<br> + * Wait until execution is finished if <code>wait == true</code>.<br> + * Shall start the thread if not running.<br> + * Can be issued from within EDT, ie from within an enqueued task.<br> + * + * @throws RuntimeException in case EDT is stopped and not {@link #reset()} + */ + public void invoke(boolean wait, Runnable task); + + /** + * Wait until the EDT task queue is empty.<br> + * The last task may still be in execution when this method returns. + */ + public void waitUntilIdle(); + + /** + * Wait until EDT task is stopped.<br> + * No <code>stop</code> action is performed, {@link #invokeStop(java.lang.Runnable)} should be used before. + */ + public void waitUntilStopped(); +} + diff --git a/src/newt/classes/com/jogamp/newt/util/MainThread.java b/src/newt/classes/com/jogamp/newt/util/MainThread.java new file mode 100644 index 000000000..5b26cfbda --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/util/MainThread.java @@ -0,0 +1,419 @@ +/* + * Copyright (c) 2009 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. + * + * You acknowledge that this software is not designed or intended for use + * in the design, construction, operation or maintenance of any nuclear + * facility. + */ + +package com.jogamp.newt.util; + +import java.util.*; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.security.*; + +import javax.media.nativewindow.*; + +import com.jogamp.common.util.*; +import com.jogamp.newt.*; +import com.jogamp.newt.impl.*; + +/** + * NEWT Utility class MainThread<P> + * + * This class provides a startup singleton <i>main thread</i>, + * from which a new thread with the users main class is launched.<br> + * + * Such behavior is necessary for native windowing toolkits, + * where the windowing management must happen on the so called + * <i>main thread</i> e.g. for Mac OS X !<br> + * + * Utilizing this class as a launchpad, now you are able to + * use a NEWT multithreaded application with window handling within the different threads, + * even on these restricted platforms.<br> + * + * To support your NEWT Window platform, + * you have to pass your <i>main thread</i> actions to {@link #invoke invoke(..)}, + * have a look at the {@link com.jogamp.newt.macosx.MacWindow MacWindow} implementation.<br> + * <i>TODO</i>: Some hardcoded dependencies exist in this implementation, + * where you have to patch this code or factor it out. <P> + * + * If your platform is not Mac OS X, but you want to test your code without modifying + * this class, you have to set the system property <code>newt.MainThread.force</code> to <code>true</code>.<P> + * + * The code is compatible with all other platform, which support multithreaded windowing handling. + * Since those platforms won't trigger the <i>main thread</i> serialization, the main method + * will be simply executed, in case you haven't set <code>newt.MainThread.force</code> to <code>true</code>.<P> + * + * Test case on Mac OS X (or any other platform): + <PRE> + java -XstartOnFirstThread com.jogamp.newt.util.MainThread demos.es1.RedSquare -GL2 -GL2 -GL2 -GL2 + </PRE> + * Which starts 4 threads, each with a window and OpenGL rendering.<br> + */ +public class MainThread implements EDTUtil { + private static AccessControlContext localACC = AccessController.getContext(); + public static final boolean MAIN_THREAD_CRITERIA = ( !NativeWindowFactory.isAWTAvailable() && + NativeWindowFactory.TYPE_MACOSX.equals(NativeWindowFactory.getNativeWindowType(false)) + ) || Debug.getBooleanProperty("newt.MainThread.force", true, localACC); + + protected static final boolean DEBUG = Debug.debug("MainThread"); + + private static MainThread singletonMainThread = new MainThread(); // one singleton MainThread + + private static boolean isExit=false; + private static volatile boolean isRunning=false; + private static Object taskWorkerLock=new Object(); + private static boolean shouldStop; + private static ArrayList tasks; + private static Thread mainThread; + + private static Timer pumpMessagesTimer=null; + private static TimerTask pumpMessagesTimerTask=null; + private static Map/*<Display, Runnable>*/ pumpMessageDisplayMap = new HashMap(); + + private static boolean useMainThread = false; + private static Class cAWTEventQueue=null; + private static Method mAWTInvokeAndWait=null; + private static Method mAWTInvokeLater=null; + private static Method mAWTIsDispatchThread=null; + + static class MainAction extends Thread { + private String mainClassName; + private String[] mainClassArgs; + + private Class mainClass; + private Method mainClassMain; + + public MainAction(String mainClassName, String[] mainClassArgs) { + this.mainClassName=mainClassName; + this.mainClassArgs=mainClassArgs; + } + + public void run() { + if ( useMainThread ) { + // we have to start first to provide the service .. + singletonMainThread.waitUntilRunning(); + } + + // start user app .. + try { + Class mainClass = ReflectionUtil.getClass(mainClassName, true, getClass().getClassLoader()); + if(null==mainClass) { + throw new RuntimeException(new ClassNotFoundException("MainThread couldn't find main class "+mainClassName)); + } + try { + mainClassMain = mainClass.getDeclaredMethod("main", new Class[] { String[].class }); + mainClassMain.setAccessible(true); + } catch (Throwable t) { + throw new RuntimeException(t); + } + if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" invoke "+mainClassName); + mainClassMain.invoke(null, new Object[] { mainClassArgs } ); + } catch (InvocationTargetException ite) { + ite.getTargetException().printStackTrace(); + } catch (Throwable t) { + t.printStackTrace(); + } + + if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" user app fin"); + + if ( useMainThread ) { + singletonMainThread.invokeStop(new Runnable() { + public void run() { + // nop + }}); + if(DEBUG) System.err.println("MainAction.run(): "+Thread.currentThread().getName()+" MainThread fin - stop"); + System.exit(0); + } + } + } + private static MainAction mainAction; + + /** Your new java application main entry, which pipelines your application */ + public static void main(String[] args) { + useMainThread = MAIN_THREAD_CRITERIA; + + if(DEBUG) System.err.println("MainThread.main(): "+Thread.currentThread().getName()+" useMainThread "+ useMainThread ); + + if(args.length==0) { + return; + } + + String mainClassName=args[0]; + String[] mainClassArgs=new String[args.length-1]; + if(args.length>1) { + System.arraycopy(args, 1, mainClassArgs, 0, args.length-1); + } + + NEWTJNILibLoader.loadNEWT(); + + mainAction = new MainAction(mainClassName, mainClassArgs); + + if(NativeWindowFactory.TYPE_MACOSX.equals(NativeWindowFactory.getNativeWindowType(false))) { + ReflectionUtil.callStaticMethod("com.jogamp.newt.impl.macosx.MacDisplay", "initSingleton", + null, null, MainThread.class.getClassLoader()); + } + + if ( useMainThread ) { + shouldStop = false; + tasks = new ArrayList(); + mainThread = Thread.currentThread(); + + // dispatch user's main thread .. + mainAction.start(); + + // do our main thread task scheduling + singletonMainThread.run(); + } else { + // run user's main in this thread + mainAction.run(); + } + } + + public static final MainThread getSingleton() { + return singletonMainThread; + } + + public static Runnable removePumpMessage(Display dpy) { + synchronized(pumpMessageDisplayMap) { + return (Runnable) pumpMessageDisplayMap.remove(dpy); + } + } + + public static void addPumpMessage(Display dpy, Runnable pumpMessage) { + if ( useMainThread ) { + return; // error ? + } + if(null == pumpMessagesTimer) { + synchronized (MainThread.class) { + if(null == pumpMessagesTimer) { + pumpMessagesTimer = new Timer(); + pumpMessagesTimerTask = new TimerTask() { + public void run() { + synchronized(pumpMessageDisplayMap) { + for(Iterator i = pumpMessageDisplayMap.values().iterator(); i.hasNext(); ) { + ((Runnable) i.next()).run(); + } + } + } + }; + pumpMessagesTimer.scheduleAtFixedRate(pumpMessagesTimerTask, 0, defaultEDTPollGranularity); + } + } + } + synchronized(pumpMessageDisplayMap) { + pumpMessageDisplayMap.put(dpy, pumpMessage); + } + } + + private void initAWTReflection() { + if(null == cAWTEventQueue) { + ClassLoader cl = MainThread.class.getClassLoader(); + cAWTEventQueue = ReflectionUtil.getClass("java.awt.EventQueue", true, cl); + mAWTInvokeAndWait = ReflectionUtil.getMethod(cAWTEventQueue, "invokeAndWait", new Class[] { java.lang.Runnable.class }, cl); + mAWTInvokeLater = ReflectionUtil.getMethod(cAWTEventQueue, "invokeLater", new Class[] { java.lang.Runnable.class }, cl); + mAWTIsDispatchThread = ReflectionUtil.getMethod(cAWTEventQueue, "isDispatchThread", new Class[] { }, cl); + } + } + + public void reset() { + // nop + } + + public void start() { + // nop + } + + public boolean isCurrentThreadEDT() { + if(NativeWindowFactory.isAWTAvailable()) { + initAWTReflection(); + return ((Boolean) ReflectionUtil.callMethod(null, mAWTIsDispatchThread, null) ).booleanValue(); + } + return isRunning() && mainThread == Thread.currentThread() ; + } + + public boolean isRunning() { + if( useMainThread ) { + synchronized(taskWorkerLock) { + return isRunning; + } + } + return true; // AWT is always running + } + + private void invokeLater(Runnable task) { + synchronized(taskWorkerLock) { + if(isRunning() && mainThread != Thread.currentThread()) { + tasks.add(task); + taskWorkerLock.notifyAll(); + } else { + // if !running or isEDTThread, do it right away + task.run(); + } + } + } + + public void invokeStop(Runnable r) { + invokeImpl(true, r, true); + } + + public void invoke(boolean wait, Runnable r) { + invokeImpl(wait, r, false); + } + + private void invokeImpl(boolean wait, Runnable r, boolean stop) { + if(r == null) { + return; + } + + if(NativeWindowFactory.isAWTAvailable()) { + initAWTReflection(); + + // handover to AWT MainThread .. + try { + if ( ((Boolean) ReflectionUtil.callMethod(null, mAWTIsDispatchThread, null) ).booleanValue() ) { + r.run(); + return; + } + if(wait) { + ReflectionUtil.callMethod(null, mAWTInvokeAndWait, new Object[] { r }); + } else { + ReflectionUtil.callMethod(null, mAWTInvokeLater, new Object[] { r }); + } + } catch (Exception e) { + throw new NativeWindowException(e); + } + return; + } + + // if this main thread is not being used or + // if this is already the main thread .. just execute. + // FIXME: start if not started .. sync logic with DefaultEDTUtil!!! + if( !isRunning() || mainThread == Thread.currentThread() ) { + r.run(); + return; + } + + boolean doWait = wait && isRunning() && mainThread != Thread.currentThread(); + Object lock = new Object(); + RunnableTask rTask = new RunnableTask(r, doWait?lock:null, true); + Throwable throwable = null; + synchronized(lock) { + invokeLater(rTask); + // FIXME .. + synchronized(taskWorkerLock) { + if(isRunning) { + shouldStop = true; + if(DEBUG) System.err.println("MainThread.stop(): "+Thread.currentThread().getName()+" start"); + } + taskWorkerLock.notifyAll(); + } + if( doWait ) { + try { + lock.wait(); + } catch (InterruptedException ie) { + throwable = ie; + } + } + } + if(null==throwable) { + throwable = rTask.getThrowable(); + } + if(null!=throwable) { + throw new RuntimeException(throwable); + } + } + + public void waitUntilIdle() { + } + + public void waitUntilStopped() { + } + + private void waitUntilRunning() { + synchronized(taskWorkerLock) { + if(isExit) return; + + while(!isRunning) { + try { + taskWorkerLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + public void run() { + if(DEBUG) System.err.println("MainThread.run(): "+Thread.currentThread().getName()); + synchronized(taskWorkerLock) { + isRunning = true; + taskWorkerLock.notifyAll(); + } + while(!shouldStop) { + try { + // wait for something todo .. + synchronized(taskWorkerLock) { + while(!shouldStop && tasks.size()==0) { + try { + taskWorkerLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + // take over the tasks .. + if(!shouldStop && tasks.size()>0) { + Runnable task = (Runnable) tasks.remove(0); + task.run(); // FIXME: could be run outside of lock + } + taskWorkerLock.notifyAll(); + } + } catch (Throwable t) { + // handle errors .. + t.printStackTrace(); + } finally { + // epilog - unlock locked stuff + } + } + if(DEBUG) System.err.println("MainThread.run(): "+Thread.currentThread().getName()+" fin"); + synchronized(taskWorkerLock) { + isRunning = false; + isExit = true; + taskWorkerLock.notifyAll(); + } + } +} + + diff --git a/src/newt/classes/com/jogamp/newt/util/MonitorMode.java b/src/newt/classes/com/jogamp/newt/util/MonitorMode.java new file mode 100644 index 000000000..fb2d0ceb5 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/util/MonitorMode.java @@ -0,0 +1,109 @@ +/** + * 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.util; + +import javax.media.nativewindow.util.*; + +/** Immutable MonitorMode Class, consisting of it's read only components:<br> + * <ul> + * <li>{@link javax.media.nativewindow.util.SurfaceSize} surface memory size</li> + * <li>{@link javax.media.nativewindow.util.DimensionReadOnly} size in [mm]</li> + * <li><code>refresh rate</code></li> + * </ul> + */ +public class MonitorMode implements Cloneable { + SurfaceSize surfaceSize; + DimensionReadOnly screenSizeMM; // in [mm] + int refreshRate; + + public MonitorMode(SurfaceSize surfaceSize, DimensionReadOnly screenSizeMM, int refreshRate) { + if(null==surfaceSize || refreshRate<=0) { + throw new IllegalArgumentException("surfaceSize must be set and refreshRate greater 0"); + } + this.surfaceSize=surfaceSize; + this.screenSizeMM=screenSizeMM; + this.refreshRate=refreshRate; + } + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException ex) { + throw new InternalError(); + } + } + + public final SurfaceSize getSurfaceSize() { + return surfaceSize; + } + + public final DimensionReadOnly getScreenSizeMM() { + return screenSizeMM; + } + + public final int getRefreshRate() { + return refreshRate; + } + + public final String toString() { + return new String("[ "+surfaceSize+" x "+refreshRate+" Hz, "+screenSizeMM+" mm ]"); + } + + /** + * Checks whether two size objects are equal. Two instances + * of <code>MonitorMode</code> are equal if the three components + * <code>surfaceSize</code> and <code>refreshRate</code> + * are equal. <code>screenSizeMM</code> is kept out intentional to reduce the requirements for finding the current mode. + * @return <code>true</code> if the two dimensions are equal; + * otherwise <code>false</code>. + */ + public final boolean equals(Object obj) { + if (this == obj) { return true; } + if (obj instanceof MonitorMode) { + MonitorMode p = (MonitorMode)obj; + return getSurfaceSize().equals(p.getSurfaceSize()) && + /* getScreenSizeMM().equals(p.getScreenSizeMM()) && */ + getRefreshRate() == p.getRefreshRate() ; + } + return false; + } + + /** + * returns a hash code over <code>surfaceSize</code> and <code>refreshRate</code>. + * <code>screenSizeMM</code> is kept out intentional to reduce the requirements for finding the current mode. + */ + public final int hashCode() { + // 31 * x == (x << 5) - x + int hash = 31 + getSurfaceSize().hashCode(); + /* hash = ((hash << 5) - hash) + getScreenSizeMM().hashCode(); */ + hash = ((hash << 5) - hash) + getRefreshRate(); + return hash; + } +} + diff --git a/src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java b/src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java new file mode 100644 index 000000000..3e0e3dac5 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java @@ -0,0 +1,340 @@ +/** + * 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.util; + +import com.jogamp.common.util.ArrayHashSet; +import com.jogamp.newt.ScreenMode; +import java.util.ArrayList; +import java.util.List; +import javax.media.nativewindow.util.Dimension; +import javax.media.nativewindow.util.DimensionReadOnly; +import javax.media.nativewindow.util.SurfaceSize; + +/** + * Convenient {@link com.jogamp.newt.ScreenMode} utility methods, + * filters etc. + */ +public class ScreenModeUtil { + /** WARNING: must be synchronized with ScreenMode.h, native implementation + * 2: width and height + */ + public static final int NUM_RESOLUTION_PROPERTIES = 2; + + /** WARNING: must be synchronized with ScreenMode.h, native implementation + * 1: bpp + */ + public static final int NUM_SURFACE_SIZE_PROPERTIES = 1; + + /** WARNING: must be synchronized with ScreenMode.h, native implementation + * 3: ScreenSizeMM[width, height], refresh-rate + */ + public static final int NUM_MONITOR_MODE_PROPERTIES = 3; + + /** WARNING: must be synchronized with ScreenMode.h, native implementation + * 1: rotation, native_mode_id + */ + public static final int NUM_SCREEN_MODE_PROPERTIES = 1; + + /** WARNING: must be synchronized with ScreenMode.h, native implementation + * count + all the above + */ + public static final int NUM_SCREEN_MODE_PROPERTIES_ALL = 8; + + public static int getIndex(List/*<ScreenMode>*/ screenModes, ScreenMode search) { + return screenModes.indexOf(search); + } + + public static int getIndexByHashCode(List/*<ScreenMode>*/ screenModes, ScreenMode search) { + for (int i=0; null!=screenModes && i<screenModes.size(); i++) { + if ( search.hashCode() == ((ScreenMode)screenModes.get(i)).hashCode() ) { + return i; + } + } + return -1; + } + + /** + * @param screenModes + * @param resolution + * @return modes with nearest resolution, or matching ones + */ + public static List/*<ScreenMode>*/ filterByResolution(List/*<ScreenMode>*/ screenModes, DimensionReadOnly resolution) { + if(null==screenModes || screenModes.size()==0) { + return null; + } + List out = new ArrayList(); + int resolution_sq = resolution.getHeight()*resolution.getWidth(); + int sm_dsq=resolution_sq, sm_dsq_idx=0; + + for (int i=0; null!=screenModes && i<screenModes.size(); i++) { + ScreenMode sm = (ScreenMode)screenModes.get(i); + DimensionReadOnly res = sm.getMonitorMode().getSurfaceSize().getResolution(); + int dsq = Math.abs(resolution_sq - res.getHeight()*res.getWidth()); + if(dsq<sm_dsq) { + sm_dsq = dsq; + sm_dsq_idx = i; + } + if(res.equals(resolution)) { + out.add(sm); + } + } + if(out.size()>0) { + return out; + } + // nearest .. + resolution = ((ScreenMode)screenModes.get(sm_dsq_idx)).getMonitorMode().getSurfaceSize().getResolution(); + return filterByResolution(screenModes, resolution); + } + + public static List/*<ScreenMode>*/ filterBySurfaceSize(List/*<ScreenMode>*/ screenModes, SurfaceSize surfaceSize) { + if(null==screenModes || screenModes.size()==0) { + return null; + } + List out = new ArrayList(); + for (int i=0; null!=screenModes && i<screenModes.size(); i++) { + ScreenMode sm = (ScreenMode)screenModes.get(i); + if(sm.getMonitorMode().getSurfaceSize().equals(surfaceSize)) { + out.add(sm); + } + } + return out.size()>0 ? out : null; + } + + public static List/*<ScreenMode>*/ filterByRotation(List/*<ScreenMode>*/ screenModes, int rotation) { + if(null==screenModes || screenModes.size()==0) { + return null; + } + List out = new ArrayList(); + for (int i=0; null!=screenModes && i<screenModes.size(); i++) { + ScreenMode sm = (ScreenMode)screenModes.get(i); + if(sm.getRotation() == rotation) { + out.add(sm); + } + } + return out.size()>0 ? out : null; + } + + public static List/*<ScreenMode>*/ filterByBpp(List/*<ScreenMode>*/ screenModes, int bitsPerPixel) { + if(null==screenModes || screenModes.size()==0) { + return null; + } + List out = new ArrayList(); + for (int i=0; null!=screenModes && i<screenModes.size(); i++) { + ScreenMode sm = (ScreenMode)screenModes.get(i); + if(sm.getMonitorMode().getSurfaceSize().getBitsPerPixel() == bitsPerPixel) { + out.add(sm); + } + } + return out.size()>0 ? out : null; + } + + /** + * + * @param screenModes + * @param refreshRate + * @return modes with nearest refreshRate, or matching ones + */ + public static List/*<ScreenMode>*/ filterByRate(List/*<ScreenMode>*/ screenModes, int refreshRate) { + if(null==screenModes || screenModes.size()==0) { + return null; + } + int sm_dr = refreshRate; + int sm_dr_idx = -1; + List out = new ArrayList(); + for (int i=0; null!=screenModes && i<screenModes.size(); i++) { + ScreenMode sm = (ScreenMode)screenModes.get(i); + int dr = Math.abs(refreshRate - sm.getMonitorMode().getRefreshRate()); + if(dr<sm_dr) { + sm_dr = dr; + sm_dr_idx = i; + } + if(0 == dr) { + out.add(sm); + } + } + if(out.size()>0) { + return out; + } + refreshRate = ((ScreenMode)screenModes.get(sm_dr_idx)).getMonitorMode().getRefreshRate(); + return filterByRate(screenModes, refreshRate); + } + + public static List/*<ScreenMode>*/ getHighestAvailableBpp(List/*<ScreenMode>*/ screenModes) { + if(null==screenModes || screenModes.size()==0) { + return null; + } + int highest = -1; + for (int i=0; null!=screenModes && i < screenModes.size(); i++) { + ScreenMode sm = (ScreenMode)screenModes.get(i); + int bpp = sm.getMonitorMode().getSurfaceSize().getBitsPerPixel(); + if (bpp > highest) { + highest = bpp; + } + } + return filterByBpp(screenModes, highest); + } + + public static List/*<ScreenMode>*/ getHighestAvailableRate(List/*<ScreenMode>*/ screenModes) { + if(null==screenModes || screenModes.size()==0) { + return null; + } + int highest = -1; + for (int i=0; null!=screenModes && i < screenModes.size(); i++) { + ScreenMode sm = (ScreenMode)screenModes.get(i); + int rate = sm.getMonitorMode().getRefreshRate(); + if (rate > highest) { + highest = rate; + } + } + return filterByRate(screenModes, highest); + } + + /** WARNING: must be synchronized with ScreenMode.h, native implementation */ + public static DimensionReadOnly streamInResolution(int[] resolutionProperties, int offset) { + Dimension resolution = new Dimension(resolutionProperties[offset++], resolutionProperties[offset++]); + return resolution; + } + + /** WARNING: must be synchronized with ScreenMode.h, native implementation */ + public static SurfaceSize streamInSurfaceSize(DimensionReadOnly resolution, int[] sizeProperties, int offset) { + SurfaceSize surfaceSize = new SurfaceSize(resolution, sizeProperties[offset++]); + return surfaceSize; + } + + /** WARNING: must be synchronized with ScreenMode.h, native implementation */ + public static MonitorMode streamInMonitorMode(SurfaceSize surfaceSize, DimensionReadOnly screenSizeMM, int[] monitorProperties, int offset) { + int refreshRate = monitorProperties[offset++]; + return new MonitorMode(surfaceSize, screenSizeMM, refreshRate); + } + + /** WARNING: must be synchronized with ScreenMode.h, native implementation */ + public static ScreenMode streamInScreenMode(MonitorMode monitorMode, int[] modeProperties, int offset) { + int rotation = modeProperties[offset++]; + return new ScreenMode(monitorMode, rotation); + } + + /** + * WARNING: must be synchronized with ScreenMode.h, native implementation + * + * @param modeProperties the input data + * @param offset the offset to the input data + * @return index of the identical (old or new) ScreenMode element in <code>screenModePool</code>, + * matching the input <code>modeProperties</code>, or -1 if input could not be processed. + */ + public static ScreenMode streamIn(int[] modeProperties, int offset) { + return streamInImpl(null, null, null, null, null, modeProperties, offset); + } + + /** + * WARNING: must be synchronized with ScreenMode.h, native implementation + * + * @param resolutionPool hash array of unique DimensionReadOnly resolutions, no duplicates + * @param surfaceSizePool hash array of unique SurfaceSize, no duplicates + * @param monitorModePool hash array of unique MonitorMode, no duplicates + * @param screenModePool hash array of unique ScreenMode, no duplicates + * @param modeProperties the input data + * @param offset the offset to the input data + * @return index of the identical (old or new) ScreenMode element in <code>screenModePool</code>, + * matching the input <code>modeProperties</code>, or -1 if input could not be processed. + */ + public static int streamIn(ArrayHashSet resolutionPool, + ArrayHashSet surfaceSizePool, + ArrayHashSet screenSizeMMPool, + ArrayHashSet monitorModePool, + ArrayHashSet screenModePool, + int[] modeProperties, int offset) { + ScreenMode screenMode = streamInImpl(resolutionPool, surfaceSizePool, screenSizeMMPool, monitorModePool, screenModePool, + modeProperties, offset); + return screenModePool.indexOf(screenMode); + } + + private static ScreenMode streamInImpl(ArrayHashSet resolutionPool, + ArrayHashSet surfaceSizePool, + ArrayHashSet screenSizeMMPool, + ArrayHashSet monitorModePool, + ArrayHashSet screenModePool, + int[] modeProperties, int offset) { + int count = modeProperties[offset]; + if(NUM_SCREEN_MODE_PROPERTIES_ALL != count) { + throw new RuntimeException("NUM_SCREEN_MODE_PROPERTIES should be "+NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+count+", len "+(modeProperties.length-offset)); + } + if(NUM_SCREEN_MODE_PROPERTIES_ALL > modeProperties.length-offset) { + throw new RuntimeException("properties array too short, should be >= "+NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+(modeProperties.length-offset)); + } + offset++; + DimensionReadOnly resolution = ScreenModeUtil.streamInResolution(modeProperties, offset); + offset += ScreenModeUtil.NUM_RESOLUTION_PROPERTIES; + if(null!=resolutionPool) { + resolution = (DimensionReadOnly) resolutionPool.getOrAdd(resolution); + } + + SurfaceSize surfaceSize = ScreenModeUtil.streamInSurfaceSize(resolution, modeProperties, offset); + offset += ScreenModeUtil.NUM_SURFACE_SIZE_PROPERTIES; + if(null!=surfaceSizePool) { + surfaceSize = (SurfaceSize) surfaceSizePool.getOrAdd(surfaceSize); + } + + DimensionReadOnly screenSizeMM = ScreenModeUtil.streamInResolution(modeProperties, offset); + offset += ScreenModeUtil.NUM_RESOLUTION_PROPERTIES; + if(null!=screenSizeMMPool) { + screenSizeMM = (DimensionReadOnly) screenSizeMMPool.getOrAdd(screenSizeMM); + } + + MonitorMode monitorMode = ScreenModeUtil.streamInMonitorMode(surfaceSize, screenSizeMM, modeProperties, offset); + offset += ScreenModeUtil.NUM_MONITOR_MODE_PROPERTIES - ScreenModeUtil.NUM_RESOLUTION_PROPERTIES; + if(null!=monitorModePool) { + monitorMode = (MonitorMode) monitorModePool.getOrAdd(monitorMode); + } + + ScreenMode screenMode = ScreenModeUtil.streamInScreenMode(monitorMode, modeProperties, offset); + if(null!=screenModePool) { + screenMode = (ScreenMode) screenModePool.getOrAdd(screenMode); + } + return screenMode; + } + + /** WARNING: must be synchronized with ScreenMode.h, native implementation */ + public static int[] streamOut (ScreenMode screenMode) { + int[] data = new int[NUM_SCREEN_MODE_PROPERTIES_ALL]; + int idx=0; + data[idx++] = NUM_SCREEN_MODE_PROPERTIES_ALL; + data[idx++] = screenMode.getMonitorMode().getSurfaceSize().getResolution().getWidth(); + data[idx++] = screenMode.getMonitorMode().getSurfaceSize().getResolution().getHeight(); + data[idx++] = screenMode.getMonitorMode().getSurfaceSize().getBitsPerPixel(); + data[idx++] = screenMode.getMonitorMode().getScreenSizeMM().getWidth(); + data[idx++] = screenMode.getMonitorMode().getScreenSizeMM().getHeight(); + data[idx++] = screenMode.getMonitorMode().getRefreshRate(); + data[idx++] = screenMode.getRotation(); + if(NUM_SCREEN_MODE_PROPERTIES_ALL != idx) { + throw new InternalError("wrong number of attributes: got "+idx+" != should "+NUM_SCREEN_MODE_PROPERTIES_ALL); + } + return data; + } + +} |