diff options
author | Sven Gothel <[email protected]> | 2015-02-16 06:23:43 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2015-02-16 06:23:43 +0100 |
commit | 70faf070f50ea66fd4cc8f5f586614810f378787 (patch) | |
tree | c4e1175587337386620c823927c017c6fd68c727 | |
parent | 1eea4278f1be5900f0d990d0a7d352923def217c (diff) |
Bug 1129 - NEWT MonitorDevice's physical size on Windows must be read via EDID
On Windows, one must read the monitor's EDID data as stored in the registry,
no 'simple' API works otherwise.
The proper way requires utilizing the Windows Setup-API.
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.
-rw-r--r-- | make/build-newt.xml | 1 | ||||
-rwxr-xr-x | make/scripts/tests-win.bat | 4 | ||||
-rw-r--r-- | make/scripts/tests.sh | 6 | ||||
-rw-r--r-- | src/jogl/classes/com/jogamp/opengl/JoglVersion.java | 1 | ||||
-rw-r--r-- | src/newt/classes/com/jogamp/newt/opengl/GLWindow.java | 5 | ||||
-rw-r--r-- | src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java | 82 | ||||
-rw-r--r-- | src/newt/native/WindowsEDID.c | 419 | ||||
-rw-r--r-- | src/newt/native/WindowsEDID.h | 40 | ||||
-rw-r--r-- | src/newt/native/WindowsWindow.c | 158 | ||||
-rw-r--r-- | src/test/com/jogamp/opengl/test/junit/newt/mm/TestScreenMode00aNEWT.java | 19 |
10 files changed, 645 insertions, 90 deletions
diff --git a/make/build-newt.xml b/make/build-newt.xml index cf8330eb1..37e6b8bff 100644 --- a/make/build-newt.xml +++ b/make/build-newt.xml @@ -616,6 +616,7 @@ <include name="${rootrel.src.c}/NewtCommon.c" /> <!-- include name="${rootrel.src.c}/timespec.c" /--> <!-- currently used for X11 and OSX with special PERF DEBUG MODE--> <include name="${rootrel.src.c}/WindowsWindow.c" if="isWindows"/> + <include name="${rootrel.src.c}/WindowsEDID.c" if="isWindows"/> <include name="${rootrel.src.c}/MacWindow.m" if="isOSX"/> <include name="${rootrel.src.c}/NewtMacWindow.m" if="isOSX"/> <include name="${rootrel.src.c}/AndroidWindow.c" if="isAndroid"/> diff --git a/make/scripts/tests-win.bat b/make/scripts/tests-win.bat index 8a94a0fa2..bd4a73b14 100755 --- a/make/scripts/tests-win.bat +++ b/make/scripts/tests-win.bat @@ -12,7 +12,7 @@ REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGe REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT -vsync -time 40000 -width 100 -height 100 -screen 0 %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.gl2.awt.TestGearsAWT %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2AWT %* -scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelAWT %* +REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelAWT %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.awt.TestGearsES2GLJPanelsAWT %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.awt.DemoGLJPanelPerf02AWT %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NewtCanvasAWT %* @@ -167,7 +167,7 @@ REM scripts\java-win.bat com.jogamp.opengl.test.junit.newt.TestGLWindows02NEWTAn REM scripts\java-win.bat com.jogamp.opengl.test.junit.newt.TestGLWindowInvisiblePointer01NEWT %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.nativewindow.TestRecursiveToolkitLockCORE -REM scripts\java-win.bat com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00aNEWT %* +scripts\java-win.bat com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00aNEWT %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00bNEWT %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00cNEWT %* REM scripts\java-win.bat com.jogamp.opengl.test.junit.newt.mm.TestScreenMode01aNEWT %* diff --git a/make/scripts/tests.sh b/make/scripts/tests.sh index 83d51f971..d8ad7e9da 100644 --- a/make/scripts/tests.sh +++ b/make/scripts/tests.sh @@ -300,7 +300,7 @@ function jrun() { #X_ARGS="-Xrs" #X_ARGS="-Dsun.awt.disableMixing=true" #D_ARGS="-Djogamp.debug.NativeLibrary=true -Djogamp.debug.JNILibLoader=true -Djogl.debug.GLMediaPlayer" - D_ARGS="-Djogl.debug.GLMediaPlayer" + #D_ARGS="-Djogl.debug.GLMediaPlayer" #D_ARGS="-Djogamp.debug.IOUtil -Djogl.debug.GLSLCode -Djogl.debug.GLMediaPlayer" #D_ARGS="-Djogl.debug.AudioSink -Djoal.openal.lib=system" #D_ARGS="-Djogl.debug.AudioSink -Djogl.debug.AudioSink.trace" @@ -613,7 +613,7 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle01NEWT #testnoawt com.jogamp.opengl.test.junit.newt.TestDisplayLifecycle02NEWT #testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.newt.TestGearsES2NEWT $* -#testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00aNEWT $* +testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00aNEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00bNEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode00cNEWT $* #testnoawt com.jogamp.opengl.test.junit.newt.mm.TestScreenMode01aNEWT $* @@ -842,7 +842,7 @@ function testawtswt() { #testnoawt com.jogamp.opengl.test.junit.graph.demos.ui.UINewtDemo01 $* #testnoawt com.jogamp.opengl.test.junit.graph.demos.GPUTextNewtDemo $* #testnoawt com.jogamp.opengl.test.junit.graph.demos.GPURegionNewtDemo $* -testnoawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtDemo $* +#testnoawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtDemo $* #testawt com.jogamp.opengl.test.junit.graph.demos.GPUUISceneNewtCanvasAWTDemo $* #testnoawt com.jogamp.opengl.test.junit.jogl.demos.es2.av.MovieCube $* diff --git a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java index 5070f3e4e..af16348a8 100644 --- a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java +++ b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java @@ -29,7 +29,6 @@ package com.jogamp.opengl; import com.jogamp.common.GlueGenVersion; -import com.jogamp.opengl.*; import com.jogamp.common.os.Platform; import com.jogamp.common.util.VersionUtil; diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index d638b3ae5..e15f52730 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(" pp/mm ["+pixelPerMM[0]+", "+pixelPerMM[1]+"]"); + System.err.println(" pp/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/driver/windows/ScreenDriver.java b/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java index b476ee38a..947ea27f4 100644 --- a/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java +++ b/src/newt/classes/jogamp/newt/driver/windows/ScreenDriver.java @@ -65,19 +65,21 @@ 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 int getFirstActiveMonitor(final String adapterName) { + return getFirstActiveMonitor0(adapterName); } - 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; } @@ -86,34 +88,35 @@ public class ScreenDriver extends ScreenImpl { @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>(); + int adapter_idx; + String adapterName; + for(adapter_idx=0; null != ( adapterName = getAdapterName(adapter_idx) ); adapter_idx++ ) { + final int activeMonitorIdx = getFirstActiveMonitor(adapterName); + if( 0 <= activeMonitorIdx ) { + int mode_idx = 0; + MonitorMode mode; + do { + mode = getMonitorModeImpl(cache, adapterName, mode_idx); + if( null != mode ) { + supportedModes.getOrAdd(mode); + // next mode on same monitor + mode_idx++; + } + } while( null != mode); + if( 0 < mode_idx ) { + // has at least one mode -> add device + final MonitorMode currentMode = getMonitorModeImpl(cache, adapterName, -1); + if ( null != currentMode ) { // enabled + final int[] monitorProps = getMonitorDevice0(adapterName, adapter_idx); + // 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); } } @@ -121,8 +124,8 @@ public class ScreenDriver extends ScreenImpl { protected boolean updateNativeMonitorDeviceViewportImpl(final MonitorDevice monitor, final float[] pixelScale, final Rectangle viewportPU, final Rectangle viewportWU) { final String adapterName = getAdapterName(monitor.getId()); if( null != adapterName ) { - final String activeMonitorName = getActiveMonitorName(adapterName, 0); - if( null != activeMonitorName ) { + final int activeMonitorIdx = getFirstActiveMonitor(adapterName); + if( 0 <= activeMonitorIdx ) { final int[] monitorProps = getMonitorDevice0(adapterName, monitor.getId()); int offset = MonitorModeProps.IDX_MONITOR_DEVICE_VIEWPORT; viewportPU.set(monitorProps[offset++], monitorProps[offset++], monitorProps[offset++], monitorProps[offset++]); @@ -168,9 +171,10 @@ 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 getFirstActiveMonitor0(String adapterName); + private native int[] getMonitorMode0(String adapterName, int mode_idx); + private native int[] getMonitorDevice0(String adapterName, int adapter_idx); + 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/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..d3ad69f92 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,11 @@ 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) { 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; } @@ -1647,16 +1655,19 @@ static LPCTSTR NewtScreen_getAdapterName(DISPLAY_DEVICE * device, int crt_idx) { static LPCTSTR NewtScreen_getMonitorName(LPCTSTR adapterName, DISPLAY_DEVICE * device, int monitor_idx, BOOL onlyActive) { 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: getDisplayName.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( 0 != ( device->StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER ) ) { + DBG_PRINT("*** WindowsWindow: DISPLAY_DEVICE_MIRRORING_DRIVER(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 +1676,23 @@ static LPCTSTR NewtScreen_getMonitorName(LPCTSTR adapterName, DISPLAY_DEVICE * d return device->DeviceName; } +static int NewtScreen_getFirstActiveMonitor(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 +1700,16 @@ 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\n", + i, j, dDevice.DeviceName, dDevice.StateFlags, ( 0 != ( dDevice.StateFlags & DISPLAY_DEVICE_ACTIVE ) ) ); + STD_PRINT(" deviceString <%s> \n", dDevice.DeviceString); + STD_PRINT(" deviceID <%s> \n", dDevice.DeviceID); j++; } i++; @@ -1692,11 +1726,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 +1744,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 @@ -1741,6 +1775,30 @@ JNIEXPORT jstring JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getActive /* * Class: jogamp_newt_driver_windows_ScreenDriver + * Method: getFirstActiveMonitor0 + * Signature: (Ljava/lang/String;)I + */ +JNIEXPORT jint JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getFirstActiveMonitor0 + (JNIEnv *env, jobject obj, jstring jAdapterName) +{ + DISPLAY_DEVICE device; + int monitorIdx; +#ifdef UNICODE + LPCTSTR adapterName = NewtCommon_GetNullTerminatedStringChars(env, jAdapterName); + monitorIdx = NewtScreen_getFirstActiveMonitor(adapterName, &device); + DBG_PRINT("*** WindowsWindow: getFirstActiveMonitor(%s) -> monitor_idx %d, %s\n", adapterName, monitorIdx, (NULL==device.DeviceName?"nil":device.DeviceName)); + free((void*) adapterName); +#else + LPCTSTR adapterName = (*env)->GetStringUTFChars(env, jAdapterName, NULL); + monitorIdx = NewtScreen_getFirstActiveMonitor(adapterName, &device); + DBG_PRINT("*** WindowsWindow: getFirstActiveMonitor(%s) -> monitor_idx %d, %s\n", adapterName, monitorIdx, (NULL==device.DeviceName?"nil":device.DeviceName)); + (*env)->ReleaseStringUTFChars(env, jAdapterName, adapterName); +#endif + return monitorIdx; +} + +/* + * Class: jogamp_newt_driver_windows_ScreenDriver * Method: getMonitorMode0 * Signature: (Ljava/lang/String;I)[I */ @@ -1818,9 +1876,8 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMoni * Signature: (Ljava/lang/String;I)[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) { - DISPLAY_DEVICE device; LPCTSTR adapterName; { #ifdef UNICODE @@ -1830,10 +1887,36 @@ 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], EDID-avail %d\n", adapterName, adapter_idx, NewtEDID_avail); + int gotsize = 0; + int widthmm, heightmm; + if( NewtEDID_avail ) { + int widthcm, heightcm; + DISPLAY_DEVICE monitorDevice; + int monitor_idx = NewtScreen_getFirstActiveMonitor(adapterName, &monitorDevice); + if( 0 <= monitor_idx && + 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 +1939,7 @@ JNIEXPORT jintArray JNICALL Java_jogamp_newt_driver_windows_ScreenDriver_getMoni int propIndex = 0; prop[propIndex++] = propCount; - prop[propIndex++] = monitor_idx; + prop[propIndex++] = adapter_idx; prop[propIndex++] = widthmm; prop[propIndex++] = heightmm; prop[propIndex++] = dm.dmPosition.x; // rotated viewport pixel units @@ -1883,17 +1966,17 @@ 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"); + int monitor_idx = NewtScreen_getFirstActiveMonitor(adapterName, &monitorDevice); + if( 0 > monitor_idx ) { + DBG_PRINT("*** WindowsWindow: setMonitorMode.getFirstActiveMonitor(%s) -> n/a\n", adapterName); return JNI_FALSE; } @@ -1981,6 +2064,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/test/com/jogamp/opengl/test/junit/newt/mm/TestScreenMode00aNEWT.java b/src/test/com/jogamp/opengl/test/junit/newt/mm/TestScreenMode00aNEWT.java index be15e3b7e..e103fc490 100644 --- a/src/test/com/jogamp/opengl/test/junit/newt/mm/TestScreenMode00aNEWT.java +++ b/src/test/com/jogamp/opengl/test/junit/newt/mm/TestScreenMode00aNEWT.java @@ -173,6 +173,9 @@ public class TestScreenMode00aNEWT extends UITestCase { for(final Iterator<MonitorDevice> iMonitor=monitors.iterator(); iMonitor.hasNext(); j++) { final MonitorDevice monitor = iMonitor.next(); System.err.println(j+": "+monitor); + final float[] pixelPerMM = monitor.getPixelsPerMM(new float[2]); + System.err.println(j+" pp/mm ["+pixelPerMM[0]+", "+pixelPerMM[1]+"]"); + System.err.println(j+" pp/in ["+pixelPerMM[0]*25.4f+", "+pixelPerMM[1]*25.4f+"]"); final List<MonitorMode> modes = monitor.getSupportedModes(); Assert.assertTrue(modes.size()>0); int i=0; @@ -195,21 +198,21 @@ public class TestScreenMode00aNEWT extends UITestCase { Assert.assertNotNull(sm_c); Assert.assertEquals(sm_o, sm_c); } - + final RectangleImmutable zero = new Rectangle(); - + final Rectangle monitorViewPU = new Rectangle(); final Rectangle monitorViewWU = new Rectangle(); MonitorDevice.unionOfViewports(monitorViewPU, monitorViewWU, monitors); - System.err.println("Test.0: Monitor union viewport: "+monitorViewPU+" [pu] / "+monitorViewWU+" [wu]"); + System.err.println("Test.0: Monitor union viewport: "+monitorViewPU+" [pu] / "+monitorViewWU+" [wu]"); Assert.assertNotEquals(zero, monitorViewPU); - Assert.assertNotEquals(zero, monitorViewWU); - + Assert.assertNotEquals(zero, monitorViewWU); + final RectangleImmutable screenViewPU = screen.getViewport(); - final RectangleImmutable screenViewWU = screen.getViewportInWindowUnits(); - System.err.println("Test.1: Screen viewport: "+screenViewPU+" [pu] / "+screenViewWU+" [wu]"); + final RectangleImmutable screenViewWU = screen.getViewportInWindowUnits(); + System.err.println("Test.1: Screen viewport: "+screenViewPU+" [pu] / "+screenViewWU+" [wu]"); Assert.assertNotEquals(zero, screenViewPU); - Assert.assertNotEquals(zero, screenViewWU); + Assert.assertNotEquals(zero, screenViewWU); screen.removeReference(); |