diff options
Diffstat (limited to 'src/newt')
24 files changed, 870 insertions, 120 deletions
diff --git a/src/newt/classes/com/jogamp/newt/MonitorDevice.java b/src/newt/classes/com/jogamp/newt/MonitorDevice.java index 4d9c6493a..ec38ce3c3 100644 --- a/src/newt/classes/com/jogamp/newt/MonitorDevice.java +++ b/src/newt/classes/com/jogamp/newt/MonitorDevice.java @@ -35,7 +35,6 @@ import com.jogamp.nativewindow.util.DimensionImmutable; import com.jogamp.nativewindow.util.Rectangle; import com.jogamp.nativewindow.util.RectangleImmutable; import com.jogamp.nativewindow.util.SurfaceSize; - import com.jogamp.common.util.ArrayHashSet; /** @@ -65,15 +64,17 @@ public abstract class MonitorDevice { protected final DimensionImmutable sizeMM; // in [mm] protected final MonitorMode originalMode; protected final ArrayHashSet<MonitorMode> supportedModes; // FIXME: May need to support mutable mode, i.e. adding modes on the fly! - protected MonitorMode currentMode; - protected boolean modeChanged; protected final float[] pixelScale; protected final Rectangle viewportPU; // in pixel units protected final Rectangle viewportWU; // in window units + protected boolean isClone; + protected MonitorMode currentMode; + protected boolean modeChanged; /** * @param screen associated {@link Screen} * @param nativeId unique monitor device ID + * @param isClone flag * @param sizeMM size in millimeters * @param currentMode * @param pixelScale pre-fetched current pixel-scale, maybe {@code null} for {@link ScalableSurface#IDENTITY_PIXELSCALE}. @@ -81,19 +82,21 @@ public abstract class MonitorDevice { * @param viewportWU viewport in window-units * @param supportedModes all supported {@link MonitorMode}s */ - protected MonitorDevice(final Screen screen, final int nativeId, final DimensionImmutable sizeMM, - final MonitorMode currentMode, - final float[] pixelScale, final Rectangle viewportPU, final Rectangle viewportWU, - final ArrayHashSet<MonitorMode> supportedModes) { + protected MonitorDevice(final Screen screen, final int nativeId, final boolean isClone, + final DimensionImmutable sizeMM, + final MonitorMode currentMode, final float[] pixelScale, final Rectangle viewportPU, + final Rectangle viewportWU, final ArrayHashSet<MonitorMode> supportedModes) { this.screen = screen; this.nativeId = nativeId; this.sizeMM = sizeMM; this.originalMode = currentMode; this.supportedModes = supportedModes; - this.currentMode = currentMode; this.pixelScale = null != pixelScale ? pixelScale : new float[] { 1.0f, 1.0f }; this.viewportPU = viewportPU; this.viewportWU = viewportWU; + + this.isClone = isClone; + this.currentMode = currentMode; this.modeChanged = false; } @@ -134,6 +137,9 @@ public abstract class MonitorDevice { /** @return the immutable unique native Id of this monitor device. */ public final int getId() { return nativeId; } + /** @return {@code true} if this device represents a <i>clone</i>, otherwise return {@code false}. */ + public final boolean isClone() { return isClone; } + /** * @return the immutable monitor size in millimeters. */ @@ -310,20 +316,22 @@ public abstract class MonitorDevice { * <p> * The returned {@link MonitorMode} is element of the lists {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}. * </p> + * @throws IllegalStateException if the {@link #getScreen() associated screen} is not {@link Screen#isNativeValid() valid natively}. * @see #getCurrentMode() */ - public abstract MonitorMode queryCurrentMode(); + public abstract MonitorMode queryCurrentMode() throws IllegalStateException; /** * Set the current {@link com.jogamp.newt.MonitorMode}. * @param mode to be made current, must be element of the list {@link #getSupportedModes()} and {@link Screen#getMonitorModes()}. * @return true if successful, otherwise false + * @throws IllegalStateException if the {@link #getScreen() associated screen} is not {@link Screen#isNativeValid() valid natively}. */ - public abstract boolean setCurrentMode(MonitorMode mode); + public abstract boolean setCurrentMode(MonitorMode mode) throws IllegalStateException; @Override public String toString() { - return "Monitor[Id "+Display.toHexString(nativeId)+", "+sizeMM+" mm, pixelScale ["+pixelScale[0]+", "+pixelScale[1]+ + return "Monitor[Id "+Display.toHexString(nativeId)+", clone "+isClone+", "+sizeMM+" mm, pixelScale ["+pixelScale[0]+", "+pixelScale[1]+ "], viewport "+viewportPU+ " [pixels], "+viewportWU+" [window], orig "+originalMode+", curr "+currentMode+ ", modeChanged "+modeChanged+", modeCount "+supportedModes.size()+"]"; } diff --git a/src/newt/classes/com/jogamp/newt/Screen.java b/src/newt/classes/com/jogamp/newt/Screen.java index 65031a565..b8f096fc3 100644 --- a/src/newt/classes/com/jogamp/newt/Screen.java +++ b/src/newt/classes/com/jogamp/newt/Screen.java @@ -210,7 +210,8 @@ public abstract class Screen { /** * Returns the {@link MonitorDevice} with the highest {@link MonitorDevice#getViewportInWindowUnits() viewport} - * {@link RectangleImmutable#coverage(RectangleImmutable) coverage} of the given rectangle in window units. + * {@link RectangleImmutable#coverage(RectangleImmutable) coverage} of the given rectangle in window units, + * which is not a {@link MonitorDevice#isClone() clone}. * <p> * If no coverage is detected the first {@link MonitorDevice} is returned. * </p> @@ -220,12 +221,15 @@ public abstract class Screen { MonitorDevice res = null; float maxCoverage = Float.MIN_VALUE; final List<MonitorDevice> monitors = getMonitorDevices(); - for(int i=monitors.size()-1; i>=0; i--) { + final int monitorCount = monitors.size(); + for(int i=0; i<monitorCount; i++) { final MonitorDevice monitor = monitors.get(i); - final float coverage = monitor.getViewportInWindowUnits().coverage(r); - if( coverage > maxCoverage ) { - maxCoverage = coverage; - res = monitor; + if( !monitor.isClone() ) { + final float coverage = monitor.getViewportInWindowUnits().coverage(r); + if( coverage > maxCoverage ) { + maxCoverage = coverage; + res = monitor; + } } } if( maxCoverage > 0.0f && null != res ) { @@ -234,6 +238,18 @@ public abstract class Screen { return monitors.get(0); } + public final MonitorDevice getMonitor(final int monitorId) { + final List<MonitorDevice> monitors = getMonitorDevices(); + final int monitorCount = monitors.size(); + for(int i=0; i<monitorCount; i++) { + final MonitorDevice monitor = monitors.get(i); + if( monitor.getId() == monitorId ) { + return monitor; + } + } + return null; + } + /** * Calculates the union of all monitor's {@link MonitorDevice#getViewport() viewport} in pixel- and window units. * <p> diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index d638b3ae5..3ef017d1b 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -1004,6 +1004,11 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind glWindow.addGLEventListener(new GLEventListener() { @Override public void init(final GLAutoDrawable drawable) { + final MonitorDevice monitor = glWindow.getMainMonitor(); + System.err.println("Main Monitor: "+monitor); + final float[] pixelPerMM = monitor.getPixelsPerMM(new float[2]); + System.err.println(" pixel/mm ["+pixelPerMM[0]+", "+pixelPerMM[1]+"]"); + System.err.println(" pixel/in ["+pixelPerMM[0]*25.4f+", "+pixelPerMM[1]*25.4f+"]"); final GL gl = drawable.getGL(); System.err.println(JoglVersion.getGLInfo(gl, null)); System.err.println("Requested: "+drawable.getNativeSurface().getGraphicsConfiguration().getRequestedCapabilities()); diff --git a/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java b/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java index 7c7d54680..3f039a9f4 100644 --- a/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java +++ b/src/newt/classes/jogamp/newt/MonitorDeviceImpl.java @@ -31,7 +31,6 @@ package jogamp.newt; import com.jogamp.nativewindow.ScalableSurface; import com.jogamp.nativewindow.util.DimensionImmutable; import com.jogamp.nativewindow.util.Rectangle; - import com.jogamp.common.util.ArrayHashSet; import com.jogamp.newt.MonitorDevice; import com.jogamp.newt.MonitorMode; @@ -42,6 +41,7 @@ public class MonitorDeviceImpl extends MonitorDevice { /** * @param screen associated {@link Screen} * @param nativeId unique monitor device ID + * @param isClone TODO * @param sizeMM size in millimeters * @param currentMode * @param pixelScale pre-fetched current pixel-scale, maybe {@code null} for {@link ScalableSurface#IDENTITY_PIXELSCALE}. @@ -49,16 +49,19 @@ public class MonitorDeviceImpl extends MonitorDevice { * @param viewportWU viewport in window-units * @param supportedModes all supported {@link MonitorMode}s */ - public MonitorDeviceImpl(final ScreenImpl screen, final int nativeId, final DimensionImmutable sizeMM, - final MonitorMode currentMode, - final float[] pixelScale, final Rectangle viewportPU, final Rectangle viewportWU, - final ArrayHashSet<MonitorMode> supportedModes) { - super(screen, nativeId, sizeMM, currentMode, pixelScale, viewportPU, viewportWU, supportedModes); + public MonitorDeviceImpl(final ScreenImpl screen, final int nativeId, final boolean isClone, + final DimensionImmutable sizeMM, + final MonitorMode currentMode, final float[] pixelScale, final Rectangle viewportPU, + final Rectangle viewportWU, final ArrayHashSet<MonitorMode> supportedModes) { + super(screen, nativeId, isClone, sizeMM, currentMode, pixelScale, viewportPU, viewportWU, supportedModes); } @Override - public final MonitorMode queryCurrentMode() { + public final MonitorMode queryCurrentMode() throws IllegalStateException { final ScreenImpl screenImpl = (ScreenImpl)screen; + if( !screenImpl.isNativeValid() ) { + throw new IllegalStateException("Screen is not created natively: "+screenImpl); + } final ScreenMonitorState sms = screenImpl.getScreenMonitorStatus(true); sms.lock(); try { @@ -87,11 +90,14 @@ public class MonitorDeviceImpl extends MonitorDevice { } @Override - public final boolean setCurrentMode(final MonitorMode mode) { + public final boolean setCurrentMode(final MonitorMode mode) throws IllegalStateException { + final ScreenImpl screenImpl = (ScreenImpl)screen; + if( !screenImpl.isNativeValid() ) { + throw new IllegalStateException("Screen is not created natively: "+screenImpl); + } if(Screen.DEBUG) { System.err.println("Screen.setCurrentMode.0: "+this+" -> "+mode); } - final ScreenImpl screenImpl = (ScreenImpl)screen; final ScreenMonitorState sms = screenImpl.getScreenMonitorStatus(true); sms.lock(); try { @@ -157,4 +163,7 @@ public class MonitorDeviceImpl extends MonitorDevice { return supportedModes; } + /* pp */ final void setIsClone(final boolean isClone) { + this.isClone = isClone; + } } diff --git a/src/newt/classes/jogamp/newt/MonitorModeProps.java b/src/newt/classes/jogamp/newt/MonitorModeProps.java index 3f9e0be78..eacf77e25 100644 --- a/src/newt/classes/jogamp/newt/MonitorModeProps.java +++ b/src/newt/classes/jogamp/newt/MonitorModeProps.java @@ -31,13 +31,17 @@ package jogamp.newt; import com.jogamp.common.util.ArrayHashSet; import com.jogamp.newt.MonitorDevice; import com.jogamp.newt.MonitorMode; +import com.jogamp.newt.Screen; +import java.util.ArrayList; import java.util.List; + import com.jogamp.nativewindow.ScalableSurface; import com.jogamp.nativewindow.util.Dimension; import com.jogamp.nativewindow.util.DimensionImmutable; import com.jogamp.nativewindow.util.Rectangle; import com.jogamp.nativewindow.util.SurfaceSize; +import com.jogamp.opengl.math.FloatUtil; import jogamp.newt.MonitorDeviceImpl; import jogamp.newt.ScreenImpl; @@ -128,6 +132,7 @@ public class MonitorModeProps { * <ul> * <li>count</li> * <li>id</li> + * <li>IsClone</li> * <li>ScreenSizeMM[width, height] (2 elements)</li> * <li>Rotated Viewport pixel-units (4 elements)</li> * <li>Rotated Viewport window-units (4 elements)</li> @@ -142,7 +147,7 @@ public class MonitorModeProps { * WARNING: must be synchronized with ScreenMode.h, native implementation * </p> */ - public static final int MIN_MONITOR_DEVICE_PROPERTIES = 15; + public static final int MIN_MONITOR_DEVICE_PROPERTIES = 16; public static final int IDX_MONITOR_DEVICE_VIEWPORT = 1 // count + 1 // native mode @@ -285,6 +290,7 @@ public class MonitorModeProps { offset++; final List<MonitorMode> allMonitorModes = cache.monitorModes.getData(); final int id = monitorProperties[offset++]; + final boolean isClone = 0 == monitorProperties[offset++] ? false : true; final DimensionImmutable sizeMM = streamInResolution(monitorProperties, offset); offset+=NUM_RESOLUTION_PROPERTIES; final Rectangle viewportPU = new Rectangle(monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++]); final Rectangle viewportWU = new Rectangle(monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++]); @@ -304,7 +310,7 @@ public class MonitorModeProps { } } } - MonitorDevice monitorDevice = new MonitorDeviceImpl(screen, id, sizeMM, currentMode, pixelScale, viewportPU, viewportWU, supportedModes); + MonitorDevice monitorDevice = new MonitorDeviceImpl(screen, id, isClone, sizeMM, currentMode, pixelScale, viewportPU, viewportWU, supportedModes); if(null!=cache) { monitorDevice = cache.monitorDevices.getOrAdd(monitorDevice); } @@ -365,10 +371,11 @@ public class MonitorModeProps { } offset++; final int id = monitorProperties[offset++]; + final boolean isClone = 0 == monitorProperties[offset++] ? false : true; final DimensionImmutable sizeMM = streamInResolution(monitorProperties, offset); offset+=NUM_RESOLUTION_PROPERTIES; final Rectangle viewportPU = new Rectangle(monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++]); final Rectangle viewportWU = new Rectangle(monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++], monitorProperties[offset++]); - MonitorDevice monitorDevice = new MonitorDeviceImpl(screen, id, sizeMM, currentMode, pixelScale, viewportPU, viewportWU, supportedModes); + MonitorDevice monitorDevice = new MonitorDeviceImpl(screen, id, isClone, sizeMM, currentMode, pixelScale, viewportPU, viewportWU, supportedModes); if(null!=cache) { monitorDevice = cache.monitorDevices.getOrAdd(monitorDevice); } @@ -393,6 +400,7 @@ public class MonitorModeProps { int idx=0; data[idx++] = data.length; data[idx++] = monitorDevice.getId(); + data[idx++] = monitorDevice.isClone() ? 1 : 0; data[idx++] = monitorDevice.getSizeMM().getWidth(); data[idx++] = monitorDevice.getSizeMM().getHeight(); data[idx++] = monitorDevice.getViewport().getX(); @@ -415,7 +423,36 @@ public class MonitorModeProps { return data; } - public final void swapRotatePair(final int rotation, final int[] pairs, int offset, final int numPairs) { + /** Identify monitor devices in <i>cloned</i> mode, i.e. consecutive devices being 100% covered by preceding devices. */ + /* pp */ static void identifyClonedMonitorDevices(final MonitorModeProps.Cache cache) { + final ArrayList<MonitorDevice> monitors = cache.monitorDevices.toArrayList(); + final int monitorCount = monitors.size(); + for(int i=0; i<monitorCount; i++) { + final MonitorDevice a = monitors.get(i); + if( !a.isClone() ) { + for(int j=i+1; j<monitorCount; j++) { + final MonitorDevice b = monitors.get(j); + if( !b.isClone() ) { + final float coverage = b.getViewport().coverage( a.getViewport() ); + if( FloatUtil.isZero( 1f - coverage, FloatUtil.EPSILON ) ) { + ((MonitorDeviceImpl)b).setIsClone(true); + if( Screen.DEBUG ) { + System.err.printf("MonitorCloneTest[%d of %d]: %f -> _is_ covered%n", j, i, coverage); + System.err.printf(" Monitor[%d] %s%n", j, b.toString()); + System.err.printf(" Monitor[%d] %s%n", i, a.toString()); + } + } else if( Screen.DEBUG ) { + System.err.printf("MonitorDevice-CloneTest[%d of %d]: %f -> not covered%n", j, i, coverage); + System.err.printf(" Monitor[%d] %s%n", j, b.toString()); + System.err.printf(" Monitor[%d] %s%n", i, a.toString()); + } + } + } + } + } + } + + public static final void swapRotatePair(final int rotation, final int[] pairs, int offset, final int numPairs) { if( MonitorMode.ROTATE_0 == rotation || MonitorMode.ROTATE_180 == rotation ) { // nop return; diff --git a/src/newt/classes/jogamp/newt/ScreenImpl.java b/src/newt/classes/jogamp/newt/ScreenImpl.java index b8383b631..36e42e52c 100644 --- a/src/newt/classes/jogamp/newt/ScreenImpl.java +++ b/src/newt/classes/jogamp/newt/ScreenImpl.java @@ -500,6 +500,7 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { int i = 0; props[i++] = MonitorModeProps.MIN_MONITOR_DEVICE_PROPERTIES; props[i++] = monitorId; + props[i++] = 0; // is-clone props[i++] = default_sm_widthmm; props[i++] = default_sm_heightmm; props[i++] = 0; // rotated viewport x pixel-units @@ -608,6 +609,7 @@ public abstract class ScreenImpl extends Screen implements MonitorModeListener { private final int collectNativeMonitorModes(final MonitorModeProps.Cache cache) { if(!DEBUG_TEST_SCREENMODE_DISABLED) { collectNativeMonitorModesAndDevicesImpl(cache); + MonitorModeProps.identifyClonedMonitorDevices(cache); } // filter out insufficient modes for(int i=cache.monitorModes.size()-1; i>=0; i--) { diff --git a/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java index 23e9c4370..4faa5de9c 100644 --- a/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java +++ b/src/newt/classes/jogamp/newt/awt/NewtFactoryAWT.java @@ -28,17 +28,30 @@ package jogamp.newt.awt; +import java.awt.GraphicsDevice; + import com.jogamp.nativewindow.AbstractGraphicsConfiguration; import com.jogamp.nativewindow.CapabilitiesImmutable; import com.jogamp.nativewindow.NativeWindow; import com.jogamp.nativewindow.NativeWindowException; import com.jogamp.nativewindow.NativeWindowFactory; +import jogamp.nativewindow.awt.AWTMisc; +import jogamp.nativewindow.jawt.JAWTUtil; +import jogamp.nativewindow.jawt.x11.X11SunJDKReflection; +import jogamp.nativewindow.x11.X11Lib; import jogamp.newt.Debug; import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration; +import com.jogamp.nativewindow.awt.AWTGraphicsScreen; import com.jogamp.nativewindow.awt.JAWTWindow; +import com.jogamp.nativewindow.util.Point; +import com.jogamp.nativewindow.util.Rectangle; +import com.jogamp.nativewindow.util.RectangleImmutable; +import com.jogamp.newt.Display; +import com.jogamp.newt.MonitorDevice; import com.jogamp.newt.NewtFactory; +import com.jogamp.newt.Screen; public class NewtFactoryAWT extends NewtFactory { public static final boolean DEBUG_IMPLEMENTATION = Debug.debug("Window"); @@ -83,5 +96,102 @@ public class NewtFactoryAWT extends NewtFactory { config.getScreen().getDevice().close(); } + /** + * @param awtComp + * @throws IllegalArgumentException if {@code awtComp} is not {@link java.awt.Component#isDisplayable() displayable} + * or has {@code null} {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration}. + */ + private static void checkComponentValid(final java.awt.Component awtComp) throws IllegalArgumentException { + if( !awtComp.isDisplayable() ) { + throw new IllegalArgumentException("Given AWT-Component is not displayable: "+awtComp); + } + if( null == awtComp.getGraphicsConfiguration() ) { + throw new IllegalArgumentException("Given AWT-Component has no GraphicsConfiguration set: "+awtComp); + } + } + + /** + * @param awtComp must be {@link java.awt.Component#isDisplayable() displayable} + * and must have a {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration} + * @param reuse attempt to reuse an existing {@link Display} with same <code>name</code> if set true, otherwise create a new instance. + * @return {@link Display} instance reflecting the {@code awtComp} + * @throws IllegalArgumentException if {@code awtComp} is not {@link java.awt.Component#isDisplayable() displayable} + * or has {@code null} {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration}. + * @see #getAbstractGraphicsScreen(java.awt.Component) + */ + public static Display createDisplay(final java.awt.Component awtComp, final boolean reuse) throws IllegalArgumentException { + checkComponentValid(awtComp); + final GraphicsDevice device = awtComp.getGraphicsConfiguration().getDevice(); + + final String displayConnection; + final String nwt = NativeWindowFactory.getNativeWindowType(true); + if( NativeWindowFactory.TYPE_X11 == nwt ) { + final long displayHandleAWT = X11SunJDKReflection.graphicsDeviceGetDisplay(device); + if( 0 == displayHandleAWT ) { + displayConnection = null; // default + } else { + /** + * Using the AWT display handle works fine with NVidia. + * However we experienced different results w/ AMD drivers, + * some work, but some behave erratic. + * I.e. hangs in XQueryExtension(..) via X11GraphicsScreen. + */ + displayConnection = X11Lib.XDisplayString(displayHandleAWT); + } + } else { + displayConnection = null; // default + } + return NewtFactory.createDisplay(displayConnection, reuse); + } + + /** + * @param awtComp must be {@link java.awt.Component#isDisplayable() displayable} + * and must have a {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration} + * @param reuse attempt to reuse an existing {@link Display} with same <code>name</code> if set true, otherwise create a new instance. + * @return {@link Screen} instance reflecting the {@code awtComp} + * @throws IllegalArgumentException if {@code awtComp} is not {@link java.awt.Component#isDisplayable() displayable} + * or has {@code null} {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration}. + * @see #createDevice(java.awt.Component) + */ + public static Screen createScreen(final java.awt.Component awtComp, final boolean reuse) throws IllegalArgumentException { + final Display display = createDisplay(awtComp, reuse); + return NewtFactory.createScreen(display, AWTGraphicsScreen.findScreenIndex(awtComp.getGraphicsConfiguration().getDevice())); + } + + /** + * Retrieves the {@link MonitorDevice} for the given displayable {@code awtComp}. + * <p> + * In case this method shall be called multiple times, it is advised to keep the given {@link Screen} instance + * natively created during operation. This should be done via the initial {@link Screen#addReference()}. + * After operation, user shall destroy the instance accordingly via the final {@link Screen#removeReference()}. + * </p> + * @param screen the {@link Screen} instance matching {@code awtComp}, i.e. via {@link #createScreen(java.awt.Component, boolean)}. + * @param awtComp must be {@link java.awt.Component#isDisplayable() displayable} + * and must have a {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration} + * @return {@link MonitorDevice} instance reflecting the {@code awtComp} + * @throws IllegalArgumentException if {@code awtComp} is not {@link java.awt.Component#isDisplayable() displayable} + * or has {@code null} {@link java.awt.Component#getGraphicsConfiguration() GraphicsConfiguration}. + * @see #createScreen(java.awt.Component, boolean) + */ + public static MonitorDevice getMonitorDevice(final Screen screen, final java.awt.Component awtComp) throws IllegalArgumentException { + checkComponentValid(awtComp); + final String nwt = NativeWindowFactory.getNativeWindowType(true); + MonitorDevice res = null; + screen.addReference(); + try { + if( NativeWindowFactory.TYPE_MACOSX == nwt ) { + res = screen.getMonitor( JAWTUtil.getMonitorIndex( awtComp.getGraphicsConfiguration().getDevice() ) ); + } + if( null == res ) { + // Fallback, use AWT component coverage + final Point los = AWTMisc.getLocationOnScreenSafe(null, awtComp, false); + final RectangleImmutable r = new Rectangle(los.getX(), los.getY(), awtComp.getWidth(), awtComp.getHeight()); + res = screen.getMainMonitor(r); + } + } finally { + screen.removeReference(); + } + return res; + } } diff --git a/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java index 273ff2b45..60e6e7d5f 100644 --- a/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/android/ScreenDriver.java @@ -104,6 +104,7 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl { int i = 0; props[i++] = props.length; props[i++] = 0; // crt_idx + props[i++] = 0; // is-clone i = getScreenSizeMM(outMetrics, props, i); // sizeMM props[i++] = 0; // rotated viewport x pixel-units props[i++] = 0; // rotated viewport y pixel-units diff --git a/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java index eb92e0d13..aba7a1ab9 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/awt/ScreenDriver.java @@ -109,6 +109,7 @@ public class ScreenDriver extends ScreenImpl { int i = 0; props[i++] = props.length; props[i++] = 0; // crt_idx + props[i++] = 0; // is-clone props[i++] = ScreenImpl.default_sm_widthmm; // FIXME props[i++] = ScreenImpl.default_sm_heightmm; // FIXME props[i++] = 0; // rotated viewport x pixel-units diff --git a/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java index e65d79e2a..704fad73f 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/egl/ScreenDriver.java @@ -84,6 +84,7 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl { i = 0; props[i++] = props.length; props[i++] = 0; // crt_idx + props[i++] = 0; // is-clone props[i++] = ScreenImpl.default_sm_widthmm; // FIXME props[i++] = ScreenImpl.default_sm_heightmm; // FIXME props[i++] = 0; // rotated viewport x pixel-units diff --git a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/ScreenDriver.java index 42a63f91e..8d46adeab 100644 --- a/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/bcm/vc/iv/ScreenDriver.java @@ -77,6 +77,7 @@ public class ScreenDriver extends ScreenImpl { i = 0; props[i++] = props.length; props[i++] = 0; // crt_idx + props[i++] = 0; // is-clone props[i++] = ScreenImpl.default_sm_widthmm; // FIXME props[i++] = ScreenImpl.default_sm_heightmm; // FIXME props[i++] = 0; // rotated viewport x pixel-units diff --git a/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java index bd99fd18c..b55378459 100644 --- a/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/intel/gdl/ScreenDriver.java @@ -86,6 +86,7 @@ public class ScreenDriver extends jogamp.newt.ScreenImpl { i = 0; props[i++] = props.length; props[i++] = 0; // crt_idx + props[i++] = 0; // is-clone props[i++] = ScreenImpl.default_sm_widthmm; // FIXME props[i++] = ScreenImpl.default_sm_heightmm; // FIXME props[i++] = 0; // rotated viewport x pixel-units diff --git a/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java index 975e0f96e..1e878bc3a 100644 --- a/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/kd/ScreenDriver.java @@ -82,6 +82,7 @@ public class ScreenDriver extends ScreenImpl { i = 0; props[i++] = props.length; props[i++] = 0; // crt_idx + props[i++] = 0; // is-clone props[i++] = ScreenImpl.default_sm_widthmm; // FIXME props[i++] = ScreenImpl.default_sm_heightmm; // FIXME props[i++] = 0; // rotated viewport x pixel-units diff --git a/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java index b476ee38a..013f9f9ca 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java @@ -65,65 +65,81 @@ public class ScreenDriver extends ScreenImpl { protected void closeNativeImpl() { } - private final String getAdapterName(final int crt_idx) { - return getAdapterName0(crt_idx); + private final String getAdapterName(final int adapter_idx) { + return getAdapterName0(adapter_idx); } - private final String getActiveMonitorName(final String adapterName, final int monitor_idx) { - return getActiveMonitorName0(adapterName, monitor_idx); + private final String getMonitorName(final String adapterName, final int monitor_idx, final boolean onlyActive) { + return getMonitorName0(adapterName, monitor_idx, onlyActive); } - private final MonitorMode getMonitorModeImpl(final MonitorModeProps.Cache cache, final String adapterName, final int crtModeIdx) { + private final MonitorMode getMonitorModeImpl(final MonitorModeProps.Cache cache, final String adapterName, final int mode_idx) { if( null == adapterName ) { return null; } - final String activeMonitorName = getActiveMonitorName(adapterName, 0); - final int[] modeProps = null != activeMonitorName ? getMonitorMode0(adapterName, crtModeIdx) : null; + final int[] modeProps = getMonitorMode0(adapterName, mode_idx); if ( null == modeProps || 0 >= modeProps.length) { return null; } return MonitorModeProps.streamInMonitorMode(null, cache, modeProps, 0); } + private static final int getMonitorId(final int adapterIdx, final int monitorIdx) { + if( adapterIdx > 0xff ) { + throw new InternalError("Unsupported adapter idx > 0xff: "+adapterIdx); + } + if( monitorIdx > 0xff ) { + throw new InternalError("Unsupported monitor idx > 0xff: "+monitorIdx); + } + return ( adapterIdx & 0x000000ff ) << 8 | ( monitorIdx & 0x000000ff ); + } + private static final int getAdapterIndex(final int monitorId) { + return ( monitorId >>> 8 ) & 0x000000ff; + } + private static final int getMonitorIndex(final int monitorId) { + return monitorId & 0x000000ff; + } + @Override protected void collectNativeMonitorModesAndDevicesImpl(final MonitorModeProps.Cache cache) { - int crtIdx = 0; ArrayHashSet<MonitorMode> supportedModes = new ArrayHashSet<MonitorMode>(); - String adapterName = getAdapterName(crtIdx); - while( null != adapterName ) { - int crtModeIdx = 0; - MonitorMode mode; - do { - mode = getMonitorModeImpl(cache, adapterName, crtModeIdx); - if( null != mode ) { - supportedModes.getOrAdd(mode); - // next mode on same monitor - crtModeIdx++; - } - } while( null != mode); - if( 0 < crtModeIdx ) { - // has at least one mode -> add device - final MonitorMode currentMode = getMonitorModeImpl(cache, adapterName, -1); - if ( null != currentMode ) { // enabled - final int[] monitorProps = getMonitorDevice0(adapterName, crtIdx); - // merge monitor-props + supported modes - MonitorModeProps.streamInMonitorDevice(cache, this, currentMode, null, supportedModes, monitorProps, 0, null); - - // next monitor, 1st mode - supportedModes= new ArrayHashSet<MonitorMode>(); + String adapterName; + for(int adapterIdx=0; null != ( adapterName = getAdapterName(adapterIdx) ); adapterIdx++ ) { + for(int monitorIdx=0; null != getMonitorName(adapterName, monitorIdx, true); monitorIdx++ ) { + int modeIdx = 0; + MonitorMode mode; + do { + mode = getMonitorModeImpl(cache, adapterName, modeIdx); + if( null != mode ) { + supportedModes.getOrAdd(mode); + // next mode on same monitor + modeIdx++; + } + } while( null != mode); + if( 0 < modeIdx ) { + // has at least one mode -> add device + final MonitorMode currentMode = getMonitorModeImpl(cache, adapterName, -1); + if ( null != currentMode ) { // enabled + final int[] monitorProps = getMonitorDevice0(adapterName, adapterIdx, monitorIdx, getMonitorId(adapterIdx, monitorIdx)); + // merge monitor-props + supported modes + MonitorModeProps.streamInMonitorDevice(cache, this, currentMode, null, supportedModes, monitorProps, 0, null); + + // next monitor, 1st mode + supportedModes = new ArrayHashSet<MonitorMode>(); + } } } - crtIdx++; - adapterName = getAdapterName(crtIdx); } } @Override protected boolean updateNativeMonitorDeviceViewportImpl(final MonitorDevice monitor, final float[] pixelScale, final Rectangle viewportPU, final Rectangle viewportWU) { - final String adapterName = getAdapterName(monitor.getId()); + final int monitorId = monitor.getId(); + final int adapterIdx = getAdapterIndex(monitorId); + final int monitorIdx = getMonitorIndex(monitorId); + final String adapterName = getAdapterName(adapterIdx); if( null != adapterName ) { - final String activeMonitorName = getActiveMonitorName(adapterName, 0); - if( null != activeMonitorName ) { - final int[] monitorProps = getMonitorDevice0(adapterName, monitor.getId()); + if( null != getMonitorName(adapterName, monitorIdx, true) ) { + final int[] monitorProps = getMonitorDevice0(adapterName, adapterIdx, monitorIdx, getMonitorId(adapterIdx, monitorIdx)); int offset = MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT; viewportPU.set(monitorProps[offset++], monitorProps[offset++], monitorProps[offset++], monitorProps[offset++]); viewportWU.set(monitorProps[offset++], monitorProps[offset++], monitorProps[offset++], monitorProps[offset++]); @@ -135,12 +151,12 @@ public class ScreenDriver extends ScreenImpl { @Override protected MonitorMode queryCurrentMonitorModeImpl(final MonitorDevice monitor) { - return getMonitorModeImpl(null, getAdapterName(monitor.getId()), -1); + return getMonitorModeImpl(null, getAdapterName(getAdapterIndex(monitor.getId())), -1); } @Override protected boolean setCurrentMonitorModeImpl(final MonitorDevice monitor, final MonitorMode mode) { - return setMonitorMode0(monitor.getId(), + return setMonitorMode0(getAdapterIndex(monitor.getId()), -1, -1, // no fixed position! mode.getSurfaceSize().getResolution().getWidth(), mode.getSurfaceSize().getResolution().getHeight(), @@ -168,9 +184,9 @@ public class ScreenDriver extends ScreenImpl { private native int getVirtualHeightImpl0(); private static native void dumpMonitorInfo0(); - private native String getAdapterName0(int crt_index); - private native String getActiveMonitorName0(String adapterName, int crtModeIdx); - private native int[] getMonitorMode0(String adapterName, int crtModeIdx); - private native int[] getMonitorDevice0(String adapterName, int monitor_index); - private native boolean setMonitorMode0(int monitor_index, int x, int y, int width, int height, int bits, int freq, int flags, int rot); + private native String getAdapterName0(int adapter_idx); + private native String getMonitorName0(String adapterName, int monitor_idx, boolean onlyActive); + private native int[] getMonitorMode0(String adapterName, int mode_idx); + private native int[] getMonitorDevice0(String adapterName, int adapter_idx, int monitor_idx, int monitorId); + private native boolean setMonitorMode0(int adapter_idx, int x, int y, int width, int height, int bits, int freq, int flags, int rot); } diff --git a/src/newt/classes/jogamp/newt/driver/x11/RandR11.java b/src/newt/classes/jogamp/newt/driver/x11/RandR11.java index d11703e47..a4c578b26 100644 --- a/src/newt/classes/jogamp/newt/driver/x11/RandR11.java +++ b/src/newt/classes/jogamp/newt/driver/x11/RandR11.java @@ -186,6 +186,7 @@ class RandR11 implements RandR { int i = 0; props[i++] = props.length; props[i++] = crt_idx; + props[i++] = 0; // is-clone props[i++] = widthMM; props[i++] = heightMM; props[i++] = 0; // rotated viewport x pixel-units diff --git a/src/newt/native/MacWindow.m b/src/newt/native/MacWindow.m index e0f8be856..690aaa505 100644 --- a/src/newt/native/MacWindow.m +++ b/src/newt/native/MacWindow.m @@ -517,6 +517,7 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_macosx_ScreenDriver_getMonit int offset = 0; prop[offset++] = propCount; prop[offset++] = crt_idx; + prop[offset++] = 0; // is-clone prop[offset++] = (jint) sizeMM.width; prop[offset++] = (jint) sizeMM.height; prop[offset++] = (jint) dBounds.origin.x; // rotated viewport x (pixel units, will be fixed in java code) diff --git a/src/newt/native/ScreenMode.h b/src/newt/native/ScreenMode.h index 56c424b11..18e773107 100644 --- a/src/newt/native/ScreenMode.h +++ b/src/newt/native/ScreenMode.h @@ -40,7 +40,7 @@ #define NUM_MONITOR_MODE_PROPERTIES_ALL 8 /* count + the above */ -#define MIN_MONITOR_DEVICE_PROPERTIES 15 /* count + id, ScreenSizeMM[width, height], rotated Viewport pixel-units, rotated Viewport pixel-units, currentMonitorModeId, rotation, supportedModeId+ */ +#define MIN_MONITOR_DEVICE_PROPERTIES 16 /* count + id + is_clone, ScreenSizeMM[width, height], rotated Viewport pixel-units, rotated Viewport pixel-units, currentMonitorModeId, rotation, supportedModeId+ */ /* Viewport := [x, y, width, height] (4 elements) */ #define FLAG_INTERLACE ( 1 << 0 ) diff --git a/src/newt/native/WindowsEDID.c b/src/newt/native/WindowsEDID.c new file mode 100644 index 000000000..d84773dc6 --- /dev/null +++ b/src/newt/native/WindowsEDID.c @@ -0,0 +1,419 @@ +/** + * Copyright 2015 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. + * + *** + * + * This code is inspired by Ofek Shilon's code and blog post: + * <http://ofekshilon.com/2014/06/19/reading-specific-monitor-dimensions/> + * See: function 'NewtEDID_GetMonitorSizeFromEDIDByModelName' + * + * In contrast to Ofek's code, function 'NewtEDID_GetMonitorSizeFromEDIDByDevice' + * uses the proper link from + * DISPLAY_DEVICE.DeviceID -> SP_DEVICE_INTERFACE_DETAIL_DATA.DevicePath, + * where DISPLAY_DEVICE.DeviceID is the monitor's enumeration via: + * EnumDisplayDevices(adapterName, monitor_idx, &ddMon, EDD_GET_DEVICE_INTERFACE_NAME); + * Hence the path to the registry-entry is well determined instead of just comparing + * the monitor's model name. + * + */ + +#include <Windows.h> +#include <Windowsx.h> +#include <tchar.h> +#include <stdlib.h> +#include <stdio.h> +#include <stddef.h> + +#include <SetupApi.h> +#include <cfgmgr32.h> // for MAX_DEVICE_ID_LEN + +#include "WindowsEDID.h" + +// #define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(x, ...) _ftprintf(stderr, __T(x), ##__VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif + +#define NAME_SIZE 128 + +/* GetProcAddress doesn't exist in A/W variants under desktop Windows */ +#ifndef UNDER_CE +#define GetProcAddressA GetProcAddress +#endif + +#ifndef EDD_GET_DEVICE_INTERFACE_NAME +#define EDD_GET_DEVICE_INTERFACE_NAME 0x00000001 +#endif + +static const GUID GUID_CLASS_MONITOR = { 0x4d36e96e, 0xe325, 0x11ce, 0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18 }; +static const GUID GUID_DEVINTERFACE_MONITOR = { 0xe6f07b5f, 0xee97, 0x4a90, 0xb0, 0x76, 0x33, 0xf5, 0x7b, 0xf4, 0xea, 0xa7 }; + +#ifdef _UNICODE +typedef HDEVINFO (WINAPI *SetupDiGetClassDevsPROCADDR)(CONST GUID *ClassGuid,PCWSTR Enumerator,HWND hwndParent,DWORD Flags); +typedef WINBOOL (WINAPI *SetupDiGetDeviceInstanceIdPROCADDR)(HDEVINFO DeviceInfoSet,PSP_DEVINFO_DATA DeviceInfoData,PCWSTR DeviceInstanceId,DWORD DeviceInstanceIdSize,PDWORD RequiredSize); +typedef WINBOOL (WINAPI *SetupDiGetDeviceInterfaceDetailPROCADDR)(HDEVINFO DeviceInfoSet,PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,PSP_DEVICE_INTERFACE_DETAIL_DATA_W DeviceInterfaceDetailData,DWORD DeviceInterfaceDetailDataSize,PDWORD RequiredSize,PSP_DEVINFO_DATA DeviceInfoData); +#else +typedef HDEVINFO (WINAPI *SetupDiGetClassDevsPROCADDR)(CONST GUID *ClassGuid,PCSTR Enumerator,HWND hwndParent,DWORD Flags); +typedef WINBOOL (WINAPI *SetupDiGetDeviceInstanceIdPROCADDR)(HDEVINFO DeviceInfoSet,PSP_DEVINFO_DATA DeviceInfoData,PSTR DeviceInstanceId,DWORD DeviceInstanceIdSize,PDWORD RequiredSize); +typedef WINBOOL (WINAPI *SetupDiGetDeviceInterfaceDetailPROCADDR)(HDEVINFO DeviceInfoSet,PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData,PSP_DEVICE_INTERFACE_DETAIL_DATA_A DeviceInterfaceDetailData,DWORD DeviceInterfaceDetailDataSize,PDWORD RequiredSize,PSP_DEVINFO_DATA DeviceInfoData); +#endif + +typedef WINBOOL (WINAPI *SetupDiEnumDeviceInfoPROCADDR)(HDEVINFO DeviceInfoSet,DWORD MemberIndex,PSP_DEVINFO_DATA DeviceInfoData); +typedef WINBOOL (WINAPI *SetupDiEnumDeviceInterfacesPROCADDR)(HDEVINFO DeviceInfoSet,PSP_DEVINFO_DATA DeviceInfoData,CONST GUID *InterfaceClassGuid,DWORD MemberIndex,PSP_DEVICE_INTERFACE_DATA DeviceInterfaceData); +typedef HKEY (WINAPI *SetupDiOpenDevRegKeyPROCADDR)(HDEVINFO DeviceInfoSet,PSP_DEVINFO_DATA DeviceInfoData,DWORD Scope,DWORD HwProfile,DWORD KeyType,REGSAM samDesired); +typedef WINBOOL (WINAPI *SetupDiDestroyDeviceInfoListPROCADDR)(HDEVINFO DeviceInfoSet); + +static int WinSetupAPI_avail = 0; +static SetupDiGetClassDevsPROCADDR WinSetup_SetupDiGetClassDevs = NULL; +static SetupDiGetDeviceInstanceIdPROCADDR WinSetup_SetupDiGetDeviceInstanceId = NULL; +static SetupDiGetDeviceInterfaceDetailPROCADDR WinSetup_SetupDiGetDeviceInterfaceDetail = NULL; +static SetupDiEnumDeviceInfoPROCADDR WinSetup_SetupDiEnumDeviceInfo = NULL; +static SetupDiEnumDeviceInterfacesPROCADDR WinSetup_SetupDiEnumDeviceInterfaces = NULL; +static SetupDiOpenDevRegKeyPROCADDR WinSetup_SetupDiOpenDevRegKey = NULL; +static SetupDiDestroyDeviceInfoListPROCADDR WinSetup_SetupDiDestroyDeviceInfoList = NULL; + +static int _init = 0; + +int NewtEDID_init() { + if( !_init ) { + WinSetupAPI_avail = 0; + HANDLE setup = LoadLibrary(TEXT("setupapi.dll")); + if( setup ) { + #ifdef _UNICODE + WinSetup_SetupDiGetClassDevs = (SetupDiGetClassDevsPROCADDR) GetProcAddressA(setup, "SetupDiGetClassDevsW"); + WinSetup_SetupDiGetDeviceInstanceId = (SetupDiGetDeviceInstanceIdPROCADDR) GetProcAddressA(setup, "SetupDiGetDeviceInstanceIdW"); + WinSetup_SetupDiGetDeviceInterfaceDetail = (SetupDiGetDeviceInterfaceDetailPROCADDR) GetProcAddressA(setup, "SetupDiGetDeviceInterfaceDetailW"); + #else + WinSetup_SetupDiGetClassDevs = (SetupDiGetClassDevsPROCADDR) GetProcAddressA(setup, "SetupDiGetClassDevsA"); + WinSetup_SetupDiGetDeviceInstanceId = (SetupDiGetDeviceInstanceIdPROCADDR) GetProcAddressA(setup, "SetupDiGetDeviceInstanceIdA"); + WinSetup_SetupDiGetDeviceInterfaceDetail = (SetupDiGetDeviceInterfaceDetailPROCADDR) GetProcAddressA(setup, "SetupDiGetDeviceInterfaceDetailA"); + #endif + WinSetup_SetupDiEnumDeviceInfo = (SetupDiEnumDeviceInfoPROCADDR) GetProcAddressA(setup, "SetupDiEnumDeviceInfo"); + WinSetup_SetupDiEnumDeviceInterfaces = (SetupDiEnumDeviceInterfacesPROCADDR) GetProcAddressA(setup, "SetupDiEnumDeviceInterfaces"); + WinSetup_SetupDiOpenDevRegKey = (SetupDiOpenDevRegKeyPROCADDR) GetProcAddressA(setup, "SetupDiOpenDevRegKey"); + WinSetup_SetupDiDestroyDeviceInfoList = (SetupDiDestroyDeviceInfoListPROCADDR) GetProcAddressA(setup, "SetupDiDestroyDeviceInfoList"); + if( NULL != WinSetup_SetupDiGetClassDevs && + NULL != WinSetup_SetupDiGetDeviceInstanceId && + NULL != WinSetup_SetupDiGetDeviceInterfaceDetail && + NULL != WinSetup_SetupDiEnumDeviceInfo && + NULL != WinSetup_SetupDiEnumDeviceInterfaces && + NULL != WinSetup_SetupDiOpenDevRegKey && + NULL != WinSetup_SetupDiDestroyDeviceInfoList ) { + WinSetupAPI_avail = 1; + } + } + _init = 1; + } + return WinSetupAPI_avail; +} + +static _TCHAR* Get2ndSlashBlock(const _TCHAR* sIn, _TCHAR* sOut, size_t sOutLen) +{ + _TCHAR* s = _tcschr(sIn, '\\'); + if( NULL != s ) { + s += 1; // skip '\\' + _TCHAR* t = _tcschr(s, '\\'); + if( NULL != t ) { + size_t len = t - s; + if( len > 0 ) { + if( sOutLen >= len ) { + _tcsncpy_s(sOut, sOutLen, s, len); + return sOut; + } + } + } + } + return NULL; +} + +static int GetMonitorSizeFromEDIDByRegKey(const HKEY hEDIDRegKey, int* widthMm, int* heightMm, int *widthCm, int *heightCm) +{ + DWORD dwType, actualValueNameLength = NAME_SIZE; + _TCHAR valueName[NAME_SIZE]; + + BYTE edidData[1024]; + DWORD edidSize = sizeof(edidData); + + *widthMm = -1; + *heightMm = -1; + *widthCm = -1; + *heightCm = -1; + + LONG retValue; + DWORD i; + for (i = 0, retValue = ERROR_SUCCESS; retValue != ERROR_NO_MORE_ITEMS; i++) { + retValue = RegEnumValue(hEDIDRegKey, i, &valueName[0], + &actualValueNameLength, NULL, &dwType, + edidData, // buffer + &edidSize); // buffer size + + if ( retValue == ERROR_SUCCESS && edidSize >= 23 && + 0 == _tcscmp(valueName, _T("EDID")) ) + { + DBG_PRINT("*** EDID Version %d.%d, data-size %d\n", (int)edidData[18], (int)edidData[19], edidSize); + if( edidSize >= 69 ) { + // 54 + 12 = 66: Horizontal display size, mm, 8 lsbits (0–4095 mm, 161 in) + // 54 + 13 = 67: Vertical display size, mm, 8 lsbits (0–4095 mm, 161 in) + // 54 + 14 = 68: + // Bits 7–4 Horizontal display size, mm, 4 msbits + // Bits 3–0 Vertical display size, mm, 4 msbits + *widthMm = ( (int)(edidData[68] & 0xF0) << 4 ) | (int)edidData[66]; + *heightMm = ( (int)(edidData[68] & 0x0F) << 8 ) | (int)edidData[67]; + } + *widthCm = (int) edidData[21]; + *heightCm = (int) edidData[22]; + return 1; // valid EDID found + } + } + return 0; // EDID not found +} + +int NewtEDID_GetMonitorSizeFromEDIDByModelName(const DISPLAY_DEVICE* ddMon, int* widthMm, int* heightMm, int *widthCm, int *heightCm) +{ + _TCHAR useDevModelNameStore[MAX_DEVICE_ID_LEN]; + _TCHAR *useDevModelName = Get2ndSlashBlock(ddMon->DeviceID, useDevModelNameStore, MAX_DEVICE_ID_LEN); + if( NULL == useDevModelName ) { + return 0; + } + + HDEVINFO devInfo = WinSetup_SetupDiGetClassDevs( + &GUID_CLASS_MONITOR, //class GUID + NULL, //enumerator + NULL, //HWND + DIGCF_PRESENT | DIGCF_PROFILE); // Flags //DIGCF_ALLCLASSES| + + if (NULL == devInfo) { + return 0; + } + + int bRes = 0; + DWORD i; + DWORD lastError = ERROR_SUCCESS; + for (i = 0; !bRes && ERROR_SUCCESS == lastError; i++) { + SP_DEVINFO_DATA devInfoData; + memset(&devInfoData, 0, sizeof(devInfoData)); + devInfoData.cbSize = sizeof(devInfoData); + + if (WinSetup_SetupDiEnumDeviceInfo(devInfo, i, &devInfoData)) { + _TCHAR devModelName[MAX_DEVICE_ID_LEN]; + WinSetup_SetupDiGetDeviceInstanceId(devInfo, &devInfoData, devModelName, MAX_PATH, NULL); + + if( NULL != _tcsstr(devModelName, useDevModelName) ) { + HKEY hEDIDRegKey = WinSetup_SetupDiOpenDevRegKey(devInfo, &devInfoData, + DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); + + if ( 0 != hEDIDRegKey && hEDIDRegKey != INVALID_HANDLE_VALUE ) { + bRes = GetMonitorSizeFromEDIDByRegKey(hEDIDRegKey, widthMm, heightMm, widthCm, heightCm); + RegCloseKey(hEDIDRegKey); + } + } + } + lastError = GetLastError(); + } + WinSetup_SetupDiDestroyDeviceInfoList(devInfo); + return bRes; +} + +int NewtEDID_GetMonitorSizeFromEDIDByDevice(const DISPLAY_DEVICE* ddMon, int* widthMm, int* heightMm, int *widthCm, int *heightCm) +{ + HDEVINFO devInfo = WinSetup_SetupDiGetClassDevs( + &GUID_DEVINTERFACE_MONITOR, + NULL, //enumerator + NULL, //HWND + DIGCF_DEVICEINTERFACE | DIGCF_PRESENT); // Flags //DIGCF_ALLCLASSES| + + if (NULL == devInfo) { + return 0; + } + + DWORD devIfaceDetailDataSize = offsetof(SP_DEVICE_INTERFACE_DETAIL_DATA, DevicePath) + MAX_PATH * sizeof(TCHAR); + PSP_DEVICE_INTERFACE_DETAIL_DATA pDevIfaceDetailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(devIfaceDetailDataSize); + + int bRes = 0; + DWORD i; + DWORD lastError = ERROR_SUCCESS; + for (i = 0; !bRes && ERROR_SUCCESS == lastError; i++) { + SP_DEVICE_INTERFACE_DATA devIfaceData; + memset(&devIfaceData, 0, sizeof(devIfaceData)); + devIfaceData.cbSize = sizeof(devIfaceData); + + if ( WinSetup_SetupDiEnumDeviceInterfaces(devInfo, NULL, &GUID_DEVINTERFACE_MONITOR, i, &devIfaceData) ) { + memset(pDevIfaceDetailData, 0, devIfaceDetailDataSize); + pDevIfaceDetailData->cbSize = sizeof(*pDevIfaceDetailData); + DWORD devIfaceDetailDataReqSize = 0; + SP_DEVINFO_DATA devInfoData2; + memset(&devInfoData2, 0, sizeof(devInfoData2)); + devInfoData2.cbSize = sizeof(devInfoData2); + if( WinSetup_SetupDiGetDeviceInterfaceDetail(devInfo, &devIfaceData, pDevIfaceDetailData, devIfaceDetailDataSize, + &devIfaceDetailDataReqSize, &devInfoData2) ) { + int found = 0 == _tcsicmp(pDevIfaceDetailData->DevicePath, ddMon->DeviceID); + DBG_PRINT("*** Got[%d].2 found %d, devicePath <%s>\n", i, found, pDevIfaceDetailData->DevicePath); + if( found ) { + HKEY hEDIDRegKey = WinSetup_SetupDiOpenDevRegKey(devInfo, &devInfoData2, + DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); + DBG_PRINT("*** Got[%d] hEDIDRegKey %p\n", i, (void*)hEDIDRegKey); + if ( 0 != hEDIDRegKey && hEDIDRegKey != INVALID_HANDLE_VALUE ) { + bRes = GetMonitorSizeFromEDIDByRegKey(hEDIDRegKey, widthMm, heightMm, widthCm, heightCm); + RegCloseKey(hEDIDRegKey); + } + } + } else { + lastError = GetLastError(); + DBG_PRINT("*** fail.2 at %d, werr %d\n", i, lastError); + } + } else { + lastError = GetLastError(); + DBG_PRINT("*** fail.1 at %d, werr %d\n", i, lastError); + } + } + DBG_PRINT("*** Result: found %d, enum-iter %d, werr %d\n", bRes, i, (int)lastError); + WinSetup_SetupDiDestroyDeviceInfoList(devInfo); + free(pDevIfaceDetailData); + return bRes; +} + +int NewtEDID_GetIndexedDisplayDevice(int useDevIdx, int useMonIdx, DISPLAY_DEVICE* ddMonOut, int getDeviceInterfaceName, int verbose) +{ + DISPLAY_DEVICE ddAdp; + DWORD devIdx; // device index + DWORD monIdx; // monitor index + + memset(&ddAdp, 0, sizeof(ddAdp)); + ddAdp.cb = sizeof(ddAdp); + + const DWORD dwFlagsMonitor = 0 != getDeviceInterfaceName ? EDD_GET_DEVICE_INTERFACE_NAME : 0; + + for(devIdx = 0; + ( devIdx <= useDevIdx || 0 > useDevIdx ) && EnumDisplayDevices(0, devIdx, &ddAdp, 0); + devIdx++) + { + if( NULL != ddAdp.DeviceName && 0 != _tcslen(ddAdp.DeviceName) ) { + if( verbose ) { + _ftprintf(stderr, __T("*** [%02d:__]: deviceName <%s> flags 0x%X active %d\n"), + devIdx, ddAdp.DeviceName, ddAdp.StateFlags, ( 0 != ( ddAdp.StateFlags & DISPLAY_DEVICE_ACTIVE ) ) ); + _ftprintf(stderr, __T(" deviceString <%s> \n"), ddAdp.DeviceString); + _ftprintf(stderr, __T(" deviceID <%s> \n"), ddAdp.DeviceID); + } + if( devIdx == useDevIdx || 0 > useDevIdx ) { + DISPLAY_DEVICE ddMon; + memset(&ddMon, 0, sizeof(ddMon)); + ddMon.cb = sizeof(ddMon); + + for(monIdx = 0; + ( monIdx <= useMonIdx || 0 > useMonIdx ) && EnumDisplayDevices(ddAdp.DeviceName, monIdx, &ddMon, dwFlagsMonitor); + monIdx++) + { + if( NULL != ddMon.DeviceName && 0 < _tcslen(ddMon.DeviceName) ) { + if( verbose ) { + _ftprintf(stderr, __T("*** [%02d:%02d]: deviceName <%s> flags 0x%X active %d\n"), + devIdx, monIdx, ddMon.DeviceName, ddMon.StateFlags, ( 0 != ( ddMon.StateFlags & DISPLAY_DEVICE_ACTIVE ) ) ); + _ftprintf(stderr, __T(" deviceString <%s> \n"), ddMon.DeviceString); + _ftprintf(stderr, __T(" deviceID <%s> \n"), ddMon.DeviceID); + } + if( monIdx == useMonIdx ) { + *ddMonOut = ddMon; + return 1; + } + } + memset(&ddMon, 0, sizeof(ddMon)); + ddMon.cb = sizeof(ddMon); + } + } + } + memset(&ddAdp, 0, sizeof(ddAdp)); + ddAdp.cb = sizeof(ddAdp); + } + memset(ddMonOut, 0, sizeof(*ddMonOut)); + ddMonOut->cb = sizeof(*ddMonOut); + return 0; +} + +#ifdef WINDOWS_EDID_WITH_MAIN + +int _tmain(int argc, _TCHAR* argv []) +{ +#ifdef _UNICODE + _ftprintf(stderr, __T("_UNICODE enabled\n")); +#else + fprintf(stderr, "_UNICODE disabled\n"); +#endif + if( !NewtEDID_init() ) { + _ftprintf(stderr, __T("setupapi not available\n")); + return 1; + } + DISPLAY_DEVICE ddMon; + + if( 3 != argc ) { + NewtEDID_GetIndexedDisplayDevice(-1, -1, &ddMon, 0 /* getDeviceInterfaceName */, 1 /* verbose */); + _ftprintf(stderr, __T("Usage: %s dev-idx mon-idx\n"), argv[0]); + return 1; + } + int useDevIdx = _tstoi(argv[1]); + int useMonIdx = _tstoi(argv[2]); + int widthMm, heightMm; + int widthCm, heightCm; + + // + // Proper method + // + if( 0 == NewtEDID_GetIndexedDisplayDevice(useDevIdx, useMonIdx, &ddMon, 1 /* getDeviceInterfaceName */, 0 /* verbose */) ) { + _ftprintf(stderr, __T("No monitor found at dev %d : mon %d\n"), useDevIdx, useMonIdx); + return 1; + } + _ftprintf(stderr, __T("Found monitor at dev %d : mon %d:\n"), useDevIdx, useMonIdx); + _ftprintf(stderr, __T(" Device Name : %s\n"), ddMon.DeviceName); + _ftprintf(stderr, __T(" Device String: %s\n"), ddMon.DeviceString); + _ftprintf(stderr, __T(" Device ID : %s\n"), ddMon.DeviceID); + fflush(NULL); + + if( NewtEDID_GetMonitorSizeFromEDIDByDevice(&ddMon, &widthMm, &heightMm, &widthCm, &heightCm) ) { + _ftprintf(stderr, __T("Proper: Found EDID size [%d, %d] [mm], [%d, %d] [cm]\n"), widthMm, heightMm, widthCm, heightCm); + } + + // + // Monitor model name method + // + if( 0 == NewtEDID_GetIndexedDisplayDevice(useDevIdx, useMonIdx, &ddMon, 0 /* getDeviceInterfaceName */, 0 /* verbose */) ) { + _ftprintf(stderr, __T("No monitor found at dev %d : mon %d\n"), useDevIdx, useMonIdx); + return 1; + } + _ftprintf(stderr, __T("Found monitor at dev %d : mon %d:\n"), useDevIdx, useMonIdx); + _ftprintf(stderr, __T(" Device Name : %s\n"), ddMon.DeviceName); + _ftprintf(stderr, __T(" Device String: %s\n"), ddMon.DeviceString); + _ftprintf(stderr, __T(" Device ID : %s\n"), ddMon.DeviceID); + fflush(NULL); + + if( NewtEDID_GetMonitorSizeFromEDIDByModelName(&ddMon, &widthMm, &heightMm, &widthCm, &heightCm) ) { + _ftprintf(stderr, __T("ModelN: Found EDID size [%d, %d] [mm], [%d, %d] [cm]\n"), widthMm, heightMm, widthCm, heightCm); + } + return 0; +} + +#endif /* WINDOWS_EDID_WITH_MAIN */ diff --git a/src/newt/native/WindowsEDID.h b/src/newt/native/WindowsEDID.h new file mode 100644 index 000000000..ea80ca6df --- /dev/null +++ b/src/newt/native/WindowsEDID.h @@ -0,0 +1,40 @@ +/** + * Copyright 2015 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. + */ + +#ifndef _WINDOWS_EDID_H_ +#define _WINDOWS_EDID_H_ + +#include <Windows.h> +#include <Wingdi.h> + +int NewtEDID_init(); +int NewtEDID_GetMonitorSizeFromEDIDByModelName(const DISPLAY_DEVICE* ddMon, int* widthMm, int* heightMm, int *widthCm, int *heightCm); +int NewtEDID_GetMonitorSizeFromEDIDByDevice(const DISPLAY_DEVICE* ddMon, int* widthMm, int* heightMm, int *widthCm, int *heightCm); +int NewtEDID_GetIndexedDisplayDevice(int useDevIdx, int useMonIdx, DISPLAY_DEVICE* ddMonOut, int getDeviceInterfaceName, int verbose); + +#endif /* _WINDOWS_EDID_H_ */ diff --git a/src/newt/native/WindowsWindow.c b/src/newt/native/WindowsWindow.c index 70d0c6f83..7e15cd925 100644 --- a/src/newt/native/WindowsWindow.c +++ b/src/newt/native/WindowsWindow.c @@ -108,6 +108,10 @@ #define TOUCH_COORD_TO_PIXEL(l) (l/100) #endif +#ifndef EDD_GET_DEVICE_INTERFACE_NAME +#define EDD_GET_DEVICE_INTERFACE_NAME 0x00000001 +#endif + #ifndef MONITOR_DEFAULTTONULL #define MONITOR_DEFAULTTONULL 0 #endif @@ -139,16 +143,18 @@ #include "NewtCommon.h" +#include "WindowsEDID.h" + // #define VERBOSE_ON 1 // #define DEBUG_KEYS 1 #ifdef VERBOSE_ON - #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) + #define DBG_PRINT(x, ...) _ftprintf(stderr, __T(x), ##__VA_ARGS__); fflush(stderr) #else #define DBG_PRINT(...) #endif -#define STD_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#define STD_PRINT(x, ...) _ftprintf(stderr, __T(x), ##__VA_ARGS__); fflush(stderr) static jmethodID insetsChangedID = NULL; static jmethodID sizeChangedID = NULL; @@ -175,6 +181,8 @@ static IsTouchWindowPROCADDR WinTouch_IsTouchWindow = NULL; static RegisterTouchWindowPROCADDR WinTouch_RegisterTouchWindow = NULL; static UnregisterTouchWindowPROCADDR WinTouch_UnregisterTouchWindow = NULL; +static int NewtEDID_avail = 0; + static RECT* UpdateInsets(JNIEnv *env, jobject window, HWND hwnd); typedef struct { @@ -1629,11 +1637,15 @@ static int NewtScreen_RotationNewtCCW2NativeCCW(JNIEnv *env, jint newt) { return native; } -static LPCTSTR NewtScreen_getAdapterName(DISPLAY_DEVICE * device, int crt_idx) { +static LPCTSTR NewtScreen_getAdapterName(DISPLAY_DEVICE * device, int adapter_idx) { + if( 0 > adapter_idx ) { + DBG_PRINT("*** WindowsWindow: getAdapterName(adapter_idx %d < 0)\n", adapter_idx); + return NULL; + } memset(device, 0, sizeof(DISPLAY_DEVICE)); device->cb = sizeof(DISPLAY_DEVICE); - if( FALSE == EnumDisplayDevices(NULL, crt_idx, device, 0) ) { - DBG_PRINT("*** WindowsWindow: getAdapterName.EnumDisplayDevices(crt_idx %d) -> FALSE\n", crt_idx); + if( FALSE == EnumDisplayDevices(NULL, adapter_idx, device, 0) ) { + DBG_PRINT("*** WindowsWindow: getAdapterName.EnumDisplayDevices(adapter_idx %d) -> FALSE\n", adapter_idx); return NULL; } @@ -1645,19 +1657,22 @@ static LPCTSTR NewtScreen_getAdapterName(DISPLAY_DEVICE * device, int crt_idx) { } static LPCTSTR NewtScreen_getMonitorName(LPCTSTR adapterName, DISPLAY_DEVICE * device, int monitor_idx, BOOL onlyActive) { + if( 0 > monitor_idx ) { + DBG_PRINT("*** WindowsWindow: getMonitorName(monitor_idx %d < 0)\n", monitor_idx); + return NULL; + } memset(device, 0, sizeof(DISPLAY_DEVICE)); device->cb = sizeof(DISPLAY_DEVICE); - if( 0 == monitor_idx ) { - if( FALSE == EnumDisplayDevices(adapterName, monitor_idx, device, 0) ) { - DBG_PRINT("*** WindowsWindow: getDisplayName.EnumDisplayDevices(monitor_idx %d).adapter -> FALSE\n", monitor_idx); + if( FALSE == EnumDisplayDevices(adapterName, monitor_idx, device, EDD_GET_DEVICE_INTERFACE_NAME) ) { + DBG_PRINT("*** WindowsWindow: getMonitorName.EnumDisplayDevices(monitor_idx %d).adapter -> FALSE\n", monitor_idx); + return NULL; + } + if( onlyActive ) { + if( 0 == ( device->StateFlags & DISPLAY_DEVICE_ACTIVE ) ) { + DBG_PRINT("*** WindowsWindow: !DISPLAY_DEVICE_ACTIVE(monitor_idx %d).display\n", monitor_idx); return NULL; } } - - if( onlyActive && 0 == ( device->StateFlags & DISPLAY_DEVICE_ACTIVE ) ) { - DBG_PRINT("*** WindowsWindow: !DISPLAY_DEVICE_ACTIVE(monitor_idx %d).display\n", monitor_idx); - return NULL; - } if( NULL == device->DeviceName || 0 == _tcslen(device->DeviceName) ) { return NULL; } @@ -1665,6 +1680,23 @@ static LPCTSTR NewtScreen_getMonitorName(LPCTSTR adapterName, DISPLAY_DEVICE * d return device->DeviceName; } +static int NewtScreen_getFirstActiveNonCloneMonitor(LPCTSTR adapterName, DISPLAY_DEVICE * device) { + memset(device, 0, sizeof(DISPLAY_DEVICE)); + device->cb = sizeof(DISPLAY_DEVICE); + int monitor_idx; + for(monitor_idx=0; EnumDisplayDevices(adapterName, monitor_idx, device, EDD_GET_DEVICE_INTERFACE_NAME); monitor_idx++) { + if( NULL != device->DeviceName && + 0 < _tcslen(device->DeviceName) && + 0 != ( device->StateFlags & DISPLAY_DEVICE_ACTIVE ) && + 0 == ( device->StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER ) ) { + return monitor_idx; + } + memset(device, 0, sizeof(DISPLAY_DEVICE)); + device->cb = sizeof(DISPLAY_DEVICE); + } + return -1; +} + JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_dumpMonitorInfo0 (JNIEnv *env, jclass clazz) { @@ -1672,10 +1704,18 @@ JNIEXPORT void JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_dumpMonitorI int i = 0, j; LPCTSTR aName, dName; while(NULL != (aName = NewtScreen_getAdapterName(&aDevice, i))) { - fprintf(stderr, "*** [%d]: <%s> flags 0x%X active %d\n", i, aName, aDevice.StateFlags, ( 0 != ( aDevice.StateFlags & DISPLAY_DEVICE_ACTIVE ) ) ); + STD_PRINT("*** [%02d:__]: deviceName <%s> flags 0x%X active %d\n", + i, aDevice.DeviceName, aDevice.StateFlags, ( 0 != ( aDevice.StateFlags & DISPLAY_DEVICE_ACTIVE ) ) ); + STD_PRINT(" deviceString <%s> \n", aDevice.DeviceString); + STD_PRINT(" deviceID <%s> \n", aDevice.DeviceID); j=0; while(NULL != (dName = NewtScreen_getMonitorName(aName, &dDevice, j, FALSE))) { - fprintf(stderr, "*** [%d][%d]: <%s> flags 0x%X active %d\n", i, j, dName, dDevice.StateFlags, ( 0 != ( dDevice.StateFlags & DISPLAY_DEVICE_ACTIVE ) ) ); + STD_PRINT("*** [%02d:%02d]: deviceName <%s> flags 0x%X active %d, mirror %d\n", + i, j, dDevice.DeviceName, dDevice.StateFlags, + 0 != ( dDevice.StateFlags & DISPLAY_DEVICE_ACTIVE ), + 0 != ( dDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER ) ); + STD_PRINT(" deviceString <%s> \n", dDevice.DeviceString); + STD_PRINT(" deviceID <%s> \n", dDevice.DeviceID); j++; } i++; @@ -1692,11 +1732,11 @@ static HDC NewtScreen_createDisplayDC(LPCTSTR displayDeviceName) { * Signature: (I)Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getAdapterName0 - (JNIEnv *env, jobject obj, jint crt_idx) + (JNIEnv *env, jobject obj, jint adapter_idx) { DISPLAY_DEVICE device; - LPCTSTR adapterName = NewtScreen_getAdapterName(&device, crt_idx); - DBG_PRINT("*** WindowsWindow: getAdapterName(crt_idx %d) -> %s, active %d\n", crt_idx, + LPCTSTR adapterName = NewtScreen_getAdapterName(&device, adapter_idx); + DBG_PRINT("*** WindowsWindow: getAdapterName(adapter_idx %d) -> %s, active %d\n", adapter_idx, (NULL==adapterName?"nil":adapterName), 0 == ( device.StateFlags & DISPLAY_DEVICE_ACTIVE )); if(NULL == adapterName) { return NULL; @@ -1710,22 +1750,22 @@ JNIEXPORT jstring JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getAdapte /* * Class: jogamp_newt_driver_windows_ScreenDriver - * Method: getActiveMonitorName0 - * Signature: (Ljava/lang/String;I)Ljava/lang/String; + * Method: getMonitorName0 + * Signature: (Ljava/lang/String;IZ)Ljava/lang/String; */ -JNIEXPORT jstring JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getActiveMonitorName0 - (JNIEnv *env, jobject obj, jstring jAdapterName, jint monitor_idx) +JNIEXPORT jstring JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMonitorName0 + (JNIEnv *env, jobject obj, jstring jAdapterName, jint monitor_idx, jboolean onlyActive) { DISPLAY_DEVICE device; LPCTSTR monitorName; #ifdef UNICODE LPCTSTR adapterName = NewtCommon_GetNullTerminatedStringChars(env, jAdapterName); - monitorName = NewtScreen_getMonitorName(adapterName, &device, monitor_idx, TRUE); + monitorName = NewtScreen_getMonitorName(adapterName, &device, monitor_idx, onlyActive); DBG_PRINT("*** WindowsWindow: getMonitorName(%s, monitor_idx %d) -> %s\n", adapterName, monitor_idx, (NULL==monitorName?"nil":monitorName)); free((void*) adapterName); #else LPCTSTR adapterName = (*env)->GetStringUTFChars(env, jAdapterName, NULL); - monitorName = NewtScreen_getMonitorName(adapterName, &device, monitor_idx, TRUE); + monitorName = NewtScreen_getMonitorName(adapterName, &device, monitor_idx, onlyActive); DBG_PRINT("*** WindowsWindow: getMonitorName(%s, monitor_idx %d) -> %s\n", adapterName, monitor_idx, (NULL==monitorName?"nil":monitorName)); (*env)->ReleaseStringUTFChars(env, jAdapterName, adapterName); #endif @@ -1815,12 +1855,11 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMoni /* * Class: jogamp_newt_driver_windows_ScreenDriver * Method: getMonitorDevice0 - * Signature: (Ljava/lang/String;I)[I + * Signature: (Ljava/lang/String;II)[I */ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMonitorDevice0 - (JNIEnv *env, jobject obj, jstring jAdapterName, jint monitor_idx) + (JNIEnv *env, jobject obj, jstring jAdapterName, jint adapter_idx, jint monitor_idx, jint monitor_id) { - DISPLAY_DEVICE device; LPCTSTR adapterName; { #ifdef UNICODE @@ -1830,10 +1869,37 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMoni #endif } - HDC hdc = NewtScreen_createDisplayDC(adapterName); - int widthmm = GetDeviceCaps(hdc, HORZSIZE); - int heightmm = GetDeviceCaps(hdc, VERTSIZE); - DeleteDC(hdc); + DBG_PRINT("*** WindowsWindow: adapter[name %s, idx %d], monitor[idx %d, id %d], EDID-avail %d\n", + adapterName, adapter_idx, monitor_idx, monitor_id, NewtEDID_avail); + int gotsize = 0; + int widthmm, heightmm; + DISPLAY_DEVICE monitorDevice; + LPCTSTR monitorName = NewtScreen_getMonitorName(adapterName, &monitorDevice, monitor_idx, TRUE); + if( NewtEDID_avail ) { + int widthcm, heightcm; + if( NULL != monitorName && + NewtEDID_GetMonitorSizeFromEDIDByDevice(&monitorDevice, &widthmm, &heightmm, &widthcm, &heightcm) ) { + DBG_PRINT("*** WindowsWindow: EDID %d x %d [mm], %d x %d [cm]\n", widthmm, heightmm, widthcm, heightcm); + if( 0 <= widthmm && 0 <= heightmm ) { + gotsize = 1; // got mm values + DBG_PRINT("*** WindowsWindow: %d x %d [mm] (EDID mm)\n", widthmm, heightmm); + } else if( 0 <= widthcm && 0 <= heightcm ) { + // fallback using cm values + widthmm = widthcm * 10; + heightmm = heightcm * 10; + gotsize = 1; + DBG_PRINT("*** WindowsWindow: %d x %d [mm] (EDID cm)\n", widthmm, heightmm); + } + } + } + if( !gotsize ) { + // fallback using buggy API resulting in erroneous values + HDC hdc = NewtScreen_createDisplayDC(adapterName); + widthmm = GetDeviceCaps(hdc, HORZSIZE); + heightmm = GetDeviceCaps(hdc, VERTSIZE); + DeleteDC(hdc); + DBG_PRINT("*** WindowsWindow: %d x %d [mm] (Buggy API)\n", widthmm, heightmm); + } int devModeID = ENUM_CURRENT_SETTINGS; DEVMODE dm; @@ -1856,7 +1922,8 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMoni int propIndex = 0; prop[propIndex++] = propCount; - prop[propIndex++] = monitor_idx; + prop[propIndex++] = monitor_id; + prop[propIndex++] = NULL != monitorName && 0 != ( monitorDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER ); prop[propIndex++] = widthmm; prop[propIndex++] = heightmm; prop[propIndex++] = dm.dmPosition.x; // rotated viewport pixel units @@ -1883,18 +1950,22 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMoni * Signature: (IIIIIIIII)Z */ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_setMonitorMode0 - (JNIEnv *env, jobject object, jint monitor_idx, jint x, jint y, jint width, jint height, jint bits, jint rate, jint flags, jint rot) + (JNIEnv *env, jobject object, jint adapter_idx, jint x, jint y, jint width, jint height, jint bits, jint rate, jint flags, jint rot) { DISPLAY_DEVICE adapterDevice, monitorDevice; - LPCTSTR adapterName = NewtScreen_getAdapterName(&adapterDevice, monitor_idx); + LPCTSTR adapterName = NewtScreen_getAdapterName(&adapterDevice, adapter_idx); if(NULL == adapterName) { - DBG_PRINT("*** WindowsWindow: setMonitorMode.getAdapterName(monitor_idx %d) -> NULL\n", monitor_idx); + DBG_PRINT("*** WindowsWindow: setMonitorMode.getAdapterName(adapter_idx %d) -> NULL\n", adapter_idx); return JNI_FALSE; } - LPCTSTR monitorName = NewtScreen_getMonitorName(adapterName, &monitorDevice, 0, TRUE); - if(NULL == monitorName) { - DBG_PRINT("*** WindowsWindow: setMonitorMode.getMonitorName(monitor_idx 0) -> NULL\n"); - return JNI_FALSE; + + { + // Just test whether there is an active non-mirror monitor attached + int monitor_idx = NewtScreen_getFirstActiveNonCloneMonitor(adapterName, &monitorDevice); + if( 0 > monitor_idx ) { + DBG_PRINT("*** WindowsWindow: setMonitorMode.getFirstActiveNonCloneMonitor(%s) -> n/a\n", adapterName); + return JNI_FALSE; + } } DEVMODE dm; @@ -1981,6 +2052,7 @@ JNIEXPORT jboolean JNICALL Java_jogamp_newt_driver_windows_WindowDriver_initIDs0 WinTouch_func_avail = 0; } } + NewtEDID_avail = NewtEDID_init(); } return JNI_TRUE; } diff --git a/src/newt/native/X11Display.c b/src/newt/native/X11Display.c index b62a9b234..60daf1af2 100644 --- a/src/newt/native/X11Display.c +++ b/src/newt/native/X11Display.c @@ -30,7 +30,7 @@ #include <X11/Xcursor/Xcursor.h> -// #include <X11/XKBlib.h> // XKB disabled for now +#include <X11/XKBlib.h> jclass X11NewtWindowClazz = NULL; jmethodID insetsChangedID = NULL; diff --git a/src/newt/native/X11RandR13.c b/src/newt/native/X11RandR13.c index 4e92a32b4..1d721efcb 100644 --- a/src/newt/native/X11RandR13.c +++ b/src/newt/native/X11RandR13.c @@ -26,7 +26,7 @@ * or implied, of JogAmp Community. */ -#include "X11Common.h" +#include "X11Screen.h" /* * Class: jogamp_newt_driver_x11_RandR13 @@ -67,9 +67,16 @@ static void dumpOutputs(const char *prefix, Display *dpy, XRRScreenResources *re for(i=0; i<noutput; i++) { RROutput output = outputs[i]; XRROutputInfo * xrrOutputInfo = XRRGetOutputInfo (dpy, resources, output); - fprintf(stderr, " Output[%d]: id %#lx, crtx 0x%X, name %s (%d), %lux%lu, ncrtc %d, .., nmode %d (preferred %d)\n", - i, output, xrrOutputInfo->crtc, SAFE_STRING(xrrOutputInfo->name), xrrOutputInfo->nameLen, xrrOutputInfo->mm_width, xrrOutputInfo->mm_height, - xrrOutputInfo->ncrtc, xrrOutputInfo->nmode, xrrOutputInfo->npreferred); + fprintf(stderr, " Output[%d]: id %#lx, crtx 0x%lX, name %s (%d), %lux%lu, ncrtc %d, nclone %d, nmode %d (preferred %d)\n", + i, output, xrrOutputInfo->crtc, SAFE_STRING(xrrOutputInfo->name), xrrOutputInfo->nameLen, + xrrOutputInfo->mm_width, xrrOutputInfo->mm_height, + xrrOutputInfo->ncrtc, xrrOutputInfo->nclone, xrrOutputInfo->nmode, xrrOutputInfo->npreferred); + for(j=0; j<xrrOutputInfo->ncrtc; j++) { + fprintf(stderr, " Output[%d].Crtc[%d].id %#lx\n", i, j, xrrOutputInfo->crtcs[j]); + } + for(j=0; j<xrrOutputInfo->nclone; j++) { + fprintf(stderr, " Output[%d].Clones[%d].id %#lx\n", i, j, xrrOutputInfo->clones[j]); + } for(j=0; j<xrrOutputInfo->nmode; j++) { fprintf(stderr, " Output[%d].Mode[%d].id %#lx\n", i, j, xrrOutputInfo->modes[j]); } @@ -424,6 +431,7 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_x11_RandR13_getMonitorDevice prop[propIndex++] = propCount; prop[propIndex++] = crt_idx; + prop[propIndex++] = 0; // is_clone, does not work: 0 < xrrOutputInfo->nclone ? 1 : 0; prop[propIndex++] = xrrOutputInfo->mm_width; prop[propIndex++] = xrrOutputInfo->mm_height; prop[propIndex++] = xrrCrtcInfo->x; // rotated viewport pixel units diff --git a/src/newt/native/X11Window.c b/src/newt/native/X11Window.c index 2cc66c78d..43506c6a6 100644 --- a/src/newt/native/X11Window.c +++ b/src/newt/native/X11Window.c @@ -489,7 +489,7 @@ static Bool WaitForUnmapNotify( Display *dpy, XEvent *event, XPointer arg ) { } static void NewtWindows_setPosSize(Display *dpy, Window w, jint x, jint y, jint width, jint height) { - if(width>0 && height>0 || x>=0 && y>=0) { // resize/position if requested + if( ( width>0 && height>0 ) || ( x>=0 && y>=0 ) ) { // resize/position if requested XWindowChanges xwc; int flags = CWX | CWY; diff --git a/src/newt/native/bcm_vc_iv.c b/src/newt/native/bcm_vc_iv.c index ee59f0aa6..6b1ee3aaf 100644 --- a/src/newt/native/bcm_vc_iv.c +++ b/src/newt/native/bcm_vc_iv.c @@ -357,7 +357,7 @@ JNIEXPORT jlong JNICALL Java_jogamp_newt_driver_bcm_vc_iv_WindowDriver_CreateWin VC_RECT_T src_rect; if( 0 == display ) { - return; + return 0; } dst_rect.x = x; dst_rect.y = y; |