Bug 1129

Summary: NEWT MonitorDevice on Windows reports wrong physical size [mm]
Product: [JogAmp] Newt Reporter: Sven Gothel <sgothel>
Component: windowsAssignee: Sven Gothel <sgothel>
Status: RESOLVED FIXED    
Severity: major    
Priority: ---    
Version: 2.3.0   
Hardware: All   
OS: all   
Type: --- SCM Refs:
70faf070f50ea66fd4cc8f5f586614810f378787 559ecad2a2387ba0aa34ce9e35ca8a2c5a31e655 aba21ccaebb2acf20690a77f5c0914f12d736755
Workaround: ---

Description Sven Gothel 2015-02-09 12:15:12 CET
On MS Windows, NEWT's MonitorDevice reports the wrong physical size
in millimeter.

Current code uses EnumDisplayDevices for 'displayDeviceName', i.e. monitor name
and the adapter names, then:

static HDC NewtScreen_createDisplayDC(LPCTSTR displayDeviceName) {
    return CreateDC("DISPLAY", displayDeviceName, NULL, NULL);
}

...
    HDC hdc = NewtScreen_createDisplayDC(adapterName);
    int widthmm = GetDeviceCaps(hdc, HORZSIZE);
    int heightmm = GetDeviceCaps(hdc, VERTSIZE);
...

^^ will not return reliable and accurate monitor dimension.

+++

One workaround seems to be using registry EDID information:

<http://ofekshilon.com/2011/11/13/reading-monitor-physical-dimensions-or-getting-the-edid-the-right-way/>

+++

Another API seems to be

<https://msdn.microsoft.com/en-us/library/ff553933(v=vs.85).aspx>:

"To get the physical desktop width and physical monitor width, call QueryDisplayConfig. For each DISPLAYCONFIG_MODE_INFO in the returned pModeInfoArray, check the pModeInfoArray[i].sourceMode.width (and height and position) to reconstruct the bounding rect of all the monitors."

DISPLAYCONFIG_MODE_INFO:
  <https://msdn.microsoft.com/en-us/library/ff553933(v=vs.85).aspx>

+++
Comment 1 Sven Gothel 2015-02-16 06:24:49 CET
70faf070f50ea66fd4cc8f5f586614810f378787

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.
Comment 2 Sven Gothel 2015-02-17 01:16:06 CET
commit 559ecad2a2387ba0aa34ce9e35ca8a2c5a31e655:

NEWT MonitorDevice:
    
    - Identify cloned devices (fully covered)
      - MonitorDevice gets 'isCloned()' to identify whether
        it is a cloned device, i.e. fully covered by another monitor.
        This detection may happen natively but will always performed
        platform agnostic.
    
      - getMainMonitor(..) now exclude 'cloned' devices
    
    - Windows: Iterate-over and identify all adapter:monitor
      - Since we also list cloned monitor,
        we need to iterate over all adapter and all it's monitor-devices.
      - The native monitor-id is now defined as: ( adapter-idx << 8 ) | monitor-idx.
    
    - Bug 1129 <- listed under this bug entry for convenience
Comment 3 Sven Gothel 2015-03-09 10:48:35 CET
aba21ccaebb2acf20690a77f5c0914f12d736755

Fix regression of commit 559ecad2a2387ba0aa34ce9e35ca8a2c5a31e655
IDX_MONITOR_DEVICE_VIEWPORT needed to be updated!