diff options
Diffstat (limited to 'src/newt/classes/com')
22 files changed, 1851 insertions, 811 deletions
diff --git a/src/newt/classes/com/jogamp/newt/Display.java b/src/newt/classes/com/jogamp/newt/Display.java index b09f63962..7ce20e4bb 100644 --- a/src/newt/classes/com/jogamp/newt/Display.java +++ b/src/newt/classes/com/jogamp/newt/Display.java @@ -54,24 +54,69 @@ public abstract class Display { 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>. * - * @param v + * @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(); diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java index b57e34091..2cea88d19 100644 --- a/src/newt/classes/com/jogamp/newt/Screen.java +++ b/src/newt/classes/com/jogamp/newt/Screen.java @@ -25,13 +25,21 @@ * 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.List; import javax.media.nativewindow.AbstractGraphicsScreen; public interface 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"); boolean isNativeValid(); @@ -44,69 +52,106 @@ public interface Screen { void destroy(); + /** + * @return {@link Display#getDestroyWhenUnused()} + * + * @see #addReference() + * @see #removeReference() + * @see Display#setDestroyWhenUnused(boolean) + */ boolean getDestroyWhenUnused(); + /** + * calls {@link Display#setDestroyWhenUnused(boolean)}. + * + * @see #addReference() + * @see #removeReference() + * @see Display#setDestroyWhenUnused(boolean) + */ void setDestroyWhenUnused(boolean v); + /** + * See {@link Display#addReference()} + * + * @see #removeReference() + * @see #setDestroyWhenUnused(boolean) + * @see #getDestroyWhenUnused() + */ + int addReference(); + + /** + * See {@link Display#removeReference()} + * + * @see #addReference() + * @see #setDestroyWhenUnused(boolean) + * @see #getDestroyWhenUnused() + */ + int removeReference(); + AbstractGraphicsScreen getGraphicsScreen(); + /** + * @return this Screen index of all Screens of {@link #getDisplay()}. + */ int getIndex(); /** - * The actual implementation shall return the detected display value, - * if not we return 800. - * This can be overwritten with the user property 'newt.ws.swidth', + * @return the current screen width */ int getWidth(); /** - * The actual implementation shall return the detected display value, - * if not we return 480. - * This can be overwritten with the user property 'newt.ws.sheight', + * @return the current screen height */ int getHeight(); + /** + * @return the associated Display + */ Display getDisplay(); - - /** Get the screen fully qualified name - * which can be used to get the screen controller - * associated with this screen + + /** + * @return the screen fully qualified Screen name, + * which is a key of {@link com.jogamp.newt.Display#getFQName()} + {@link #getIndex()}. */ - String getScreenFQN(); - + String getFQName(); + /** - * Get the Current Desktop Screen mode index - * returns -1 if functionality not implemented - * for screen platform + * @param sml ScreenModeListener to be added for ScreenMode change events */ - int getDesktopScreenModeIndex(); - - /** Get the current screen rate - * returns -1 if not natively implemented + public void addScreenModeListener(ScreenModeListener sml); + + /** + * @param sml ScreenModeListener to be removed from ScreenMode change events */ - short getCurrentScreenRate(); - + public void removeScreenModeListener(ScreenModeListener sml); + /** - * Get list of available screen modes - * null if not implemented for screen platform + * 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()}. */ - ScreenMode[] getScreenModes(); - - /** - * change the screen mode - * @param modeIndex mode index from the list of available screen modes - * @param rate the desired rate should be one of the available rates. - */ - void setScreenMode(int modeIndex, short rate); - - /** Change the Screen Rotation to - * one of the rotations defined in ScreenMode - * @param rot rotation id, example ScreenMode.ROTATE_0 - */ - public void setScreenRotation(int rot); - - /** Get the Current screen rotation - * returns -1 if not implemented natively - */ - public int getCurrentScreenRotation(); + 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()}. + * + */ + 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()}. + */ + 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 + */ + boolean setCurrentScreenMode(ScreenMode screenMode); } diff --git a/src/newt/classes/com/jogamp/newt/ScreenMode.java b/src/newt/classes/com/jogamp/newt/ScreenMode.java index f37652a23..8fb5aabb8 100644 --- a/src/newt/classes/com/jogamp/newt/ScreenMode.java +++ b/src/newt/classes/com/jogamp/newt/ScreenMode.java @@ -1,76 +1,179 @@ +/** + * 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; -public class ScreenMode { - public static final int ROTATE_0 = 0; - public static final int ROTATE_90 = 90; - public static final int ROTATE_180 = 180; - public static final int ROTATE_270 = 270; - - private int index; - private int width; - private int height; - private int bitsPerPixel = -1; - - private short[] rates = null; - - public ScreenMode(int index, int width, int height) { - this.index = index; - this.width = width; - this.height = height; - } - /** Not safe to use this on platforms - * other than windows. Since the mode ids - * on X11 match the native ids. unlike windows - * where the ids are generated . - * @param index - */ - public void setIndex(int index) { - this.index = index; - } - public int getIndex() { - return index; - } - public int getWidth() { - return width; - } - public void setWidth(int width) { - this.width = width; - } - public int getHeight() { - return height; - } - public void setHeight(int height) { - this.height = height; - } - public short[] getRates() { - return rates; - } - public void setRates(short[] rates) { - this.rates = rates; - } - - public int getBitsPerPixel() { - return bitsPerPixel; - } - - public void setBitsPerPixel(int bitsPerPixel) { - this.bitsPerPixel = bitsPerPixel; - } - - public short getHighestAvailableRate(){ - short highest = rates[0]; - if(rates.length > 1){ - for (int i = 1; i < rates.length; i++) { - if(rates[i] > highest){ - highest = rates[i]; - } - } - } - return highest; - } - - public String toString() { - return "ScreenMode: " + this.index + " - " + this.width + " x " - + this.height + " " + getHighestAvailableRate() + " Hz"; - } +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}</li> + * <li><code>rotation</code></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 { + public static final int ROTATE_0 = 0; + public static final int ROTATE_90 = 90; + public static final int ROTATE_180 = 180; + 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 + */ + 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(); + } + } + + public final MonitorMode getMonitorMode() { + return monitorMode; + } + + public final int getRotation() { + return rotation; + } + + public final String toString() { + return "ScreenMode[" + 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 (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 index 7e1a55b21..1be5949fe 100644 --- a/src/newt/classes/com/jogamp/newt/Window.java +++ b/src/newt/classes/com/jogamp/newt/Window.java @@ -31,6 +31,7 @@ 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; @@ -42,7 +43,7 @@ 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 { +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"); 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/impl/DefaultEDTUtil.java b/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java index ce204cd25..0fdfd44fe 100644 --- a/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java +++ b/src/newt/classes/com/jogamp/newt/impl/DefaultEDTUtil.java @@ -64,8 +64,10 @@ public class DefaultEDTUtil implements EDTUtil { waitUntilStopped(); if(DEBUG) { if(edt.tasks.size()>0) { - Throwable t = new Throwable("Warning: EDT reset, remaining tasks: "+edt.tasks.size()+" - "+edt); - t.printStackTrace(); + 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); } @@ -75,7 +77,7 @@ public class DefaultEDTUtil implements EDTUtil { public final void start() { synchronized(edtLock) { - if(!edt.isRunning()) { + if(!edt.isRunning() && !edt.shouldStop) { if(edt.isAlive()) { throw new RuntimeException("EDT Thread.isAlive(): true, isRunning: "+edt.isRunning()+", edt: "+edt+", tasks: "+edt.tasks.size()); } @@ -83,7 +85,10 @@ public class DefaultEDTUtil implements EDTUtil { edt.setName(name+start_iter); edt.shouldStop = false; if(DEBUG) { - System.err.println(Thread.currentThread()+": EDT START - edt: "+edt); + String msg = Thread.currentThread()+": EDT START - edt: "+edt; + System.err.println(msg); + // Throwable t = new Throwable(msg); + // t.printStackTrace(); } edt.start(); } @@ -128,8 +133,10 @@ public class DefaultEDTUtil implements EDTUtil { if(stop) { edt.shouldStop = true; if(DEBUG) { - System.err.println(Thread.currentThread()+ - ": EDT signal STOP (on edt: "+isCurrentThreadEDT()+") - edt: "+edt); + 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() ) { @@ -140,14 +147,15 @@ public class DefaultEDTUtil implements EDTUtil { t.printStackTrace(); } } else { - start(); // start if not started yet - rTask = new RunnableTask(task, - wait ? rTaskLock : null, - wait /* catch Exceptions if waiting for result */); - if(stop) { - rTask.setAttachment(new Boolean(true)); // mark final task - } synchronized(edt.tasks) { + start(); // start if not started yet and !shouldStop + wait = wait && edt.isRunning(); + rTask = new RunnableTask(task, + wait ? rTaskLock : null, + wait /* catch Exceptions if waiting for result */); + if(stop) { + rTask.setAttachment(new Boolean(true)); // mark final task + } // append task .. edt.tasks.add(rTask); edt.tasks.notifyAll(); @@ -178,6 +186,7 @@ public class DefaultEDTUtil implements EDTUtil { synchronized(edt.tasks) { while(edt.isRunning() && edt.tasks.size()>0) { try { + edt.tasks.notifyAll(); edt.tasks.wait(); } catch (InterruptedException e) { e.printStackTrace(); @@ -190,11 +199,13 @@ public class DefaultEDTUtil implements EDTUtil { public void waitUntilStopped() { if(edt.isRunning() && edt != Thread.currentThread() ) { synchronized(edtLock) { - while(edt.isRunning()) { - try { - edtLock.wait(); - } catch (InterruptedException e) { - e.printStackTrace(); + if(edt.isRunning() && edt != Thread.currentThread() ) { + while(edt.isRunning()) { + try { + edtLock.wait(); + } catch (InterruptedException e) { + e.printStackTrace(); + } } } } diff --git a/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java b/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java index 840411984..30b3cc409 100644 --- a/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java +++ b/src/newt/classes/com/jogamp/newt/impl/DisplayImpl.java @@ -81,7 +81,7 @@ public abstract class DisplayImpl extends Display { display.refCount=0; synchronized(displayList) { display.id = serialno++; - display.fqname = getFQName(display.id, display.type, display.name); + display.fqname = getFQName(display.type, display.name, display.id); displayList.add(display); } display.createEDTUtil(); @@ -191,7 +191,7 @@ public abstract class DisplayImpl extends Display { } } - protected synchronized final int addReference() { + public synchronized final int addReference() { if(DEBUG) { System.err.println("Display.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1)); } @@ -205,7 +205,7 @@ public abstract class DisplayImpl extends Display { } - protected synchronized final int removeReference() { + public synchronized final int removeReference() { if(DEBUG) { System.err.println("Display.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); } @@ -251,7 +251,7 @@ public abstract class DisplayImpl extends Display { return ( null == name ) ? nilString : name ; } - public static final String getFQName(int id, String type, String 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(); diff --git a/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java index 37a751fe1..9dc1c1bcc 100644 --- a/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java +++ b/src/newt/classes/com/jogamp/newt/impl/ScreenImpl.java @@ -34,259 +34,429 @@ 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.*; +import com.jogamp.newt.Window; +import com.jogamp.newt.event.ScreenModeListener; +import com.jogamp.newt.util.ScreenModeUtil; import javax.media.nativewindow.*; import java.security.*; - -public abstract class ScreenImpl implements Screen { - protected DisplayImpl display; - protected int idx; - protected AbstractGraphicsScreen aScreen; - protected int refCount; // number of Screen references by Window - protected int width=-1, height=-1; // detected values: set using setScreenSize - protected static int usrWidth=-1, usrHeight=-1; // property values: newt.ws.swidth and newt.ws.sheight - private static AccessControlContext localACC = AccessController.getContext(); - - - protected static ScreensModeState screensModeState = new ScreensModeState(); // hold all screen mode controllers - private String screenFQN = null; // string fully qualified name - - private static Class getScreenClass(String type) - throws ClassNotFoundException - { - Class screenClass = NewtFactory.getCustomClass(type, "Screen"); - if(null==screenClass) { - if (NativeWindowFactory.TYPE_EGL.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.opengl.kd.KDScreen"); - } else if (NativeWindowFactory.TYPE_WINDOWS.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.windows.WindowsScreen"); - } else if (NativeWindowFactory.TYPE_MACOSX.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.macosx.MacScreen"); - } else if (NativeWindowFactory.TYPE_X11.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.x11.X11Screen"); - } else if (NativeWindowFactory.TYPE_AWT.equals(type)) { - screenClass = Class.forName("com.jogamp.newt.impl.awt.AWTScreen"); - } else { - throw new RuntimeException("Unknown window type \"" + type + "\""); - } - } - return screenClass; - } - - public static ScreenImpl create(String type, Display display, final int idx) { - try { - if(usrWidth<0 || usrHeight<0) { - usrWidth = Debug.getIntProperty("newt.ws.swidth", true, localACC); - usrHeight = Debug.getIntProperty("newt.ws.sheight", true, localACC); - if(usrWidth>0 || usrHeight>0) { - System.err.println("User screen size "+usrWidth+"x"+usrHeight); - } - } - Class screenClass = getScreenClass(type); - ScreenImpl screen = (ScreenImpl) screenClass.newInstance(); - screen.display = (DisplayImpl) display; - screen.idx = idx; - - return screen; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - protected synchronized final void createNative() { - if(null == aScreen) { - if(DEBUG) { - System.err.println("Screen.createNative() START ("+DisplayImpl.getThreadName()+", "+this+")"); - } - display.addReference(); - createNativeImpl(); - if(null == aScreen) { - throw new RuntimeException("Screen.createNative() failed to instanciate an AbstractGraphicsScreen"); - } - if(DEBUG) { - System.err.println("Screen.createNative() END ("+DisplayImpl.getThreadName()+", "+this+")"); - } - } - - initScreenModes(); - } - - /** Retrieve screen modes - * and screen rate initializing the status - * of the screen mode - */ - private void initScreenModes(){ - ScreenMode[] screenModes = getScreenModes(); - String screenFQN = display.getFQName()+idx; - setScreenFQN(screenFQN); - ScreenModeStatus screenModeStatus = new ScreenModeStatus(screenFQN , - getDesktopScreenModeIndex(), getCurrentScreenRate(),getCurrentScreenRotation()); - screenModeStatus.setScreenModes(screenModes); - - screensModeState.setScreenModeController(screenModeStatus); - } - - private void resetScreenMode() { - ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN()); - - /**Revert the screen mode and rate - * to original state of creation - */ - if(!sms.isOriginalMode()) { - setScreenMode(sms.getOriginalScreenMode(), - sms.getOriginalScreenRate()); - } - /**Revert Screen Rotation - * to original value - */ - if(!sms.isOriginalRotation()) { - setScreenRotation(sms.getOriginalScreenRotation()); - } - } - - public synchronized final void destroy() { - resetScreenMode(); - - if ( null != aScreen ) { - closeNativeImpl(); - aScreen = null; - } - refCount = 0; - display.removeReference(); - } - - protected synchronized final int addReference() { - if(DEBUG) { - System.err.println("Screen.addReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount+1)); - } - if ( 0 == refCount ) { - createNative(); - } - if(null == aScreen) { - throw new RuntimeException("Screen.addReference() (refCount "+refCount+") null AbstractGraphicsScreen"); - } - return ++refCount; - } - - protected synchronized final int removeReference() { - if(DEBUG) { - System.err.println("Screen.removeReference() ("+DisplayImpl.getThreadName()+"): "+refCount+" -> "+(refCount-1)); - } - refCount--; // 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 int getDesktopScreenModeIndex() { - ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN()); - if(sms != null){ - return sms.getCurrentScreenMode(); - } - return -1; - } - - /** - * Get list of available screen modes - * null if not implemented for screen platform - */ - public ScreenMode[] getScreenModes(){ - ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN()); - if(sms != null) { - return sms.getScreenModes(); - } - return null; - } - - public void setScreenMode(int modeIndex, short rate) { - } - - public short getCurrentScreenRate() { - ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN()); - if(sms != null){ - return sms.getCurrentScreenRate(); - } - return -1; - } - - - public void setScreenRotation(int rot) { - - } - - public int getCurrentScreenRotation() { - ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN()); - if(sms != null) { - return sms.getCurrentScreenRotation(); - } - return -1; - } - - /** get the screens mode state handler - * which contain the screen mode controller of each screen - * @return the ScreensModeState static object - */ - protected ScreensModeState getScreensModeState() { - return screensModeState; - } - - public String getScreenFQN() { - return screenFQN; - } - - private void setScreenFQN(String screenFQN) { - this.screenFQN = screenFQN; - } - - protected void setScreenSize(int w, int h) { - System.err.println("Detected screen size "+w+"x"+h); - width=w; height=h; - } - - public final Display getDisplay() { - return display; - } - - public final int getIndex() { - return idx; - } - - public final AbstractGraphicsScreen getGraphicsScreen() { - return aScreen; - } - - public final boolean isNativeValid() { - return null != aScreen; - } - - public final int getWidth() { - return (usrWidth>0) ? usrWidth : (width>0) ? width : 480; - } - - public final int getHeight() { - return (usrHeight>0) ? usrHeight : (height>0) ? height : 480; - } - - public String toString() { - return "NEWT-Screen[idx "+idx+", refCount "+refCount+", "+getWidth()+"x"+getHeight()+", "+aScreen+", "+display+"]"; - } +import java.util.ArrayList; +import java.util.List; + +public abstract class ScreenImpl implements Screen, ScreenModeListener { + protected DisplayImpl display; + protected int screen_idx; + protected String fqname; + 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 ScreenImpl create(String type, Display display, final int idx) { + try { + if(usrWidth<0 || usrHeight<0) { + usrWidth = Debug.getIntProperty("newt.ws.swidth", true, localACC); + usrHeight = Debug.getIntProperty("newt.ws.sheight", true, localACC); + if(usrWidth>0 || usrHeight>0) { + System.err.println("User screen size "+usrWidth+"x"+usrHeight); + } + } + Class screenClass = getScreenClass(type); + ScreenImpl screen = (ScreenImpl) screenClass.newInstance(); + screen.display = (DisplayImpl) display; + screen.screen_idx = idx; + screen.fqname = display.getFQName()+idx; + return screen; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + protected synchronized final void createNative() { + if(null == aScreen) { + if(DEBUG) { + System.err.println("Screen.createNative() START ("+DisplayImpl.getThreadName()+", "+this+")"); + } + 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+")"); + } + } + initScreenModeStatus(); + } + + public synchronized final void destroy() { + releaseScreenModeStatus(); + + 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) { + 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 = 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> + * Is called only to collect the ScreenModes, usually at startup setting up modes.<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 = getCurrentScreenModeImpl(); + if(null == originalScreenMode) { + throw new RuntimeException("Couldn't fetch current ScreenMode (null), but ScreenMode list size is: "+screenModes.size()); + } + sms.setOriginalScreenMode(originalScreenMode); + } + ScreenModeStatus.mapScreenModeStatus(this.getFQName(), sms); + } + sms.addListener(this); + } finally { + ScreenModeStatus.unlockScreenModeStatus(); + } + } + + 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; + do { + if(0 == num) { + smProps = getScreenModeFirstImpl(); + } else { + smProps = getScreenModeNextImpl(); + } + if(null != smProps) { + 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 ); + + ScreenModeUtil.validate(screenModePool, true); + + 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 index 94d3eb4e6..3ca9b638b 100644 --- a/src/newt/classes/com/jogamp/newt/impl/ScreenModeStatus.java +++ b/src/newt/classes/com/jogamp/newt/impl/ScreenModeStatus.java @@ -1,91 +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 String screenFQN = null; - private ScreenMode[] screenModes = null; - - private int currentScreenMode = -1; - private short currentScreenRate = -1; - private int currentScreenRotation = -1; - - private int originalScreenMode = -1; - private short originalScreenRate = -1; - private int originalScreenRotation = -1; - - public ScreenModeStatus(String screenFQN, int originalScreenMode, - short originalScreenRate, int originalScreenRotation) { - this.screenFQN = screenFQN; - this.originalScreenMode = originalScreenMode; - this.originalScreenRate = originalScreenRate; - this.originalScreenRotation = originalScreenRotation; - - this.currentScreenMode = originalScreenMode; - this.currentScreenRate = originalScreenRate; - this.currentScreenRotation = originalScreenRotation; - } - - public void setCurrentScreenRotation(int currentScreenRotation) { - this.currentScreenRotation = currentScreenRotation; - } - - public int getCurrentScreenRotation() { - return currentScreenRotation; - } - - public int getOriginalScreenRotation() { - return originalScreenRotation; - } - - public int getCurrentScreenMode() { - return currentScreenMode; - } - - public void setCurrentScreenMode(int currentScreenMode) { - this.currentScreenMode = currentScreenMode; - } - - public short getCurrentScreenRate() { - return currentScreenRate; - } - - public void setCurrentScreenRate(short currentRate) { - this.currentScreenRate = currentRate; - } - - public String getScreenFQN() { - return screenFQN; - } - - public void setScreenFQN(String screenFQN) { - this.screenFQN = screenFQN; - } - - public ScreenMode[] getScreenModes() { - return screenModes; - } - - public void setScreenModes(ScreenMode[] screenModes) { - this.screenModes = screenModes; - } - public boolean isOriginalMode(){ - if(currentScreenMode == originalScreenMode - && currentScreenRate == originalScreenRate) - return true; - return false; - } - public boolean isOriginalRotation(){ - if(currentScreenRotation == originalScreenRotation) - return true; - return false; - } - - public int getOriginalScreenMode() { - return originalScreenMode; - } - - public short getOriginalScreenRate() { - return originalScreenRate; - } + 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/ScreensModeState.java b/src/newt/classes/com/jogamp/newt/impl/ScreensModeState.java deleted file mode 100644 index e4291496d..000000000 --- a/src/newt/classes/com/jogamp/newt/impl/ScreensModeState.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.jogamp.newt.impl; - -import java.util.HashMap; - -public class ScreensModeState { - private static HashMap screenModes = new HashMap(); - private static Object lock = new Object(); - - public ScreensModeState(){ - - } - public synchronized void setScreenModeController(ScreenModeStatus screenModeStatus){ - synchronized (lock) { - screenModes.put(screenModeStatus.getScreenFQN(), screenModeStatus); - } - } - - public synchronized ScreenModeStatus getScreenModeController(String screenFQN){ - return (ScreenModeStatus) screenModes.get(screenFQN); - } -} diff --git a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java index 631c1b1c0..f9383ea38 100644 --- a/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java +++ b/src/newt/classes/com/jogamp/newt/impl/WindowImpl.java @@ -43,14 +43,16 @@ import com.jogamp.newt.event.*; import com.jogamp.common.util.*; import javax.media.nativewindow.*; import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.newt.ScreenMode; import java.util.ArrayList; import java.lang.reflect.Method; +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 +public abstract class WindowImpl implements Window, NEWTEventConsumer, ScreenModeListener { public static final boolean DEBUG_TEST_REPARENT_INCOMPATIBLE = Debug.isPropertyDefined("newt.test.Window.reparent.incompatible", true); @@ -178,9 +180,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer private boolean handleDestroyNotify = true; private final void destroyScreen() { - screenReferenced = false; if(null!=screen) { - screen.removeReference(); + if(screenReferenced) { + screen.removeReference(); + screenReferenced = false; + } screen = null; } } @@ -208,6 +212,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } createNativeImpl(); setVisibleImpl(true, x, y, width, height); + screen.addScreenModeListener(this); } } finally { if(null!=parentWindow) { @@ -461,11 +466,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer class VisibleAction implements Runnable { boolean visible; + long timeOut; boolean nativeWindowCreated; boolean madeVisible; - public VisibleAction (boolean visible) { + public VisibleAction (boolean visible, long timeOut) { this.visible = visible; + this.timeOut = timeOut; this.nativeWindowCreated = false; this.madeVisible = false; } @@ -494,13 +501,13 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer if(0==windowHandle && visible) { if( 0<width*height ) { nativeWindowCreated = createNative(); - WindowImpl.this.waitForVisible(visible, true); + WindowImpl.this.waitForVisible(visible, true, timeOut); madeVisible = visible; } } else if(WindowImpl.this.visible != visible) { if(0 != windowHandle) { setVisibleImpl(visible, x, y, width, height); - WindowImpl.this.waitForVisible(visible, true); + WindowImpl.this.waitForVisible(visible, true, timeOut); madeVisible = visible; } } @@ -529,12 +536,17 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } public void setVisible(boolean visible) { + setVisible(visible, TIMEOUT_NATIVEWINDOW); + + } + + protected final void setVisible(boolean visible, long timeOut) { 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); + VisibleAction visibleAction = new VisibleAction(visible, timeOut); runOnEDTIfAvail(true, visibleAction); if( visibleAction.getChanged() ) { sendWindowEvent(WindowEvent.EVENT_WINDOW_RESIZED); // trigger a resize/relayout and repaint to listener @@ -647,6 +659,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer keyListeners = new ArrayList(); } if( null != screen && 0 != windowHandle ) { + screen.removeScreenModeListener(WindowImpl.this); closeNativeImpl(); } invalidate(unrecoverable); @@ -666,7 +679,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer System.err.println(msg); //Exception ee = new Exception(msg); //ee.printStackTrace(); - } + } DestroyAction destroyAction = new DestroyAction(unrecoverable); runOnEDTIfAvail(true, destroyAction); } @@ -932,11 +945,15 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer setVisibleImpl(true, x, y, width, height); ok = WindowImpl.this.waitForVisible(true, false); display.dispatchMessagesNative(); // status up2date - if( WindowImpl.this.x != x || - WindowImpl.this.y != y || - WindowImpl.this.width != width || - WindowImpl.this.height != height ) + 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 @@ -1343,23 +1360,46 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer h = nfs_height; } if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { - System.err.println("X11Window fs: "+fullscreen+" "+x+"/"+y+" "+w+"x"+h+", "+isUndecorated()+", "+screen); + 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); + WindowImpl.this.waitForVisible(false, true, Screen.SCREEN_MODE_CHANGE_TIMEOUT); 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); - WindowImpl.this.waitForVisible(true, true); + 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 { @@ -1377,6 +1417,45 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer return this.fullscreen; } + boolean screenModeChangeVisible; + boolean screenModeChangeFullscreen; + + public void screenModeChangeNotify(ScreenMode sm) { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("Window.screenModeChangeNotify: "+sm); + } + screenModeChangeFullscreen = isFullscreen(); + if(screenModeChangeFullscreen) { + setFullscreen(false); + } + screenModeChangeVisible = isVisible(); + if(screenModeChangeVisible) { + setVisible(false); + } + windowLock.lock(); + } + + public void screenModeChanged(ScreenMode sm, boolean success) { + if(DEBUG_IMPLEMENTATION || DEBUG_WINDOW_EVENT) { + System.err.println("Window.screenModeChanged: "+sm+", success: "+success); + } + windowLock.unlock(); + + if(success) { + DimensionReadOnly screenSize = sm.getMonitorMode().getSurfaceSize().getResolution(); + if ( getHeight() > screenSize.getHeight() || + getWidth() > screenSize.getWidth() ) { + setSize(screenSize.getWidth(), screenSize.getHeight()); + } + } + if(screenModeChangeFullscreen) { + setFullscreen(true); + } + if(screenModeChangeVisible) { + setVisible(true, Screen.SCREEN_MODE_CHANGE_TIMEOUT); + } + } + //---------------------------------------------------------------------- // Child Window Management // @@ -1866,8 +1945,12 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } 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_NATIVEWINDOW; 0<sleep && this.visible != visible; sleep-=10 ) { + for(long sleep = timeOut; 0<sleep && this.visible != visible; sleep-=10 ) { display.dispatchMessagesNative(); // status up2date try { Thread.sleep(10); @@ -1876,9 +1959,9 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer } if(this.visible != visible) { if(failFast) { - throw new NativeWindowException("Visibility not reached as requested within "+TIMEOUT_NATIVEWINDOW+"ms : requested "+visible+", is "+this.visible); + 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_NATIVEWINDOW+"ms : requested "+visible+", is "+this.visible); + System.err.println("******* Visibility not reached as requested within "+timeOut+"ms : requested "+visible+", is "+this.visible); } } return this.visible == visible; @@ -1937,16 +2020,17 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer // Exception ee = new Exception("Window.windowRepaint: "+" - "+x+"/"+y+" "+width+"x"+height); // ee.printStackTrace(); } - if(0>width) { - width=this.width; - } - if(0>height) { - height=this.height; - } - NEWTEvent e = new WindowUpdateEvent(WindowEvent.EVENT_WINDOW_REPAINT, this, System.currentTimeMillis(), - new Rectangle(x, y, width, height)); if(isNativeValid()) { + 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); } } diff --git a/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java b/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java index eaf758b2d..5e097fdc3 100644 --- a/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java +++ b/src/newt/classes/com/jogamp/newt/impl/awt/AWTScreen.java @@ -62,5 +62,4 @@ public class AWTScreen extends ScreenImpl { } protected void closeNativeImpl() { } - } 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 index c5253e142..4abee350f 100644 --- a/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java +++ b/src/newt/classes/com/jogamp/newt/impl/intel/gdl/Screen.java @@ -47,8 +47,8 @@ public class Screen extends com.jogamp.newt.impl.ScreenImpl { protected void createNativeImpl() { AbstractGraphicsDevice adevice = getDisplay().getGraphicsDevice(); - GetScreenInfo(adevice.getHandle(), idx); - aScreen = new DefaultGraphicsScreen(adevice, idx); + GetScreenInfo(adevice.getHandle(), screen_idx); + aScreen = new DefaultGraphicsScreen(adevice, screen_idx); } protected void closeNativeImpl() { } diff --git a/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java b/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java index 21018b2be..f0c388366 100644 --- a/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java +++ b/src/newt/classes/com/jogamp/newt/impl/macosx/MacScreen.java @@ -46,8 +46,8 @@ public class MacScreen extends ScreenImpl { } protected void createNativeImpl() { - aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), idx); - setScreenSize(getWidthImpl0(idx), getHeightImpl0(idx)); + aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); + setScreenSize(getWidthImpl0(screen_idx), getHeightImpl0(screen_idx)); } protected void closeNativeImpl() { } 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 index 50fdf92e5..144fe5e83 100644 --- 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 @@ -46,7 +46,7 @@ public class Screen extends com.jogamp.newt.impl.ScreenImpl { } protected void createNativeImpl() { - aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), idx); + aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); setScreenSize(fixedWidth, fixedHeight); } 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 index a814f15b5..1a73d0e5d 100644 --- a/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java +++ b/src/newt/classes/com/jogamp/newt/impl/opengl/kd/KDScreen.java @@ -46,7 +46,7 @@ public class KDScreen extends ScreenImpl { } protected void createNativeImpl() { - aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), idx); + aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); } protected void closeNativeImpl() { } diff --git a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java index 04ffbe11d..d35021605 100644 --- a/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java +++ b/src/newt/classes/com/jogamp/newt/impl/windows/WindowsScreen.java @@ -30,182 +30,80 @@ * 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(), idx); - setScreenSize(getWidthImpl0(idx), getHeightImpl0(idx)); + aScreen = new DefaultGraphicsScreen(getDisplay().getGraphicsDevice(), screen_idx); + setScreenSize(getWidthImpl0(screen_idx), getHeightImpl0(screen_idx)); } - protected void closeNativeImpl() { } - - public int getDesktopScreenModeIndex() { - int index = super.getDesktopScreenModeIndex(); - if(index == -1) { - /** Set the current screen mode to refering to index zero - * dependent on the impl of getScreenModes which saves the - * current screen mode at index 0 which is the original screen mode - */ - ScreenMode[] screenModes = getScreenModes(); - if(screenModes != null) { - if(screenModes[0] != null) { - index = screenModes[0].getIndex(); - } - } - } - return index; + protected void closeNativeImpl() { } - - public void setScreenMode(int modeIndex, short rate) { - ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN()); - ScreenMode[] screenModes = sms.getScreenModes(); - - short selectedRate = rate; - int selectedMode = modeIndex; - - if(modeIndex < 0 || (modeIndex > screenModes.length)){ - selectedMode = sms.getOriginalScreenMode(); - } - ScreenMode sm = screenModes[selectedMode]; - - if(selectedRate == -1){ - selectedRate = sms.getOriginalScreenRate(); - } - - boolean rateAvailable = false; - short[] rates = sm.getRates(); - for(int i=0;i<rates.length;i++){ - if(rates[i] == selectedRate){ - rateAvailable = true; - break; - } - } - if(!rateAvailable){ - selectedRate = rates[0]; - } - - if(0 == setScreenMode0(idx, sm.getWidth(), sm.getHeight(), sm.getBitsPerPixel(), selectedRate)){ - sms.setCurrentScreenMode(selectedMode); - sms.setCurrentScreenRate(selectedRate); - } + + private int[] getScreenModeIdx(int idx) { + int[] modeProps = getScreenMode0(screen_idx, idx); + if (null == modeProps) { + return null; + } + if(modeProps.length != ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL + 1) { + throw new RuntimeException("properties array too short, should be >= "+ScreenModeUtil.NUM_SCREEN_MODE_PROPERTIES_ALL+", is "+modeProps.length); + } + return modeProps; } - - public short getCurrentScreenRate() { - short rate = super.getCurrentScreenRate(); - if(rate == -1){ - rate = (short)getCurrentScreenRate0(idx); - } - return rate; - } - - public ScreenMode[] getScreenModes() { - ScreenMode[] screenModes = super.getScreenModes(); - if(screenModes == null) { - ArrayList smTemp = new ArrayList(); - - int modeID = -1; - ScreenMode mySM = getScreenMode(modeID++); - int currentBitsPerPixel = mySM.getBitsPerPixel(); - while(mySM != null){ - //filter out modes with diff bits per pixel - if(mySM.getBitsPerPixel() == currentBitsPerPixel) { - smTemp.add(mySM); - } - mySM = getScreenMode(modeID++); - } - int numModes = smTemp.size(); - if(numModes > 0) { - screenModes = new ScreenMode[numModes]; - for(int i=0;i<numModes;i++) { - ScreenMode sm = (ScreenMode)smTemp.get(i); - sm.setIndex(i); - screenModes[i] = sm; - } - } - } - return screenModes; + + private int nativeModeIdx; + + protected int[] getScreenModeFirstImpl() { + nativeModeIdx = 0; + return getScreenModeNextImpl(); } - private ScreenMode getScreenMode(int modeIndex) { - int[] modeProp = getScreenMode0(idx, modeIndex); - if(modeProp == null){ - return null; - } - int propIndex = 0; - int width = modeProp[propIndex++]; - int height = modeProp[propIndex++]; - int bits = modeProp[propIndex++]; - short rate = (short)modeProp[propIndex++]; - - ScreenMode screenMode = new ScreenMode(modeIndex+1, width, height); - screenMode.setRates(new short[]{rate}); - screenMode.setBitsPerPixel(bits); - return screenMode; + + protected int[] getScreenModeNextImpl() { + int[] modeProps = getScreenModeIdx(nativeModeIdx); + if (null != modeProps) { + nativeModeIdx++; + } + return modeProps; } - - public void setScreenRotation(int rot) { - if(!isRotationValid(rot)){ - return; - } - ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN()); - if(0 == setScreenRotation0(idx, rot)) { - sms.setCurrentScreenRotation(rot); - } - } - - /** Check if this rotation is valid for platform - * @param rot user requested rotation angle - * @return true if is valid - */ - private boolean isRotationValid(int rot){ - if((rot == ScreenMode.ROTATE_0) || (rot == ScreenMode.ROTATE_90) || - (rot == ScreenMode.ROTATE_180) || (rot == ScreenMode.ROTATE_270)) { - return true; - } - return false; - } - - public int getCurrentScreenRotation() { - int rot = super.getCurrentScreenRotation(); - if(rot == -1){ - return getCurrentScreenRotation0(idx); - } - return rot; - } - - // Native calls + protected ScreenMode getCurrentScreenModeImpl() { + return ScreenModeUtil.streamIn(getScreenModeIdx(-1), 0); + } + + 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 getCurrentScreenRate0(int scrn_idx); + private native int[] getScreenMode0(int screen_index, int mode_index); - - /** Change screen mode and return zero if successful - */ - private native int setScreenMode0(int screen_index, int width, int height, int bits, short freq); - - private native int getCurrentScreenRotation0(int screen_index); - - /** Change screen mode and return zero if successful - */ - private native int setScreenRotation0(int screen_index, int rot); + 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/x11/X11Screen.java b/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java index 52c80bbe9..a04ce4242 100644 --- a/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java +++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Screen.java @@ -30,12 +30,13 @@ * 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.impl.ScreenModeStatus; +import com.jogamp.newt.util.ScreenModeUtil; +import java.util.List; import javax.media.nativewindow.x11.*; @@ -45,153 +46,221 @@ public class X11Screen extends ScreenImpl { X11Display.initSingleton(); } - public X11Screen() { } protected void createNativeImpl() { - long handle = GetScreen0(display.getHandle(), idx); - if (handle == 0 ) { - throw new RuntimeException("Error creating screen: "+idx); + 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) { + nrotations = new int[1]; + nrotations[0]=0; } - aScreen = new X11GraphicsScreen((X11GraphicsDevice)getDisplay().getGraphicsDevice(), idx); - setScreenSize(getWidth0(display.getHandle(), idx), - getHeight0(display.getHandle(), idx)); + nrotation_index = 0; + + nres_number = getNumScreenModeResolutions0(display.getHandle(), screen_idx); + nres_index = 0; + + nrates = getScreenModeRates0(display.getHandle(), screen_idx, nres_index); + nrate_index = 0; + + nmode_number = 0; + + return getScreenModeNextImpl(); } - protected void closeNativeImpl() { } - - public int getDesktopScreenModeIndex() { - int index = super.getDesktopScreenModeIndex(); - if(index == -1){ - return getDesktopScreenModeIndex0(display.getHandle(), idx); - } - return index; + 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) { + throw new InternalError("null resolution received for res idx "+nres_index+"/"+nres_number); + } + 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); + nrate_index = 0; + } + } + + return props; } - - public void setScreenMode(int modeIndex, short rate) { - ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN()); - ScreenMode[] screenModes = sms.getScreenModes(); - - short selectedRate = rate; - int selectedMode = modeIndex; - - if(modeIndex < 0 || (modeIndex > screenModes.length)){ - selectedMode = sms.getOriginalScreenMode(); - } - ScreenMode screenMode = screenModes[selectedMode]; - - if(selectedRate == -1){ - selectedRate = sms.getOriginalScreenRate(); - } - - boolean rateAvailable = false; - short[] rates = screenMode.getRates(); - for(int i=0;i<rates.length;i++){ - if(rates[i] == selectedRate){ - rateAvailable = true; - break; - } - } - if(!rateAvailable){ - selectedRate = rates[0]; - } - - - setScreenMode0(display.getHandle(), idx, selectedMode, selectedRate, getCurrentScreenRotation()); - sms.setCurrentScreenMode(selectedMode); - sms.setCurrentScreenRate(selectedRate); + + protected ScreenMode getCurrentScreenModeImpl() { + int resNumber = getNumScreenModeResolutions0(display.getHandle(), screen_idx); + int resIdx = getCurrentScreenResolutionIndex0(display.getHandle(), screen_idx); + if(0>resIdx || resIdx>=resNumber) { + throw new RuntimeException("Invalid resolution index: ! 0 < "+resIdx+" < "+resNumber); + } + int[] res = getScreenModeResolution0(display.getHandle(), screen_idx, resIdx); + if(null == res) { + throw new InternalError("null resolution received for res idx "+resIdx+"/"+resNumber); + } + 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); + int rot = getCurrentScreenRotation0(display.getHandle(), screen_idx); + + 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); } - - public short getCurrentScreenRate() { - short rate = super.getCurrentScreenRate(); - if(rate == -1){ - return getCurrentScreenRate0(display.getHandle(), idx); - } - return rate; - } - - public ScreenMode[] getScreenModes() { - ScreenMode[] screenModes = super.getScreenModes(); - if(screenModes == null){ - int numModes = getNumScreenModes0(display.getHandle(), idx); - screenModes = new ScreenMode[numModes]; - for(int i=0; i< numModes; i++){ - screenModes[i] = getScreenMode(i); - } - } - return screenModes; + + 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); + } + String tname = Thread.currentThread()+"-X11Screen.setCurrentScreenModeImpl()"; + SetScreenModeAction setScreenModeAction = new SetScreenModeAction(screenMode, resIdx); + Thread randrTask = new Thread(setScreenModeAction, tname); + randrTask.start(); + int to = SCREEN_MODE_CHANGE_TIMEOUT / 100 ; + while(to>0 && randrTask.isAlive()) { + try { + Thread.sleep(100); + } catch (InterruptedException ex) { } + to--; + } + if(0==to && DEBUG) { + System.err.println("X11Screen.setCurrentScreenModeImpl: TO ("+SCREEN_MODE_CHANGE_TIMEOUT+") reached: "+ + randrTask+", alive "+randrTask.isAlive()); + } + return setScreenModeAction.getResult(); } - - private ScreenMode getScreenMode(int modeIndex){ - int[] modeProp = getScreenMode0(display.getHandle(), idx, modeIndex); - - if(modeProp == null){ - return null; - } - int propIndex = 0; - int index = modeProp[propIndex++]; - int width = modeProp[propIndex++]; - int height = modeProp[propIndex++]; - - ScreenMode screenMode = new ScreenMode(index, width, height); - - short[] rates = new short[modeProp.length - propIndex]; - for(int i= propIndex; i < modeProp.length; i++) - { - rates[i-propIndex] = (short) modeProp[i]; - } - screenMode.setRates(rates); - return screenMode; + + class SetScreenModeAction implements Runnable { + boolean res; + ScreenMode screenMode; + int resIdx; + + public SetScreenModeAction(ScreenMode screenMode, int resIdx) { + this.screenMode = screenMode; + this.resIdx = resIdx; + this.res = false; + } + + public boolean getResult() { + return res; + } + + public void run() { + long dpy = X11Util.createDisplay(display.getName()); + if( 0 == dpy ) { + throw new RuntimeException("Error creating display: "+display.getName()); + } + try { + res = setCurrentScreenMode0(dpy, screen_idx, resIdx, + screenMode.getMonitorMode().getRefreshRate(), screenMode.getRotation()); + } finally { + X11Util.closeDisplay(dpy); + } + } } - - public void setScreenRotation(int rot) { - if(!isRotationValid(rot)){ - return; - } - ScreenModeStatus sms = screensModeState.getScreenModeController(getScreenFQN()); - setScreenRotation0(display.getHandle(), idx, rot); - sms.setCurrentScreenRotation(rot); - } - - /** Check if this rotation is valid for platform - * @param rot user requested rotation angle - * @return true if is valid - */ - private boolean isRotationValid(int rot){ - if((rot == ScreenMode.ROTATE_0) || (rot == ScreenMode.ROTATE_90) || - (rot == ScreenMode.ROTATE_180) || (rot == ScreenMode.ROTATE_270)) { - return true; - } - return false; - } - - public int getCurrentScreenRotation() { - int rotation = super.getCurrentScreenRotation(); - if(rotation == -1){ - rotation = getCurrentScreenRotation0(display.getHandle(), idx); - } - return rotation; - } - + //---------------------------------------------------------------------- // Internals only // + private static native long GetScreen0(long dpy, int scrn_idx); - private native long GetScreen0(long dpy, int scrn_idx); - private native int getWidth0(long display, int scrn_idx); - private native int getHeight0(long display, int scrn_idx); - - private native int getDesktopScreenModeIndex0(long display, int screen_index); - private native short getCurrentScreenRate0(long display, int screen_index); - - private native int getCurrentScreenRotation0(long display, int screen_index); - private native void setScreenRotation0(long display, int screen_index, int rot); - - private native void setScreenMode0(long display, int screen_index, int mode_index, short freq, int rot); - - private native int[] getScreenMode0(long display, int screen_index, int mode_index); - private native int getNumScreenModes0(long display, int screen_index); + 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 setCurrentScreenMode0(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 index 06c7dfa99..60af9b9af 100644 --- a/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java +++ b/src/newt/classes/com/jogamp/newt/impl/x11/X11Window.java @@ -33,6 +33,7 @@ package com.jogamp.newt.impl.x11; +import com.jogamp.newt.ScreenMode; import com.jogamp.newt.impl.WindowImpl; import javax.media.nativewindow.*; import javax.media.nativewindow.x11.*; diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index 50fe3f63a..aef4de92a 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -230,6 +230,14 @@ public class GLWindow implements GLAutoDrawable, Window { 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 // 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..f24416469 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/util/MonitorMode.java @@ -0,0 +1,105 @@ +/** + * 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.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("MonitorMode["+surfaceSize+" x "+refreshRate+" Hz, "+screenSizeMM+" [mm]x[mm]]"); + } + + /** + * Checks whether two size objects are equal. Two instances + * of <code>MonitorMode</code> are equal if the three components + * <code>surfaceSize</code>, <code>screenSizeMM</code> and <code>refreshRate</code> + * are equal. + * @return <code>true</code> if the two dimensions are equal; + * otherwise <code>false</code>. + */ + public final boolean equals(Object obj) { + if (obj instanceof MonitorMode) { + MonitorMode p = (MonitorMode)obj; + return getSurfaceSize().equals(p.getSurfaceSize()) && + getScreenSizeMM().equals(p.getScreenSizeMM()) && + getRefreshRate() == p.getRefreshRate() ; + } + return false; + } + + 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..9cb04c2a1 --- /dev/null +++ b/src/newt/classes/com/jogamp/newt/util/ScreenModeUtil.java @@ -0,0 +1,367 @@ +/** + * 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; + } + + /** + * Validate the given list of {@link com.jogamp.newt.ScreenMode}s, testing on:<br> + * <ul> + * <li> unique {@link com.jogamp.newt.ScreenMode}s by equality and hash code + * </ul> + * This + * @param screenModes list of {@link com.jogamp.newt.ScreenMode}s + * @param throwException if true and invalid throw IllegalArgumentException + * @return true if valid, otherwise false or throw IllegalArgumentException + * @throws IllegalArgumentException if invalid + */ + public static boolean validate(List/*<ScreenMode>*/ screenModes, boolean throwException) { + for (int j=0; null!=screenModes && j<screenModes.size(); j++) { + ScreenMode sm = (ScreenMode)screenModes.get(j); + List dups = new ArrayList(); + + /*** don't check slow-path 'equals' for now, hash is working + for (int i=0; i<screenModes.size(); i++) { + ScreenMode sm2 = (ScreenMode)screenModes.get(i); + if( i!=j && sm.equals(sm2) ) { + dups.add(new Integer(i)); + } + } + if(dups.size()>0) { + if(throwException) { + throw new IllegalArgumentException("Element "+sm+" at index "+j+" is not unique (equality), duplicates: "+dups); + } else { + return false; + } + } */ + + for (int i=0; null!=screenModes && i<screenModes.size(); i++) { + ScreenMode sm2 = (ScreenMode)screenModes.get(i); + if ( i!=j && sm.hashCode() == sm2.hashCode() ) { + dups.add(new Integer(i)); + } + } + if(dups.size()>0) { + if(throwException) { + throw new IllegalArgumentException("Element "+sm+" at index "+j+" is not unique (hash), duplicates: "+dups); + } else { + return false; + } + } + } + return true; + } + + /** + * @param screenModes + * @param resolution + * @return modes with nearest resolution, or matching ones + */ + public static List/*<ScreenMode>*/ filterByResolution(List/*<ScreenMode>*/ screenModes, DimensionReadOnly resolution) { + 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) { + 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; + } + + public static List/*<ScreenMode>*/ filterByRotation(List/*<ScreenMode>*/ screenModes, int rotation) { + 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; + } + + public static List/*<ScreenMode>*/ filterByBpp(List/*<ScreenMode>*/ screenModes, int bitsPerPixel) { + 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; + } + + /** + * + * @param screenModes + * @param refreshRate + * @return modes with nearest refreshRate, or matching ones + */ + public static List/*<ScreenMode>*/ filterByRate(List/*<ScreenMode>*/ screenModes, int refreshRate) { + 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) { + 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) { + 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; + } + +} |