diff options
Diffstat (limited to 'src/newt')
27 files changed, 2371 insertions, 1228 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; + } + +} diff --git a/src/newt/native/NewtCommon.c b/src/newt/native/NewtCommon.c index 8b64ec37f..353dcb46f 100644 --- a/src/newt/native/NewtCommon.c +++ b/src/newt/native/NewtCommon.c @@ -1,6 +1,23 @@ #include "NewtCommon.h" +static const char * const ClazzNameRuntimeException = "java/lang/RuntimeException"; +static jclass runtimeExceptionClz=NULL; + +void NewtCommon_init(JNIEnv *env) { + if(NULL==runtimeExceptionClz) { + jclass c = (*env)->FindClass(env, ClazzNameRuntimeException); + if(NULL==c) { + _FatalError(env, "NEWT X11Window: can't find %s", ClazzNameRuntimeException); + } + runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); + (*env)->DeleteLocalRef(env, c); + if(NULL==runtimeExceptionClz) { + _FatalError(env, "NEWT X11Window: can't use %s", ClazzNameRuntimeException); + } + } +} + jchar* NewtCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) { jchar* strChars = NULL; @@ -11,3 +28,15 @@ jchar* NewtCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str) return strChars; } +void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...) +{ + char buffer[512]; + va_list ap; + + va_start(ap, msg); + vsnprintf(buffer, sizeof(buffer), msg, ap); + va_end(ap); + + (*env)->ThrowNew(env, runtimeExceptionClz, buffer); +} + diff --git a/src/newt/native/NewtCommon.h b/src/newt/native/NewtCommon.h index 46a0d57cf..00ce0b643 100644 --- a/src/newt/native/NewtCommon.h +++ b/src/newt/native/NewtCommon.h @@ -5,6 +5,10 @@ #include <jni.h> #include <stdlib.h> +void NewtCommon_init(JNIEnv *env); + jchar* NewtCommon_GetNullTerminatedStringChars(JNIEnv* env, jstring str); +void NewtCommon_throwNewRuntimeException(JNIEnv *env, const char* msg, ...); + #endif diff --git a/src/newt/native/ScreenMode.h b/src/newt/native/ScreenMode.h new file mode 100644 index 000000000..0a760d54a --- /dev/null +++ b/src/newt/native/ScreenMode.h @@ -0,0 +1,16 @@ +/** + * WARNING: must be synced with com.jogamp.newt.util.ScreenModeUtil#streamIn*(int[]) + */ + +#ifndef _SCREEN_MODE_H +#define _SCREEN_MODE_H + +#define NUM_RESOLUTION_PROPERTIES 2 /* width, height */ +#define NUM_SURFACE_SIZE_PROPERTIES 1 /* bpp */ +#define NUM_MONITOR_MODE_PROPERTIES 3 /* ScreenSizeMM[width, height], refresh-rate */ +#define NUM_SCREEN_MODE_PROPERTIES 1 /* rotation */ + +#define NUM_SCREEN_MODE_PROPERTIES_ALL 8 /* count + the above */ + +#endif + diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index 9aac8720c..de501bfbc 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -413,7 +413,7 @@ static void BuildDynamicKeyMapTable() LCID idLocale = MAKELCID(idLang, SORT_DEFAULT); // get the ANSI code page associated with this locale if (GetLocaleInfo(idLocale, LOCALE_IDEFAULTANSICODEPAGE, - strCodePage, sizeof(strCodePage)/sizeof(TCHAR)) > 0 ) + strCodePage, sizeof(strCodePage)/sizeof(TCHAR)) > 0 ) { codePage = _ttoi(strCodePage); } else { @@ -1001,7 +1001,7 @@ static LRESULT CALLBACK wndProc(HWND wnd, UINT message, RECT r; useDefWindowProc = 0; if (GetUpdateRect(wnd, &r, TRUE /* erase background */)) { - /* + /* jint width = r.right-r.left; jint height = r.bottom-r.top; if (width > 0 && height > 0) { @@ -1146,26 +1146,44 @@ JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_getHeight return (jint)GetSystemMetrics(SM_CYSCREEN); } -/* - * Class: com_jogamp_newt_impl_windows_WindowsScreen - * Method: getCurrentScreenRate0 - * Signature: (I)S - */ -JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_getCurrentScreenRate0 - (JNIEnv *env, jobject object, jint scrn_idx) -{ - DEVMODE dm; - // initialize the DEVMODE structure - ZeroMemory(&dm, sizeof(dm)); - dm.dmSize = sizeof(dm); - - int rate = -1; - if (0 != EnumDisplaySettings(NULL /*current display device*/, ENUM_CURRENT_SETTINGS, &dm)) - { - rate = dm.dmDisplayFrequency; - } - - return rate; +static int NewtScreen_RotationNative2Newt(int native) { + int rot; + switch (native) { + case DMDO_DEFAULT: + rot = 0; + break; + case DMDO_270: + rot = 270; + break; + case DMDO_180: + rot = 180; + break; + case DMDO_90: + rot = 90; + break; + default: + NewtCommon_throwNewRuntimeException(env, "invalid native rotation: %d", native); + break; + } + return rot; +} + +static LPCTSTR NewtScreen_getDisplayDeviceName(int scrn_idx) { + DISPLAY_DEVICE device; + + if( FALSE == EnumDisplayDevices(NULL, scrn_idx, &device, 0) ) { + return NULL; + } + + if( 0 == ( device.StateFlags & DISPLAY_DEVICE_ACTIVE ) ) { + return NULL; + } + + return device.DeviceName; +} + +static HDC NewtScreen_createDisplayDC(LPCTSTR displayDeviceName) { + return CreateDC("DISPLAY", displayDeviceName, NULL, NULL); } /* @@ -1176,188 +1194,144 @@ JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_getCurren JNIEXPORT jintArray JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_getScreenMode0 (JNIEnv *env, jobject obj, jint scrn_idx, jint mode_idx) { - int propIndex = 0; - int prop_size = 4; //wxhxbxf - - DEVMODE dm; - // initialize the DEVMODE structure - ZeroMemory(&dm, sizeof(dm)); - dm.dmSize = sizeof(dm); - - int devModeID = (int)mode_idx; - - if(devModeID == -1) - { - devModeID = ENUM_CURRENT_SETTINGS; - } - - jintArray properties = (*env)->NewIntArray(env, prop_size); - - //Fill the properties in temp jint array - jint prop[prop_size]; - if (0 == EnumDisplaySettings(NULL /*current display device*/, devModeID, &dm)) - { - return NULL; - } - prop[propIndex++] = dm.dmPelsWidth; - prop[propIndex++] = dm.dmPelsHeight; - prop[propIndex++] = dm.dmBitsPerPel; - prop[propIndex++] = dm.dmDisplayFrequency; - - (*env)->SetIntArrayRegion(env, properties, 0, prop_size, prop); - - return properties; -} + int prop_num = NUM_SCREEN_MODE_PROPERTIES_ALL; + LPCTSTR deviceName = NewtScreen_getDisplayDeviceName(scrn_idx); + if(NULL == deviceName) { + return null; + } -#define SCREEN_MODE_NOERROR 0 -#define SCREEN_MODE_ERROR 1 -/* - * Class: com_jogamp_newt_impl_windows_WindowsScreen - * Method: setScreenMode0 - * Signature: (IIIIS)I - */ -JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_setScreenMode0 - (JNIEnv *env, jobject object, jint scrn_idx, jint width, jint height, jint bits, jshort rate) -{ - DEVMODE dm; - // initialize the DEVMODE structure + int widthmm, heightmm; + { + HDC hdc = NewtScreen_createDisplayDC(deviceName); + widthmm = GetDeviceCaps(hdc, HORZSIZE); + heightmm = GetDeviceCaps(hdc, VERTSIZE); + DeleteDC(hdc); + } + + DEVMODE dm; ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); + + int devModeID = (int)mode_idx; + + if(devModeID == -1) { + devModeID = ENUM_CURRENT_SETTINGS; + prop_num++; // add 1st extra prop, mode_idx + } - if (0 == EnumDisplaySettings(NULL /*current display device*/, ENUM_CURRENT_SETTINGS, &dm)) - { - return SCREEN_MODE_ERROR; - } - - dm.dmPelsWidth = (int)width; - dm.dmPelsHeight = (int)height; - dm.dmBitsPerPel = (int)bits; - dm.dmDisplayFrequency = (int)rate; - dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; - - long result = ChangeDisplaySettings(&dm, 0); - if(result == DISP_CHANGE_SUCCESSFUL) - { - return SCREEN_MODE_NOERROR; - } - return SCREEN_MODE_ERROR; -} + if (0 == EnumDisplaySettings(deviceName, devModeID, &dm)) + { + return NULL; + } -#define SCREEN_ROT_ERROR -1 -/* - * Class: com_jogamp_newt_impl_windows_WindowsScreen - * Method: getCurrentScreenRotation0 - * Signature: (I)I - */ -JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_getCurrentScreenRotation0 - (JNIEnv *env, jobject object, jint scrn_idx) -{ - DEVMODE dm; - // initialize the DEVMODE structure - ZeroMemory(&dm, sizeof(dm)); - dm.dmSize = sizeof(dm); + + jint prop[ prop_num ]; + int propIndex = 0; - if (0 == EnumDisplaySettings(NULL /*current display device*/, ENUM_CURRENT_SETTINGS, &dm)) - { - return SCREEN_ROT_ERROR; - } - - int currentRotation = -1; - switch (dm.dmDisplayOrientation) - { - case DMDO_DEFAULT: - currentRotation = 0; - break; - case DMDO_270: - currentRotation = 270; - break; - case DMDO_180: - currentRotation = 180; - break; - case DMDO_90: - currentRotation = 90; - break; - default: - break; - } - return currentRotation; + if(devModeID == -1) { + prop[propIndex++] = mode_idx; + } + prop[propIndex++] = 0; // set later for verification of iterator + prop[propIndex++] = dm.dmPelsWidth; + prop[propIndex++] = dm.dmPelsHeight; + prop[propIndex++] = dm.dmBitsPerPel; + prop[propIndex++] = widthmm; + prop[propIndex++] = heightmm; + prop[propIndex++] = dm.dmDisplayFrequency; + prop[propIndex++] = NewtScreen_RotationNative2Newt(dm.dmDisplayOrientation); + props[propIndex - NUM_SCREEN_MODE_PROPERTIES_ALL] = propIndex ; // count + + jintArray properties = (*env)->NewIntArray(env, prop_num); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", prop_num); + } + (*env)->SetIntArrayRegion(env, properties, 0, prop_num, prop); + + return properties; } + /* * Class: com_jogamp_newt_impl_windows_WindowsScreen - * Method: setScreenRotation0 - * Signature: (II)I + * Method: setScreenMode0 + * Signature: (IIIIII)Z */ -JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_setScreenRotation0 - (JNIEnv *env, jobject object, jint scrn_idx, jint rot) +JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_setScreenMode0 + (JNIEnv *env, jobject object, jint scrn_idx, jint width, jint height, jint bits, jint rate, jint rot) { - DEVMODE dm; + LPCTSTR deviceName = NewtScreen_getDisplayDeviceName(scrn_idx); + if(NULL == deviceName) { + return null; + } + + DEVMODE dm; // initialize the DEVMODE structure ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); - if (0 == EnumDisplaySettings(NULL /*current display device*/, ENUM_CURRENT_SETTINGS, &dm)) - { - return SCREEN_MODE_ERROR; - } - int requestedRotation = dm.dmDisplayOrientation; - int currentRotation = dm.dmDisplayOrientation; - - int shouldFlipDims = 0; - - int rotation = (int)rot; - switch (rotation) - { - case 0: - requestedRotation = DMDO_DEFAULT; - if (currentRotation == DMDO_90 || currentRotation == DMDO_270) - { - shouldFlipDims = 1; - } - break; - case 270: - requestedRotation = DMDO_270; - if (currentRotation == DMDO_DEFAULT || currentRotation == DMDO_180) - { - shouldFlipDims = 1; - } - break; - case 180: - requestedRotation = DMDO_180; - if (currentRotation == DMDO_90 || currentRotation == DMDO_270) - { - shouldFlipDims = 1; - } - break; - case 90: - requestedRotation = DMDO_90; - if (currentRotation == DMDO_DEFAULT || currentRotation == DMDO_180) - { - shouldFlipDims = 1; - } - break; - default: - //requested rotation not available - return SCREEN_MODE_ERROR; - break; - } - /** swap width and height if changing from vertical to horizantal - * or horizantal to vertical - */ - if (shouldFlipDims) - { - int tempWidth = dm.dmPelsWidth; - dm.dmPelsWidth = dm.dmPelsHeight; - dm.dmPelsHeight = tempWidth; - } - dm.dmDisplayOrientation = requestedRotation; - dm.dmFields = DM_DISPLAYORIENTATION | DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; - - long result = ChangeDisplaySettings(&dm, 0); - if(result == DISP_CHANGE_SUCCESSFUL) - { - return SCREEN_MODE_NOERROR; - } - return SCREEN_MODE_ERROR; + if (0 == EnumDisplaySettings(deviceName, ENUM_CURRENT_SETTINGS, &dm)) { + return JNI_FALSE; + } + + dm.dmPelsWidth = (int)width; + dm.dmPelsHeight = (int)height; + dm.dmBitsPerPel = (int)bits; + dm.dmDisplayFrequency = (int)rate; + dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; + + int requestedRotation = dm.dmDisplayOrientation; + int currentRotation = dm.dmDisplayOrientation; + + int shouldFlipDims = 0; + + int rotation = (int)rot; + switch (rotation) + { + case 0: + requestedRotation = DMDO_DEFAULT; + if (currentRotation == DMDO_90 || currentRotation == DMDO_270) + { + shouldFlipDims = 1; + } + break; + case 270: + requestedRotation = DMDO_270; + if (currentRotation == DMDO_DEFAULT || currentRotation == DMDO_180) + { + shouldFlipDims = 1; + } + break; + case 180: + requestedRotation = DMDO_180; + if (currentRotation == DMDO_90 || currentRotation == DMDO_270) + { + shouldFlipDims = 1; + } + break; + case 90: + requestedRotation = DMDO_90; + if (currentRotation == DMDO_DEFAULT || currentRotation == DMDO_180) + { + shouldFlipDims = 1; + } + break; + default: + //requested rotation not available + return SCREEN_MODE_ERROR; + break; + } + /** swap width and height if changing from vertical to horizantal + * or horizantal to vertical + */ + if (shouldFlipDims) + { + int tempWidth = dm.dmPelsWidth; + dm.dmPelsWidth = dm.dmPelsHeight; + dm.dmPelsHeight = tempWidth; + } + dm.dmDisplayOrientation = requestedRotation; + dm.dmFields = DM_DISPLAYORIENTATION | DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY; + + return ( DISP_CHANGE_SUCCESSFUL == ChangeDisplaySettings(&dm, 0) ) ? JNI_TRUE : JNI_FALSE ; } /* @@ -1368,6 +1342,8 @@ JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_windows_WindowsScreen_setScreen JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_initIDs0 (JNIEnv *env, jclass clazz) { + NewtCommon_init(env); + if(NULL==pointClz) { jclass c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { @@ -1628,31 +1604,31 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_setVisibl static int NewtWindows_setFullScreen(jboolean fullscreen) { - int flags = 0; - DEVMODE dm; + int flags = 0; + DEVMODE dm; // initialize the DEVMODE structure ZeroMemory(&dm, sizeof(dm)); dm.dmSize = sizeof(dm); - if (0 == EnumDisplaySettings(NULL /*current display device*/, ENUM_CURRENT_SETTINGS, &dm)) - { - return FULLSCREEN_ERROR; - } - - if(fullscreen == JNI_TRUE) - { - flags = CDS_FULLSCREEN; //set fullscreen temporary - } - else - { - flags = CDS_RESET; // reset to registery values - } - long result = ChangeDisplaySettings(&dm, flags); - if(result == DISP_CHANGE_SUCCESSFUL) - { - return FULLSCREEN_NOERROR; - } - return FULLSCREEN_ERROR; + if (0 == EnumDisplaySettings(NULL /*current display device*/, ENUM_CURRENT_SETTINGS, &dm)) + { + return FULLSCREEN_ERROR; + } + + if(fullscreen == JNI_TRUE) + { + flags = CDS_FULLSCREEN; //set fullscreen temporary + } + else + { + flags = CDS_RESET; // reset to registery values + } + long result = ChangeDisplaySettings(&dm, flags); + if(result == DISP_CHANGE_SUCCESSFUL) + { + return FULLSCREEN_NOERROR; + } + return FULLSCREEN_ERROR; } /* @@ -1687,11 +1663,11 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_reconfigu if(JNI_TRUE == visible) { windowStyle |= WS_VISIBLE ; } - - if(fullScreenChange < 0) - { - NewtWindows_setFullScreen(JNI_FALSE); - } + + if(fullScreenChange < 0) + { + NewtWindows_setFullScreen(JNI_FALSE); + } // order of call sequence: (MS documentation) // TOP: SetParent(.., NULL); Clear WS_CHILD [, Set WS_POPUP] @@ -1700,11 +1676,11 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_windows_WindowsWindow_reconfigu if ( JNI_TRUE == parentChange && NULL == hwndP ) { SetParent(hwnd, NULL); } - - if(fullScreenChange > 0) - { - NewtWindows_setFullScreen(JNI_TRUE); - } + + if(fullScreenChange > 0) + { + NewtWindows_setFullScreen(JNI_TRUE); + } if ( styleChange ) { if(NULL!=hwndP) { diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 6c6aff478..bced039b9 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -48,7 +48,7 @@ #include <X11/keysym.h> #include <X11/Xatom.h> -#include<X11/extensions/Xrandr.h> +#include <X11/extensions/Xrandr.h> #include "com_jogamp_newt_impl_x11_X11Screen.h" #include "com_jogamp_newt_impl_x11_X11Display.h" @@ -57,6 +57,7 @@ #include "MouseEvent.h" #include "KeyEvent.h" #include "WindowEvent.h" +#include "ScreenMode.h" #include "NewtCommon.h" @@ -149,16 +150,12 @@ static void _FatalError(JNIEnv *env, const char* msg, ...) (*env)->FatalError(env, buffer); } -static const char * const ClazzNameRuntimeException = "java/lang/RuntimeException"; - static const char * const ClazzNameNewtWindow = "com/jogamp/newt/Window"; static const char * const ClazzNamePoint = "javax/media/nativewindow/util/Point"; static const char * const ClazzAnyCstrName = "<init>"; static const char * const ClazzNamePointCstrSignature = "(II)V"; -static jclass runtimeExceptionClz=NULL; - static jclass newtWindowClz=NULL; static jclass pointClz = NULL; @@ -182,18 +179,6 @@ static jmethodID enqueueRequestFocusID = NULL; static jmethodID displayCompletedID = NULL; -static void _throwNewRuntimeException(Display * unlockDisplay, JNIEnv *env, const char* msg, ...) -{ - char buffer[512]; - va_list ap; - - va_start(ap, msg); - vsnprintf(buffer, sizeof(buffer), msg, ap); - va_end(ap); - - (*env)->ThrowNew(env, runtimeExceptionClz, buffer); -} - /** * Display */ @@ -212,7 +197,7 @@ static int displayDispatchErrorHandler(Display *dpy, XErrorEvent *e) { fprintf(stderr, " BadWindow (%p): Window probably already removed\n", (void*)e->resourceid); } else { - _throwNewRuntimeException(NULL, x11ErrorHandlerJNIEnv, "NEWT X11 Error: Display %p, Code 0x%X", dpy, e->error_code); + NewtCommon_throwNewRuntimeException(x11ErrorHandlerJNIEnv, "NEWT X11 Error: Display %p, Code 0x%X", dpy, e->error_code); } return 0; @@ -240,6 +225,8 @@ JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_impl_x11_X11Display_initIDs0 { jclass c; + NewtCommon_init(env); + displayCompletedID = (*env)->GetMethodID(env, clazz, "displayCompleted", "(JJ)V"); if (displayCompletedID == NULL) { return JNI_FALSE; @@ -257,18 +244,6 @@ JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_impl_x11_X11Display_initIDs0 } } - if(NULL==runtimeExceptionClz) { - c = (*env)->FindClass(env, ClazzNameRuntimeException); - if(NULL==c) { - _FatalError(env, "NEWT X11Window: can't find %s", ClazzNameRuntimeException); - } - runtimeExceptionClz = (jclass)(*env)->NewGlobalRef(env, c); - (*env)->DeleteLocalRef(env, c); - if(NULL==runtimeExceptionClz) { - _FatalError(env, "NEWT X11Window: can't use %s", ClazzNameRuntimeException); - } - } - if(NULL==pointClz) { c = (*env)->FindClass(env, ClazzNamePoint); if(NULL==c) { @@ -306,13 +281,13 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Display_CompleteDisplay0 javaObjectAtom = (jlong) XInternAtom(dpy, "JOGL_JAVA_OBJECT", False); if(None==javaObjectAtom) { - _throwNewRuntimeException(dpy, env, "could not create Atom JOGL_JAVA_OBJECT, bail out!"); + NewtCommon_throwNewRuntimeException(env, "could not create Atom JOGL_JAVA_OBJECT, bail out!"); return; } windowDeleteAtom = (jlong) XInternAtom(dpy, "WM_DELETE_WINDOW", False); if(None==windowDeleteAtom) { - _throwNewRuntimeException(dpy, env, "could not create Atom WM_DELETE_WINDOW, bail out!"); + NewtCommon_throwNewRuntimeException(env, "could not create Atom WM_DELETE_WINDOW, bail out!"); return; } @@ -400,7 +375,7 @@ static jobject getJavaWindowProperty(JNIEnv *env, Display *dpy, Window window, j #ifdef VERBOSE_ON if(JNI_FALSE == (*env)->IsInstanceOf(env, jwindow, newtWindowClz)) { - _throwNewRuntimeException(dpy, env, "fetched Atom JOGL_JAVA_OBJECT window is not a NEWT Window: javaWindow 0x%X !", jwindow); + NewtCommon_throwNewRuntimeException(env, "fetched Atom JOGL_JAVA_OBJECT window is not a NEWT Window: javaWindow 0x%X !", jwindow); } #endif return jwindow; @@ -480,8 +455,6 @@ static void NewtWindows_setDecorations (Display *dpy, Window w, Bool decorated) #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 - - static void NewtWindows_setFullscreen (Display *dpy, Window root, Window w, Bool fullscreen) { Atom _NET_WM_STATE = XInternAtom( dpy, "_NET_WM_STATE", False ); Atom _NET_WM_STATE_ABOVE = XInternAtom( dpy, "_NET_WM_STATE_ABOVE", False ); @@ -555,12 +528,12 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Display_DispatchMessages num_events--; if( 0==evt.xany.window ) { - _throwNewRuntimeException(dpy, env, "event window NULL, bail out!"); + NewtCommon_throwNewRuntimeException(env, "event window NULL, bail out!"); return ; } if(dpy!=evt.xany.display) { - _throwNewRuntimeException(dpy, env, "wrong display, bail out!"); + NewtCommon_throwNewRuntimeException(env, "wrong display, bail out!"); return ; } @@ -808,7 +781,7 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Display_DispatchMessages * Signature: (JI)J */ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_GetScreen0 - (JNIEnv *env, jobject obj, jlong display, jint screen_index) + (JNIEnv *env, jclass clazz, jlong display, jint screen_index) { Display * dpy = (Display *)(intptr_t)display; Screen * scrn= NULL; @@ -831,176 +804,224 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_GetScreen0 } JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getWidth0 - (JNIEnv *env, jobject obj, jlong display, jint scrn_idx) + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) { Display * dpy = (Display *) (intptr_t) display; return (jint) XDisplayWidth( dpy, scrn_idx); } JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getHeight0 - (JNIEnv *env, jobject obj, jlong display, jint scrn_idx) + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) { Display * dpy = (Display *) (intptr_t) display; return (jint) XDisplayHeight( dpy, scrn_idx); } + +static Bool NewtScreen_getRANDRVersion(Display *dpy, int *major, int *minor) { + if( 0 == XRRQueryVersion(dpy, major, minor) ) { + return False; + } + return True; +} + +static Bool NewtScreen_hasRANDR(Display *dpy) { + int major, minor; + return NewtScreen_getRANDRVersion(dpy, &major, &minor); +} + +static int NewtScreen_XRotation2Degree(JNIEnv *env, int xrotation) { + int rot; + if(xrotation == RR_Rotate_0) { + rot = 0; + } + else if(xrotation == RR_Rotate_90) { + rot = 90; + } + else if(xrotation == RR_Rotate_180) { + rot = 180; + } + else if(xrotation == RR_Rotate_270) { + rot = 270; + } else { + NewtCommon_throwNewRuntimeException(env, "invalid native rotation: %d", xrotation); + } + return rot; +} + /* * Class: com_jogamp_newt_impl_x11_X11Screen - * Method: getDesktopScreenModeIndex0 + * Method: getAvailableScreenModeRotations0 * Signature: (JI)I */ -JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getDesktopScreenModeIndex0 - (JNIEnv *env, jobject object, jlong display, jint scrn_indx) +JNIEXPORT jintArray JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getAvailableScreenModeRotations0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) { - Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_indx); - - // get current resolutions and frequency configuration - XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); - short original_rate = XRRConfigCurrentRate(conf); - - Rotation original_rotation; - SizeID original_size_id = XRRConfigCurrentConfiguration(conf, &original_rotation); - - //free - XRRFreeScreenConfigInfo(conf); - - return (jint)original_size_id; -} + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)scrn_idx); + int num_rotations = 0; + Rotation cur_rotation, rotations_supported; + int rotations[4]; + int major, minor; + + if(False == NewtScreen_getRANDRVersion(dpy, &major, &minor)) { + fprintf(stderr, "RANDR not available\n"); + } else { + fprintf(stderr, "RANDR %d.%d available\n", major, minor); + } -static void X11Screen_changeScreenMode(Display* dpy, Window root, int screen_indx, XRRScreenSize *xrrs, int screenModeIndex, short freq, int rotation) -{ - int num_rates; //number of available rates for selected mode index - short *rates = XRRRates(dpy, screen_indx, screenModeIndex, &num_rates); - - XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); - - int rot = RR_Rotate_0; - - if(rotation == 90) - { - rot = RR_Rotate_90; + rotations_supported = XRRRotations (dpy, (int)scrn_idx, &cur_rotation); + + if(0 != (rotations_supported & RR_Rotate_0)) { + rotations[num_rotations++] = 0; } - else if(rotation == 180) - { - rot = RR_Rotate_180; + if(0 != (rotations_supported & RR_Rotate_90)) { + rotations[num_rotations++] = 90; } - else if(rotation == 270) - { - rot = RR_Rotate_270; + if(0 != (rotations_supported & RR_Rotate_180)) { + rotations[num_rotations++] = 180; } - // Change the resolution - DBG_PRINT("\nCHANGED TO %i x %i PIXELS, %i Hz\n\n", xrrs[screenModeIndex].width, xrrs[screenModeIndex].height, selectedFreq); - XRRSetScreenConfigAndRate(dpy, conf, root, screenModeIndex, rot, freq, CurrentTime); - - //free - XRRFreeScreenConfigInfo(conf); + if(0 != (rotations_supported & RR_Rotate_270)) { + rotations[num_rotations++] = 270; + } + + jintArray properties = NULL; + + if(num_rotations>0) { + properties = (*env)->NewIntArray(env, num_rotations); + if (properties == NULL) + { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rotations); + } + + // move from the temp structure to the java structure + (*env)->SetIntArrayRegion(env, properties, 0, num_rotations, rotations); + } + + return properties; } /* * Class: com_jogamp_newt_impl_x11_X11Screen - * Method: setScreenMode0 - * Signature: (JIIS)V + * Method: getNumScreenModeResolution0 + * Signature: (JI)I */ -JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_setScreenMode0 - (JNIEnv *env, jobject object, jlong display, jint scrn_indx, jint mode_indx, jshort freq, jint rotation) +JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getNumScreenModeResolutions0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) { Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_indx); + Window root = RootWindow(dpy, (int)scrn_idx); + + if(False == NewtScreen_hasRANDR(dpy)) { + return 0; + } int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_indx, &num_sizes); //get possible screen resolutions - int screenModeIndex = (int)mode_indx; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions - if((screenModeIndex > num_sizes) || (screenModeIndex < 0)) - { - DBG_PRINT("\nSelected mode index not available for selected screen, index: %i\n", screenModeIndex); - return; - } - - X11Screen_changeScreenMode(dpy, root, (int)scrn_indx, xrrs, screenModeIndex, (short)freq, (int)rotation); + return num_sizes; } -#define NUM_SCREEN_MODE_PROPERTIES 3 - /* * Class: com_jogamp_newt_impl_x11_X11Screen - * Method: getScreenMode0 + * Method: getScreenModeResolutions0 * Signature: (JII)[I */ -JNIEXPORT jintArray JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getScreenMode0 - (JNIEnv *env, jobject object, jlong display, jint scrn_indx, jint mode_indx) +JNIEXPORT jintArray JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getScreenModeResolution0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx, jint resMode_idx) { Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_indx); + Window root = RootWindow(dpy, (int)scrn_idx); + if(False == NewtScreen_hasRANDR(dpy)) { + return NULL; + } + int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_indx, &num_sizes); //get possible screen resolutions + XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions - int num_rates; - short *rates = XRRRates(dpy, (int)scrn_indx, (int)mode_indx, &num_rates); - - int prop_size = NUM_SCREEN_MODE_PROPERTIES +num_rates; - - jintArray properties = (*env)->NewIntArray(env, prop_size); - if (properties == NULL) - { - return NULL; /* out of memory error thrown */ + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); } - - //Fill the properties in temp jint array + + // Fill the properties in temp jint array int propIndex = 0; - jint prop[prop_size]; + jint prop[4]; - prop[propIndex++] = (int)mode_indx; - prop[propIndex++] = xrrs[(int)mode_indx].width; - prop[propIndex++] = xrrs[(int)mode_indx].height; + prop[propIndex++] = xrrs[(int)resMode_idx].width; + prop[propIndex++] = xrrs[(int)resMode_idx].height; + prop[propIndex++] = xrrs[(int)resMode_idx].mwidth; + prop[propIndex++] = xrrs[(int)resMode_idx].mheight; - //loop through all possible resolutions - //with the selectable display frequencies - int i= 0; - while(i < num_rates) - { - prop[propIndex++] = rates[i]; - i++; - } + jintArray properties = (*env)->NewIntArray(env, 4); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", 4); + } - // move from the temp structure to the java structure - (*env)->SetIntArrayRegion(env, properties, 0, prop_size, prop); + (*env)->SetIntArrayRegion(env, properties, 0, 4, prop); return properties; } /* * Class: com_jogamp_newt_impl_x11_X11Screen - * Method: getNumScreenModes0 - * Signature: (JI)I + * Method: getScreenModeRates0 + * Signature: (JII)[I */ -JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getNumScreenModes0 - (JNIEnv *env, jobject object, jlong display, jint scrn_indx) +JNIEXPORT jintArray JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getScreenModeRates0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx, jint resMode_idx) { Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_indx); + Window root = RootWindow(dpy, (int)scrn_idx); + if(False == NewtScreen_hasRANDR(dpy)) { + return NULL; + } + int num_sizes; - XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_indx, &num_sizes); //get possible screen resolutions + XRRScreenSize *xrrs = XRRSizes(dpy, (int)scrn_idx, &num_sizes); //get possible screen resolutions + + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); + } + + int num_rates; + short *rates = XRRRates(dpy, (int)scrn_idx, (int)resMode_idx, &num_rates); + + jint prop[num_rates]; + int i; + for(i=0; i<num_rates; i++) { + prop[i] = (int) rates[i]; + /** fprintf(stderr, "rate[%d, %d, %d/%d]: %d\n", (int)scrn_idx, resMode_idx, i, num_rates, prop[i]); */ + } - return num_sizes; + jintArray properties = (*env)->NewIntArray(env, num_rates); + if (properties == NULL) { + NewtCommon_throwNewRuntimeException(env, "Could not allocate int array of size %d", num_rates); + } + + // move from the temp structure to the java structure + (*env)->SetIntArrayRegion(env, properties, 0, num_rates, prop); + + return properties; } - /* * Class: com_jogamp_newt_impl_x11_X11Screen * Method: getCurrentScreenRate0 - * Signature: (JI)S + * Signature: (JI)I */ -JNIEXPORT jshort JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getCurrentScreenRate0 - (JNIEnv *env, jobject object, jlong display, jint scrn_indx) +JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getCurrentScreenRate0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) { Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_indx); + Window root = RootWindow(dpy, (int)scrn_idx); + if(False == NewtScreen_hasRANDR(dpy)) { + return -1; + } + // get current resolutions and frequencies XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); short original_rate = XRRConfigCurrentRate(conf); @@ -1008,7 +1029,7 @@ JNIEXPORT jshort JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getCurrentScree //free XRRFreeScreenConfigInfo(conf); - return original_rate; + return (jint) original_rate; } /* @@ -1017,11 +1038,15 @@ JNIEXPORT jshort JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getCurrentScree * Signature: (JI)I */ JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getCurrentScreenRotation0 - (JNIEnv *env, jobject object, jlong display, jint scrn_indx) + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) { Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_indx); + Window root = RootWindow(dpy, (int)scrn_idx); + if(False == NewtScreen_hasRANDR(dpy)) { + return -1; + } + //get current resolutions and frequencies XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); @@ -1031,68 +1056,122 @@ JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getCurrentScreenR //free XRRFreeScreenConfigInfo(conf); - int rot = -1; - - if(rotation == RR_Rotate_0) { - rot = 0; - } - else if(rotation == RR_Rotate_90) { - rot = 90; - } - else if(rotation == RR_Rotate_180) { - rot = 180; - } - else if(rotation == RR_Rotate_270) { - rot = 270; - } - - return rot; + return NewtScreen_XRotation2Degree(env, rotation); +} + + +/* + * Class: com_jogamp_newt_impl_x11_X11Screen + * Method: getCurrentScreenResolutionIndex0 + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_getCurrentScreenResolutionIndex0 + (JNIEnv *env, jclass clazz, jlong display, jint scrn_idx) +{ + Display *dpy = (Display *) (intptr_t) display; + Window root = RootWindow(dpy, (int)scrn_idx); + + if(False == NewtScreen_hasRANDR(dpy)) { + return -1; + } + + // get current resolutions and frequency configuration + XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); + short original_rate = XRRConfigCurrentRate(conf); + + Rotation original_rotation; + SizeID original_size_id = XRRConfigCurrentConfiguration(conf, &original_rotation); + + //free + XRRFreeScreenConfigInfo(conf); + + return (jint)original_size_id; } /* * Class: com_jogamp_newt_impl_x11_X11Screen - * Method: setScreenRotation0 - * Signature: (JII)V + * Method: setScreenMode0 + * Signature: (JIIII)Z */ -JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_setScreenRotation0 - (JNIEnv *env, jobject object, jlong display, jint scrn_indx, jint rotation) +JNIEXPORT jboolean JNICALL Java_com_jogamp_newt_impl_x11_X11Screen_setCurrentScreenMode0 + (JNIEnv *env, jclass clazz, jlong display, jint screen_idx, jint resMode_idx, jint freq, jint rotation) { + int randr_event_base, randr_error_base; Display *dpy = (Display *) (intptr_t) display; - Window root = RootWindow(dpy, (int)scrn_indx); - - int rot = -1; - - if(rotation == 0) - { - rot = RR_Rotate_0; - } - else if(rotation == 90) - { - rot = RR_Rotate_90; - } - else if(rotation == 180) - { - rot = RR_Rotate_180; + Window root = RootWindow(dpy, (int)screen_idx); + + if(False == NewtScreen_hasRANDR(dpy)) { + return JNI_FALSE; } - else if(rotation == 270) - { - rot = RR_Rotate_270; + + XRRQueryExtension(dpy, &randr_event_base, &randr_error_base); + DBG_PRINT("RANDR: event_base: %d\n", randr_event_base); + + int num_sizes; + XRRScreenSize *xrrs = XRRSizes(dpy, (int)screen_idx, &num_sizes); //get possible screen resolutions + XRRScreenConfiguration *conf; + int rot; + + if( 0 > resMode_idx || resMode_idx >= num_sizes ) { + NewtCommon_throwNewRuntimeException(env, "Invalid resolution index: ! 0 < %d < %d", resMode_idx, num_sizes); } - else - { - return; + + conf = XRRGetScreenInfo(dpy, root); + + switch(rotation) { + case 0: + rot = RR_Rotate_0; + break; + case 90: + rot = RR_Rotate_90; + break; + case 180: + rot = RR_Rotate_180; + break; + case 270: + rot = RR_Rotate_270; + break; + default: + NewtCommon_throwNewRuntimeException(env, "Invalid rotation: %d", rotation); } - XRRScreenConfiguration *conf = XRRGetScreenInfo(dpy, root); - - Rotation current_rotation; - SizeID current_mode_id = XRRConfigCurrentConfiguration(conf, ¤t_rotation); - short current_rate = XRRConfigCurrentRate(conf); + DBG_PRINT("X11Screen.setCurrentScreenMode0: CHANGED TO %d: %d x %d PIXELS, %d Hz, %d degree\n", + resMode_idx, xrrs[resMode_idx].width, xrrs[resMode_idx].height, (int)freq, rotation); + + XRRSelectInput (dpy, root, RRScreenChangeNotifyMask); + + XSync(dpy, False); + XRRSetScreenConfigAndRate(dpy, conf, root, (int)resMode_idx, rot, (short)freq, CurrentTime); + XSync(dpy, False); + + XEvent evt; + XRRScreenChangeNotifyEvent * scn_event = (XRRScreenChangeNotifyEvent *) &evt; + int done = 0; + do { + // XWindowEvent(dpy, root, randr_event_base + RRScreenChangeNotify, &evt); + XNextEvent(dpy, &evt); + + switch (evt.type - randr_event_base) { + case RRScreenChangeNotify: + rot = NewtScreen_XRotation2Degree(env, (int)scn_event->rotation); + DBG_PRINT( "XRANDR: event . RRScreenChangeNotify call %p (root %p) resIdx %d rot %d %dx%d\n", + (void*)scn_event->window, (void*)scn_event->root, + (int)scn_event->size_index, rot, + scn_event->width, scn_event->height); + // done = scn_event->size_index == resMode_idx; // not reliable .. + done = rot == rotation && + scn_event->width == xrrs[resMode_idx].width && + scn_event->height == xrrs[resMode_idx].height; + break; + default: + DBG_PRINT("RANDR: event . unhandled %d 0x%X call %p\n", (int)evt.type, (int)evt.type, (void*)evt.xany.window); + } + XRRUpdateConfiguration(&evt); + } while(!done); - XRRSetScreenConfigAndRate(dpy, conf, root, current_mode_id, rot, current_rate, CurrentTime); - //free XRRFreeScreenConfigInfo(conf); + XSync(dpy, False); } /** @@ -1175,7 +1254,7 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CreateWindow0 } if(visualID<0) { - _throwNewRuntimeException(NULL, env, "invalid VisualID .."); + NewtCommon_throwNewRuntimeException(env, "invalid VisualID .."); return 0; } @@ -1209,7 +1288,7 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CreateWindow0 if (visual==NULL) { - _throwNewRuntimeException(dpy, env, "could not query Visual by given VisualID, bail out!"); + NewtCommon_throwNewRuntimeException(env, "could not query Visual by given VisualID, bail out!"); return 0; } @@ -1247,7 +1326,7 @@ JNIEXPORT jlong JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CreateWindow0 &xswa); if(0==window) { - _throwNewRuntimeException(dpy, env, "could not create Window, bail out!"); + NewtCommon_throwNewRuntimeException(env, "could not create Window, bail out!"); return 0; } @@ -1294,11 +1373,11 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_CloseWindow0 jwindow = getJavaWindowProperty(env, dpy, w, javaObjectAtom, True); if(NULL==jwindow) { - _throwNewRuntimeException(dpy, env, "could not fetch Java Window object, bail out!"); + NewtCommon_throwNewRuntimeException(env, "could not fetch Java Window object, bail out!"); return; } if ( JNI_FALSE == (*env)->IsSameObject(env, jwindow, obj) ) { - _throwNewRuntimeException(dpy, env, "Internal Error .. Window global ref not the same!"); + NewtCommon_throwNewRuntimeException(env, "Internal Error .. Window global ref not the same!"); return; } @@ -1416,7 +1495,6 @@ JNIEXPORT void JNICALL Java_com_jogamp_newt_impl_x11_X11Window_reconfigureWindow NewtWindows_setPosSize(dpy, w, x, y, width, height); - if(0 < fullscreenChange ) { // FS on NewtWindows_setFullscreen(dpy, root, w, True ); XSync(dpy, False); |