WinWorkstation.st
changeset 8877 d12c092cd6ae
parent 8872 7d7024512b49
child 8881 385a6800e902
--- a/WinWorkstation.st	Fri Nov 22 02:25:28 2019 +0100
+++ b/WinWorkstation.st	Fri Nov 22 10:43:26 2019 +0100
@@ -22,8 +22,8 @@
 	classVariableNames:'BeepDuration NativeDialogs NativeFileDialogs NativeWidgets
 		NativeWidgetClassTable StandardColorValues IgnoreSysColorChanges
 		IgnoreFontChanges SystemColorValues CanEndSession
-		VerboseNativeDialogs CurrentDisplayResolutionFromTool
-		VirtualDisplayResolutionFromTool'
+		VerboseNativeDialogs MonitorNameToCurrentResolution
+		MonitorNameToVirtualResolution MonitorNameDictionariesSema'
 	poolDictionaries:''
 	category:'Interface-Graphics'
 !
@@ -5423,25 +5423,31 @@
     IgnoreSysColorChanges := false.
     SystemColorValues := IdentityDictionary new.
 
+    "/ cache information we get from support/win32/displayResolutionTools
+    MonitorNameToCurrentResolution := Dictionary new.
+    MonitorNameToVirtualResolution := Dictionary new.
+    MonitorNameDictionariesSema := Semaphore forMutualExclusion.
+
     "/ translation table from ST/X windowType symbol (system-independent)
     "/ to Windows windowClass (windows-specific).
 
     NativeWidgetClassTable := IdentityDictionary
-	withKeysAndValues:#(
-		ScrollBar                 SCROLLBAR
-		HorizontalScrollBar       SCROLLBAR
-		VerticalScrollBar         SCROLLBAR
-		CheckBox                  BUTTON
-		RadioButton               BUTTON
-		Button                    BUTTON
-		DefaultButton             BUTTON
-		OwnerDrawButton           BUTTON
-		ComboBox                  COMBOBOX
-		EditField                 EDIT
-		ListBox                   LISTBOX
-	).
+        withKeysAndValues:#(
+                ScrollBar                 SCROLLBAR
+                HorizontalScrollBar       SCROLLBAR
+                VerticalScrollBar         SCROLLBAR
+                CheckBox                  BUTTON
+                RadioButton               BUTTON
+                Button                    BUTTON
+                DefaultButton             BUTTON
+                OwnerDrawButton           BUTTON
+                ComboBox                  COMBOBOX
+                EditField                 EDIT
+                ListBox                   LISTBOX
+        ).
 
     "Modified: / 24-08-2010 / 16:42:23 / sr"
+    "Modified: / 21-11-2019 / 10:04:42 / Stefan Reise"
 !
 
 initializeStandardColorNames
@@ -6266,6 +6272,59 @@
     "
 ! !
 
+!WinWorkstation class methodsFor:'converting'!
+
+convertVirtualResolutionPointToCurrentResolutionPoint:aPoint
+    "
+        self convertVirtualResolutionPointToCurrentResolutionPoint:2000@400    
+        self convertVirtualResolutionPointToCurrentResolutionPoint:2000@500  
+    "
+
+    |centerMonitorInfo centerMonitorScaleFactor
+     targetMonitorInfo minScaleFactor 
+     scaledX scaledY|
+
+    centerMonitorInfo := Display monitorInfoForPoint:0@0.
+    centerMonitorInfo isNil ifTrue:[
+        self halt. "/ should not happen?
+        ^ aPoint
+    ].             
+
+    centerMonitorScaleFactor := Screen scaleFactorForMonitorNamed:centerMonitorInfo name.
+    targetMonitorInfo := Display monitorInfoForPoint:aPoint.
+    (targetMonitorInfo isNil 
+    or:[targetMonitorInfo isCenterMonitor]) ifTrue:[
+        "the point is not inside any monitor
+         or is inside the center monitor
+         use the center monitor scale factor"       
+        ^ (aPoint * centerMonitorScaleFactor) rounded 
+    ].
+
+    minScaleFactor := (Display monitorInfos
+        collect:[:eachMonitorInfo |
+            Screen scaleFactorForRootViewTranslationOnMonitorNamed:eachMonitorInfo name
+        ])
+            min.
+
+    scaledX := self 
+        convertTargetValue:aPoint x
+        targetMonitorInfo:targetMonitorInfo 
+        minScaleFactor:minScaleFactor x
+        pointValueFetch:[:eachPoint | eachPoint x]
+        monitorInfoTopOrLeftFetch:[:monitorInfo | monitorInfo screenX].
+
+    scaledY := self 
+        convertTargetValue:aPoint y
+        targetMonitorInfo:targetMonitorInfo 
+        minScaleFactor:minScaleFactor y
+        pointValueFetch:[:eachPoint | eachPoint y]   
+        monitorInfoTopOrLeftFetch:[:monitorInfo | monitorInfo screenY].
+
+    ^ scaledX@scaledY
+
+    "Created: / 22-11-2019 / 10:09:49 / Stefan Reise"
+! !
+
 !WinWorkstation class methodsFor:'debugging'!
 
 bitmapHandleCounts
@@ -6575,79 +6634,45 @@
 
 !WinWorkstation class methodsFor:'private'!
 
-commonDisplayResolutionBinaryFromPackageSubPath:packageSubPath
-    binaryBaseNameWithoutSuffix:binaryBaseNameWithoutSuffix
-
-    "
-        Screen 
-            commonDisplayResolutionBinaryFromPackageSubPath:'currentDisplayResolution'
-            binaryBaseNameWithoutSuffix:'cdr'
-    "
-
-    |packageId directory|
-
-    packageId := 'stx:support/win32/', packageSubPath, '/bin'.
-    directory := Smalltalk packageDirectoryForPackageId:packageId.
-    directory isNil ifTrue:[
-        'package "', packageId, '" is missing"' errorPrintCR.
-        ^ nil
-    ].
-
-    ^ directory / (binaryBaseNameWithoutSuffix, '.exe')
-
-    "Created: / 19-11-2019 / 11:58:44 / Stefan Reise"
-!
-
-currentDisplayResolutionBinary
-    "
-        Screen currentDisplayResolutionBinary        
-    "
-
-    ^ self 
-        commonDisplayResolutionBinaryFromPackageSubPath:'currentDisplayResolution'
-        binaryBaseNameWithoutSuffix:'cdr'
-
-    "Created: / 15-11-2019 / 09:32:22 / Stefan Reise"
-    "Modified (comment): / 19-11-2019 / 11:59:34 / Stefan Reise"
-!
-
-displayResolutionFromTool:aFilenameOrNil
-    "
-        self displayResolutionFromTool:self currentDisplayResolutionBinary         
-        self displayResolutionFromTool:self virtualDisplayResolutionBinary     
-    "
-
-    |output pointValues|
-
-    aFilenameOrNil isNil ifTrue:[
-        ^ nil 
-    ].                            
-    aFilenameOrNil exists ifFalse:[
-        'tool binary "', aFilenameOrNil nameString, '" is missing"' errorPrintCR.
-        ^ nil
-    ].
-
-    output := '' writeStream.   
-
-    OperatingSystem
-        executeCommand:aFilenameOrNil pathName
-        outputTo:output 
-        errorTo:output.
-
-    pointValues := output contents subStrings:$x.
-
-    ^ pointValues first asInteger@pointValues second asInteger
-
-    "Created: / 15-11-2019 / 09:37:01 / Stefan Reise"
-    "Modified: / 19-11-2019 / 12:03:00 / Stefan Reise"
-!
-
-virtualDisplayResolution
-    "ATTENTION: can return nil if the package or the tool is missing:
-     stx:support/win32/virtualDisplayResolution/bin/vdr.exe  
-
-     this is the resolution of a virtual display,
-     this resolution is effected by the scaling
+convertTargetValue:targetValue
+    targetMonitorInfo:targetMonitorInfo 
+    minScaleFactor:minScaleFactor
+    pointValueFetch:pointValueFetch
+    monitorInfoTopOrLeftFetch:monitorInfoTopOrLeftFetch
+
+    |scaleFactorInTargetMonitor targetMonitorVirtualTopOrLeft 
+     targetMonitorRealTopOrLeft remainingVirtual remainingReal 
+     returnValue|
+
+    scaleFactorInTargetMonitor := pointValueFetch 
+        value:(Screen 
+            scaleFactorForRootViewTranslationOnMonitorNamed:targetMonitorInfo name).
+
+    "check if target moinitor is the center monitor"
+    targetMonitorVirtualTopOrLeft := monitorInfoTopOrLeftFetch value:targetMonitorInfo.
+    targetMonitorVirtualTopOrLeft == 0 ifTrue:[
+        returnValue := (targetValue * scaleFactorInTargetMonitor) rounded.
+        ^ returnValue
+    ].
+
+    "targte monitor is not the center monitor,
+     scale the x of the monitor with the min. scale factor 
+     and the remaining stuff with the target monitor scale factor"
+    targetMonitorRealTopOrLeft := (targetMonitorVirtualTopOrLeft * minScaleFactor) rounded.
+    remainingVirtual := targetValue - targetMonitorVirtualTopOrLeft.
+    remainingReal := (remainingVirtual * scaleFactorInTargetMonitor) rounded.
+
+    ^ targetMonitorRealTopOrLeft + remainingReal
+
+    "Created: / 22-11-2019 / 10:37:55 / Stefan Reise"
+!
+
+primResolutionForMonitorNamed:aMonitorDeviceNameOrNil
+    trueForVirtualResolutionOrFalseForCurrentResolution:trueForVirtualResolutionOrFalseForCurrentResolution
+
+    "ATTENTION: can return nil if the package or the tools are missing:
+     stx:support/win32/displayResolutionTools/bin/cdr.exe
+     stx:support/win32/displayResolutionTools/bin/vdr.exe
 
      for e.g.
         real current display resolution -> 1080p
@@ -6656,57 +6681,87 @@
 
         real current display resolution -> 1080p
         scaling 100%
-        virtual display resolution -> 1080p"
-
-    "
-        VirtualDisplayResolutionFromTool := nil.
-        self virtualDisplayResolution
-    "    
-
-    |tmp|
-
-    VirtualDisplayResolutionFromTool isNil ifTrue:[
-        tmp := self displayResolutionFromTool:self virtualDisplayResolutionBinary.
-        tmp isNil ifTrue:[
-            "use 0 to indicate nil,
-             avoid recalling of #displayResolutionFromTool:"
-            VirtualDisplayResolutionFromTool := 0.
-        ] ifFalse:[
-            VirtualDisplayResolutionFromTool := tmp.
-        ].
-    ].
-
-    VirtualDisplayResolutionFromTool == 0 ifTrue:[
+        virtual display resolution -> 1080p"     
+
+    "
+        self 
+            primResolutionForMonitorNamed:nil
+            trueForVirtualResolutionOrFalseForCurrentResolution:true.      
+
+        self 
+            primResolutionForMonitorNamed:'some nonsense'
+            trueForVirtualResolutionOrFalseForCurrentResolution:true.       
+
+        self 
+            primResolutionForMonitorNamed:'\\.\DISPLAY1'
+            trueForVirtualResolutionOrFalseForCurrentResolution:false.       
+
+        self 
+            primResolutionForMonitorNamed:'\\.\DISPLAY1'
+            trueForVirtualResolutionOrFalseForCurrentResolution:true.         
+
+        self 
+            primResolutionForMonitorNamed:'\\.\DISPLAY2'
+            trueForVirtualResolutionOrFalseForCurrentResolution:false.         
+
+        self 
+            primResolutionForMonitorNamed:'\\.\DISPLAY2'
+            trueForVirtualResolutionOrFalseForCurrentResolution:true.              
+    "
+
+    |packageId directory toolBaseNameWithoutSuffix 
+     filenameOrNil output pointValues|
+
+    aMonitorDeviceNameOrNil isNil ifTrue:[
+        ^ nil
+    ].
+
+    packageId := 'stx:support/win32/displayResolutionTools/bin'.
+    directory := Smalltalk packageDirectoryForPackageId:packageId.
+    directory isNil ifTrue:[
+        'package "', packageId, '" is missing"' errorPrintCR.
         ^ nil
     ].
 
-    ^ VirtualDisplayResolutionFromTool
-
-    "Created: / 15-11-2019 / 09:37:48 / Stefan Reise"
-    "Modified (format): / 19-11-2019 / 12:17:02 / Stefan Reise"
-!
-
-virtualDisplayResolutionBinary
-    "      
-        Screen virtualDisplayResolutionBinary   
-    "
-
-    ^ self 
-        commonDisplayResolutionBinaryFromPackageSubPath:'virtualDisplayResolution'
-        binaryBaseNameWithoutSuffix:'vdr'
-
-    "Created: / 15-11-2019 / 09:32:51 / Stefan Reise"
-    "Modified (comment): / 19-11-2019 / 11:59:52 / Stefan Reise"
-! !
-
-!WinWorkstation class methodsFor:'queries'!
-
-currentDisplayResolution
-    "ATTENTION: can return nil if the package or the tool is missing:
-     stx:support/win32/currentDisplayResolution/bin/cdr.exe
-
-     this is the current resolution of the display,
-     without any effect of scaling
+    trueForVirtualResolutionOrFalseForCurrentResolution ifTrue:[
+        toolBaseNameWithoutSuffix := 'vdr'.    
+    ] ifFalse:[
+        toolBaseNameWithoutSuffix := 'cdr'.    
+    ].
+
+    filenameOrNil := directory / (toolBaseNameWithoutSuffix, '.exe').
+    filenameOrNil isNil ifTrue:[
+        ^ nil 
+    ].                            
+    filenameOrNil exists ifFalse:[
+        'tool binary "', filenameOrNil nameString, '" is missing"' errorPrintCR.
+        ^ nil
+    ].
+
+    output := '' writeStream.   
+
+    (OperatingSystem
+        executeCommand:('"%1" %2'
+            bindWith:filenameOrNil pathName
+            with:aMonitorDeviceNameOrNil)
+        outputTo:output 
+        errorTo:output) ifFalse:[
+            ^ nil
+        ].
+
+    pointValues := output contents subStrings:$x.
+
+    ^ pointValues first asInteger@pointValues second asInteger
+
+    "Created: / 21-11-2019 / 10:07:34 / Stefan Reise"
+!
+
+resolutionForMonitorNamed:aMonitorDeviceName
+    trueForVirtualResolutionOrFalseForCurrentResolution:trueForVirtualResolutionOrFalseForCurrentResolution
+
+    "ATTENTION: can return nil if the package or the tools are missing:
+     stx:support/win32/displayResolutionTools/bin/cdr.exe
+     stx:support/win32/displayResolutionTools/bin/vdr.exe
 
      for e.g.
         real current display resolution -> 1080p
@@ -6715,68 +6770,69 @@
 
         real current display resolution -> 1080p
         scaling 100%
-        virtual display resolution -> 1080p"         
-
-    "
-        CurrentDisplayResolutionFromTool := nil. 
-        self currentDisplayResolution            
+        virtual display resolution -> 1080p"     
+
+    "
+        MonitorNameToCurrentResolution := Dictionary new. 
+        MonitorNameToVirtualResolution := Dictionary new. 
+
+        self 
+            resolutionForMonitorNamed:'\\.\DISPLAY1'      
+            trueForVirtualResolutionOrFalseForCurrentResolution:false.         
+
+        self 
+            resolutionForMonitorNamed:'\\.\DISPLAY1'      
+            trueForVirtualResolutionOrFalseForCurrentResolution:true.         
+
+        self 
+            resolutionForMonitorNamed:'\\.\DISPLAY2'      
+            trueForVirtualResolutionOrFalseForCurrentResolution:false.        
+
+        self 
+            resolutionForMonitorNamed:'\\.\DISPLAY2'      
+            trueForVirtualResolutionOrFalseForCurrentResolution:true.          
     "    
 
-    |tmp|
-
-    CurrentDisplayResolutionFromTool isNil ifTrue:[
-        tmp := self displayResolutionFromTool:self currentDisplayResolutionBinary.
-        tmp isNil ifTrue:[
-            "use 0 to indicate nil,
-             avoid recalling of #displayResolutionFromTool:"
-            CurrentDisplayResolutionFromTool := 0.
-        ] ifFalse:[
-            CurrentDisplayResolutionFromTool := tmp.
-        ].
-    ].
-
-    CurrentDisplayResolutionFromTool == 0 ifTrue:[
+    |cacheDictionary currentResolution|
+
+    aMonitorDeviceName isNil ifTrue:[
         ^ nil
     ].
 
-    ^ CurrentDisplayResolutionFromTool
-
-    "Created: / 15-11-2019 / 09:37:53 / Stefan Reise"
-    "Modified (comment): / 19-11-2019 / 12:17:27 / Stefan Reise"
-!
-
-displayScaleFactor
-    "ATTENTION: returns the may wrong default 1@1 if the package or the tool is missing:
-     stx:support/win32/currrentDisplayResolution/bin/cdr.exe
-     stx:support/win32/virtualDisplayResolution/bin/vdr.exe
-
-     this is the scale factor the user did enter within the windows settings,
-     for e.g. the user can choose between 100, 125, 150 etc.
-     here we return 1, 1.25 1.5"
-
-    "
-        self displayScaleFactor          
-    "
-
-    |currentDisplayResolution virtualDisplayResolution|
-
-    currentDisplayResolution := self currentDisplayResolution.
-    currentDisplayResolution isNil ifTrue:[
-        "may the tool binary is missing (this is already catched in #displayResolutionFromTool:)"
-        ^ 1@1
-    ].
-
-    virtualDisplayResolution := self virtualDisplayResolution.
-    virtualDisplayResolution isNil ifTrue:[
-        "may the tool binary is missing (this is already catched in #displayResolutionFromTool:)"
-        ^ 1@1
-    ].
-
-    ^ currentDisplayResolution / virtualDisplayResolution
-
-    "Created: / 15-11-2019 / 09:43:53 / Stefan Reise"
-    "Modified (comment): / 19-11-2019 / 12:07:55 / Stefan Reise"
-!
+    trueForVirtualResolutionOrFalseForCurrentResolution ifTrue:[
+        cacheDictionary := MonitorNameToVirtualResolution.
+    ] ifFalse:[
+        cacheDictionary := MonitorNameToCurrentResolution.
+    ].
+
+    currentResolution := cacheDictionary
+        at:aMonitorDeviceName
+        ifAbsent:nil.                   
+
+    currentResolution isNil ifTrue:[
+        MonitorNameDictionariesSema critical:[
+            currentResolution := cacheDictionary
+                at:aMonitorDeviceName
+                ifAbsentPut:[
+                    (self 
+                        primResolutionForMonitorNamed:aMonitorDeviceName
+                        trueForVirtualResolutionOrFalseForCurrentResolution:trueForVirtualResolutionOrFalseForCurrentResolution)  
+                            ? 0 "/ use 0 to indicate nil, avoid recalling of #displayResolutionForDisplayWithDeviceName:...
+                ].
+        ].
+    ].
+
+    currentResolution == 0 ifTrue:[
+        ^ nil
+    ].                           
+
+    ^ currentResolution
+
+    "Created: / 21-11-2019 / 10:06:51 / Stefan Reise"
+    "Modified: / 22-11-2019 / 10:41:38 / Stefan Reise"
+! !
+
+!WinWorkstation class methodsFor:'queries'!
 
 isWindowsPlatform
     "return true, if this device is a windows screen"
@@ -6792,31 +6848,245 @@
     ^ 'WIN32'
 
     "Modified: 26.5.1996 / 15:32:46 / cg"
-!
-
-scaleFactorForRootDisplayCoordinates
-    "ATTENTION: returns the may wrong default 1@1 (from super) if the package or the tool is missing:
-     stx:support/win32/currrentDisplayResolution/bin/cdr.exe
-
-     this is the factor we need to adopt for the root display coordinates,
-     if windows did scale the application (when the app is not high DPI aware)"
-
-    "
-        self scaleFactorForRootDisplayCoordinates 
-    "
-
-    |currentDisplayResolution|
-
-    currentDisplayResolution := self currentDisplayResolution.
-    currentDisplayResolution isNil ifTrue:[
-        "may the tool binary is missing (this is already catched in #displayResolutionFromTool:)"
-        ^ super scaleFactorForRootDisplayCoordinates
-    ].
-
-    ^ currentDisplayResolution / Display extent
-
-    "Created: / 14-11-2019 / 13:36:59 / Stefan Reise"
-    "Modified (comment): / 19-11-2019 / 12:08:26 / Stefan Reise"
+! !
+
+!WinWorkstation class methodsFor:'queries - monitor'!
+
+currentResolutionForMonitorNamed:aMonitorDeviceName
+    "ATTENTION: can return nil if the package or the tool is missing:
+     stx:support/win32/displayResolutionTools/bin/cdr.exe
+
+     this is the current resolution of the display,
+     without any effect of scaling
+
+     for e.g.
+        real current display resolution -> 1080p
+        scaling 150%
+        virtual display resolution -> 720p
+
+        real current display resolution -> 1080p
+        scaling 100%
+        virtual display resolution -> 1080p"         
+
+    "
+        MonitorNameToCurrentResolution := Dictionary new.       
+        self currentResolutionForMonitorNamed:'\\.\DISPLAY1'.      
+        self currentResolutionForMonitorNamed:'\\.\DISPLAY2'.      
+    "    
+
+    |currentResolution|
+
+    currentResolution := self 
+        resolutionForMonitorNamed:aMonitorDeviceName
+        trueForVirtualResolutionOrFalseForCurrentResolution:false.
+
+    currentResolution isNil ifTrue:[
+        ^ super currentResolutionForMonitorNamed:aMonitorDeviceName
+    ].
+
+    ^ currentResolution
+
+    "Created: / 21-11-2019 / 10:10:16 / Stefan Reise"
+    "Modified (comment): / 22-11-2019 / 10:22:06 / Stefan Reise"
+!
+
+monitorDeviceNameForPoint:aPoint
+    "given a point, return its monitor device name or nil if failed"
+
+    "
+        Screen monitorDeviceNameForPoint:0@0      
+        Screen monitorDeviceNameForPoint:2000@0    
+    "          
+
+    |incomingX incomingY|
+
+    incomingX := aPoint x.
+    incomingY := aPoint y. 
+
+%{
+    POINT pt;
+    HMONITOR hMonitor;
+    MONITORINFOEX monitorInfo;
+
+    pt.x = __intVal(incomingX);
+    pt.y = __intVal(incomingY);
+
+    hMonitor = MonitorFromPoint(pt, MONITOR_DEFAULTTOPRIMARY);
+    if (hMonitor == 0) {
+        RETURN(nil);
+    }
+
+    monitorInfo.cbSize = sizeof(MONITORINFOEX);
+    if (GetMonitorInfo(hMonitor, &monitorInfo) == 0){
+        RETURN(nil);
+    }              
+
+    RETURN(__MKSTRING(monitorInfo.szDevice));
+%}
+
+    "Created: / 21-11-2019 / 09:13:57 / Stefan Reise"
+    "Modified (comment): / 21-11-2019 / 12:36:21 / Stefan Reise"
+!
+
+monitorDeviceNameForView:aView
+    "given a window ID, return its monitor device name or nil if failed"
+
+    "
+        Screen monitorDeviceNameForView:Transcript topView     
+    "         
+
+    |windowId|
+
+    windowId := aView id.
+
+%{
+    if (__isExternalAddress(windowId)) {
+        HMONITOR hMonitor;
+        MONITORINFOEX monitorInfo;
+
+        hMonitor = MonitorFromWindow(_HWNDVal(windowId), MONITOR_DEFAULTTOPRIMARY);
+        if (hMonitor == 0) {
+            RETURN(nil);
+        }
+
+        monitorInfo.cbSize = sizeof(MONITORINFOEX);
+        if (GetMonitorInfo(hMonitor, &monitorInfo) == 0){
+            RETURN(nil);
+        }              
+
+        RETURN(__MKSTRING(monitorInfo.szDevice));
+    }
+%}
+
+    "Created: / 20-11-2019 / 14:52:59 / Stefan Reise"
+    "Modified: / 21-11-2019 / 18:04:50 / Stefan Reise"
+    "Modified (comment): / 22-11-2019 / 10:22:49 / Stefan Reise"
+!
+
+scaleFactorForMonitorNamed:aMonitorDeviceName                 
+    "ATTENTION: returns the may wrong default 1@1 if the package or the tools are missing:
+     stx:support/win32/displayResolutionTools/bin/cdr.exe
+     stx:support/win32/displayResolutionTools/bin/vdr.exe
+
+     ATTENTION: this method always returns the scale factor set by os,
+     REGARDLESS if the application (stx, expecco) has a virtual resolution or not
+     use #scaleFactorForRootViewTranslationOnMonitorNamed: which is dependent on the 
+     application's (stx, expecco) high dpi awareness (if the application has a virtual 
+     resolution or not).
+
+     this is the scale factor the user did enter within the windows settings,
+     for e.g. the user can choose between 100, 125, 150 etc.
+     here we return 1, 1.25 1.5"
+
+    "
+        self scaleFactorForMonitorNamed:'\\.\DISPLAY1'          
+        self scaleFactorForMonitorNamed:'\\.\DISPLAY2'            
+    "
+
+    |currentMonitorResolution virtualMonitorResolution|
+
+    currentMonitorResolution := self currentResolutionForMonitorNamed:aMonitorDeviceName.
+    currentMonitorResolution isNil ifTrue:[
+        "may the tool binary is missing"
+        ^ super scaleFactorForMonitorNamed:aMonitorDeviceName
+    ].
+
+    virtualMonitorResolution := self virtualResolutionForMonitorNamed:aMonitorDeviceName.
+    virtualMonitorResolution isNil ifTrue:[
+        "may the tool binary is missing"
+        ^ 1@1   
+    ].
+
+    ^ currentMonitorResolution / virtualMonitorResolution
+
+    "Created: / 21-11-2019 / 10:12:00 / Stefan Reise"
+    "Modified: / 22-11-2019 / 10:01:09 / Stefan Reise"
+!
+
+scaleFactorForRootViewTranslationOnMonitorNamed:aMonitorDeviceName                 
+    "ATTENTION: returns the may wrong default 1@1 if the package or the tool is missing:
+     stx:support/win32/displayResolutionTools/bin/cdr.exe
+
+     this is the scale factor, we have to use,
+     when we work directly with the root view (desktop)
+
+     because we may have a virtual display,
+     but the screen (from which we take a screenshot for e.g.)
+     does always have the current resoltion,
+     therefor we have to translate from virtual to current resolution"
+
+    "
+        self scaleFactorForRootViewTranslationOnMonitorNamed:'\\.\DISPLAY1'          
+        self scaleFactorForRootViewTranslationOnMonitorNamed:'\\.\DISPLAY2'            
+    "
+
+    |currentMonitorResolution monitorHandle monitorInfo|
+
+    currentMonitorResolution := Screen currentResolutionForMonitorNamed:aMonitorDeviceName.
+    currentMonitorResolution isNil ifTrue:[
+        "may the tool binary is missing"
+        ^ super scaleFactorForRootViewTranslationOnMonitorNamed:aMonitorDeviceName
+    ].
+
+    monitorHandle := Display monitorHandleForName:aMonitorDeviceName.
+    monitorHandle isNil ifTrue:[
+        ^ super scaleFactorForRootViewTranslationOnMonitorNamed:aMonitorDeviceName
+    ].                
+
+    monitorInfo := Display monitorInfoFor:monitorHandle.
+    monitorInfo isNil ifTrue:[
+        "something wrong with the monitor name?"
+        ^ super scaleFactorForRootViewTranslationOnMonitorNamed:aMonitorDeviceName
+    ].      
+
+    "the #monitorInfo contains the virtual resolution,
+     if the application is not high dpi aware.
+     otherwise the current resolution"
+    ^ currentMonitorResolution / ((monitorInfo screenWidth)@(monitorInfo screenHeight))
+
+    "Created: / 21-11-2019 / 12:33:11 / Stefan Reise"
+    "Modified (format): / 22-11-2019 / 10:23:16 / Stefan Reise"
+!
+
+virtualResolutionForMonitorNamed:aMonitorDeviceName
+    "ATTENTION: can return nil if the package or the tool is missing:
+     stx:support/win32/displayResolutionTools/bin/vdr.exe  
+
+     ATTENTION: this method always returns the virtual resolution,
+     REGARDLESS if the application (stx, expecco) has a virtual resolution or not
+
+     this is the resolution of a virtual display,
+     this resolution is effected by the scaling
+
+     for e.g.
+        real current display resolution -> 1080p
+        scaling 150%
+        virtual display resolution -> 720p
+
+        real current display resolution -> 1080p
+        scaling 100%
+        virtual display resolution -> 1080p"
+
+    "                                              
+        MonitorNameToVirtualResolution := Dictionary new.    
+        self virtualResolutionForMonitorNamed:'\\.\DISPLAY1'     
+        self virtualResolutionForMonitorNamed:'\\.\DISPLAY2'     
+    "    
+
+    |virtualResolution|
+
+    virtualResolution := self 
+        resolutionForMonitorNamed:aMonitorDeviceName
+        trueForVirtualResolutionOrFalseForCurrentResolution:true.
+
+    virtualResolution isNil ifTrue:[
+        ^ 1@1   
+    ].
+
+    ^ virtualResolution
+
+    "Created: / 21-11-2019 / 10:13:54 / Stefan Reise"
+    "Modified: / 22-11-2019 / 10:00:35 / Stefan Reise"
 ! !
 
 !WinWorkstation methodsFor:'accessing & queries'!
@@ -7877,18 +8147,16 @@
 monitorBoundsAt:aPoint
     "answer the bounds of the monitor the point is contained in"
 
-    |monitorHandle monitorInfo|
+    |monitorInfo|
 
     self numberOfMonitors > 1 ifTrue:[
-	"/ ******* MULTI SCREEN ******
-	monitorHandle := self monitorHandleForPoint:aPoint.
-	monitorHandle notNil ifTrue:[
-	    monitorInfo := self monitorInfoFor:monitorHandle.
-	    monitorInfo notNil ifTrue:[
-		^ monitorInfo bounds
-	    ].
-	].
-    ].
+        "/ ******* MULTI SCREEN ******
+        monitorInfo := self monitorInfoForPoint:aPoint.
+        monitorInfo notNil ifTrue:[
+            ^ monitorInfo bounds
+        ].
+    ].
+
     ^ super monitorBoundsAt:aPoint
 
     "
@@ -7898,6 +8166,166 @@
     "
 
     "Modified: / 22-10-2010 / 10:55:59 / cg"
+    "Modified: / 22-11-2019 / 10:14:50 / Stefan Reise"
+!
+
+monitorHandleForName:aMonitorDeviceName
+    "given a name, return a handle to the monitor"
+
+    "
+        Display monitorHandleForName:'some nonsense'.
+        Display monitorInfoFor:(Display monitorHandleForName:'\\.\DISPLAY1')     
+        Display monitorInfoFor:(Display monitorHandleForName:'\\.\DISPLAY2')     
+    "                   
+
+    self monitorHandles do:[:eachMonitorHandle |
+        (self monitorInfoFor:eachMonitorHandle) name = aMonitorDeviceName ifTrue:[
+            ^ eachMonitorHandle
+        ].
+    ].
+
+    ^ nil
+
+    "Created: / 21-11-2019 / 12:13:33 / Stefan Reise"
+    "Modified: / 21-11-2019 / 13:32:11 / Stefan Reise"
+!
+
+monitorHandleForPoint:aPoint
+    "given a point, return a handle to the monitor"
+
+    |pX pY|
+
+    pX := aPoint x.
+    pY := aPoint y.
+%{
+    if (__bothSmallInteger(pX, pY)) {
+	POINT p;
+	HMONITOR hMonitor;
+	p.x = __intVal(pX);
+	p.y = __intVal(pY);
+#if 0
+	/* the following is only needed when we want
+	 * to support very old NT/W95/W98 systems; we don't !
+	 */
+	static HMONITOR (__stdcall *P_MonitorFromPoint)(POINT, int);
+
+	if (P_MonitorFromPoint == 0) {
+	    HINSTANCE hUser = LoadLibrary("user32.dll");
+	    // console_printf("hUser: %x\n", hUser);
+	    if (hUser) {
+		P_MonitorFromPoint = (HMONITOR (__stdcall *)(POINT, int ))
+				    GetProcAddress(hUser, "MonitorFromPoint");
+	    }
+	}
+	// console_printf("P_MonitorFromPoint: %x\n", P_MonitorFromPoint);
+
+	hMonitor = (*P_MonitorFromPoint)(p, MONITOR_DEFAULTTONULL);
+#else
+	hMonitor = MonitorFromPoint(p, MONITOR_DEFAULTTONULL);
+#endif
+	if (hMonitor == 0) {
+	    RETURN(nil);
+	}
+	RETURN ( __MKEXTERNALADDRESS(hMonitor) );
+    }
+%}
+    "
+     Screen current monitorHandleForPoint:(0@0)
+     Screen current monitorHandleForPoint:(1500@0)
+     Screen current monitorHandleForPoint:(3000@0)
+     Screen current monitorHandleForPoint:(Display pointFromUser)
+    "
+!
+
+monitorHandleForView:aWindowId
+    "given a window ID, return a handle to the monitor"
+
+%{
+    if (__isExternalAddress(aWindowId)) {
+        HWND hWnd = _HWNDVal(aWindowId);
+        HMONITOR hMonitor;
+#if 0
+        /* the following is only needed when we want
+         * to support very old NT/W95/W98 systems; we don't !
+         */
+        static HMONITOR (__stdcall *P_MonitorFromWindow)(HWND, int);
+
+        if (P_MonitorFromWindow == 0) {
+            HINSTANCE hUser = LoadLibrary("user32.dll");
+            // console_printf("hUser: %x\n", hUser);
+            if (hUser) {
+                P_MonitorFromWindow = (HMONITOR (__stdcall *)(HWND, int ))
+                                    GetProcAddress(hUser, "MonitorFromWindow");
+            }
+        }
+        // console_printf("P_MonitorFromWindow: %x\n", P_MonitorFromWindow);
+        hMonitor = (*P_MonitorFromWindow)(hWnd, MONITOR_DEFAULTTONULL);
+#else
+        hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONULL);
+#endif
+        if (hMonitor == 0) {
+            RETURN(nil);
+        }
+        RETURN ( __MKEXTERNALADDRESS(hMonitor) );
+    }
+%}
+    "
+     Screen current monitorHandleForView:(Transcript topView id)
+     Screen current monitorHandleForPoint:(0@0)
+    "
+!
+
+monitorHandles
+    "retrieve a list of monitor handles"
+
+    |handleArray|
+
+    handleArray := Array new:(self numberOfMonitors).
+%{
+    struct EnumDisplayMonitorsProcData data;
+
+    data.hArray = handleArray;
+    data.index = 0;
+    EnumDisplayMonitors(NULL, NULL, EnumDisplayMonitorsProc, (INT)&data);
+%}.
+    ^ handleArray
+
+    "
+     Screen default monitorHandles
+    "
+
+    "Modified (comment): / 28-01-2012 / 10:26:55 / cg"
+!
+
+monitorInfoForPoint:aPoint
+    "answer the bounds of the monitor the point is contained in"
+
+    "
+        Display monitorInfoForPoint:100@100           
+        Display monitorInfoForPoint:2000@100          
+        Display monitorInfoForPoint:-200@100          
+    "                
+
+    |monitorHandle|
+
+    monitorHandle := self monitorHandleForPoint:aPoint.
+    monitorHandle notNil ifTrue:[
+        ^ self monitorInfoFor:monitorHandle
+    ].
+
+    ^ nil
+
+    "Created: / 21-11-2019 / 11:11:47 / Stefan Reise"
+    "Modified: / 22-11-2019 / 09:57:05 / Stefan Reise"
+!
+
+monitorInfos
+    ^ self monitorHandles 
+        collect:[:eachMonitorHandle |
+            self monitorInfoFor:eachMonitorHandle
+        ].
+
+    "Created: / 21-11-2019 / 13:35:22 / Stefan Reise"
 !
 
 numberOfMonitors
@@ -8093,20 +8521,20 @@
      On multi-display systems with different sized screens, this should care for
      which display is at the given x-position"
 
-    |info fullHeight usableHeight delta|
+    |info|
 
     true "(self numberOfMonitors) > 1" ifTrue:[
-	"/ ******* MULTI SCREEN ******
-	info := self monitorInfoFor:(self monitorHandleForPoint:aPoint).
-	info notNil ifTrue:[
-	    ^ info workHeight
-
-	"/ only works with single screen..
+        "/ ******* MULTI SCREEN ******
+        info := self monitorInfoForPoint:aPoint.
+        info notNil ifTrue:[
+            ^ info workHeight
+
+        "/ only works with single screen..
 "/            fullHeight := self getSystemMetrics:#SM_CYVIRTUALSCREEN.
 "/            usableHeight := self getSystemMetrics:#SM_CYFULLSCREEN.  "/ without any start-menu bar
 "/            delta := fullHeight - usableHeight.
 "/            ^ info workHeight - delta
-	].
+        ].
     ].
     ^ self usableHeight
 
@@ -8121,21 +8549,19 @@
     "
 
     "Modified (comment): / 27-10-2012 / 13:34:32 / cg"
+    "Modified: / 22-11-2019 / 10:15:17 / Stefan Reise"
 !
 
 workableAreaBoundsAt:aPoint
     "return a rectangle representing the displays bounding box 
      of the workable area (without TaskBar etc.) of the monitor"
 
-    |monitorHandle monitorInfo|
+    |monitorInfo|
 
     "/ ******* MULTI SCREEN ******
-    monitorHandle := self monitorHandleForPoint:aPoint.
-    monitorHandle notNil ifTrue:[
-        monitorInfo := self monitorInfoFor:monitorHandle.
-        monitorInfo notNil ifTrue:[
-            ^ monitorInfo workableAreaBounds
-        ].
+    monitorInfo := self monitorInfoForPoint:aPoint.
+    monitorInfo notNil ifTrue:[
+        ^ monitorInfo workableAreaBounds
     ].
 
     ^ super workableAreaBoundsAt:aPoint
@@ -8147,6 +8573,7 @@
     "
 
     "Created: / 23-05-2019 / 11:10:06 / Stefan Vogel"
+    "Modified: / 22-11-2019 / 10:15:40 / Stefan Reise"
 ! !
 
 !WinWorkstation methodsFor:'bitmap/window creation'!
@@ -16076,142 +16503,6 @@
 %}
 !
 
-monitorDeviceNameForView:aWindowId
-    "given a window ID, return its monitor device name or nil if failed"
-
-    "
-        Screen current monitorDeviceNameForView:Transcript topView id    
-    "          
-
-%{
-    if (__isExternalAddress(aWindowId)) {
-        HMONITOR hMonitor;
-        MONITORINFOEX monitorInfo;
-
-        hMonitor = MonitorFromWindow(_HWNDVal(aWindowId), MONITOR_DEFAULTTOPRIMARY);
-        if (hMonitor == 0) {
-            RETURN(nil);
-        }
-
-        monitorInfo.cbSize = sizeof(MONITORINFOEX);
-        if (GetMonitorInfo(hMonitor, &monitorInfo) == 0){
-            RETURN(nil);
-        }              
-
-        RETURN(__MKSTRING(monitorInfo.szDevice));
-    }
-%}
-
-    "Created: / 20-11-2019 / 14:52:59 / Stefan Reise"
-!
-
-monitorHandleForPoint:aPoint
-    "given a point, return a handle to the monitor"
-
-    |pX pY|
-
-    pX := aPoint x.
-    pY := aPoint y.
-%{
-    if (__bothSmallInteger(pX, pY)) {
-	POINT p;
-	HMONITOR hMonitor;
-	p.x = __intVal(pX);
-	p.y = __intVal(pY);
-#if 0
-	/* the following is only needed when we want
-	 * to support very old NT/W95/W98 systems; we don't !
-	 */
-	static HMONITOR (__stdcall *P_MonitorFromPoint)(POINT, int);
-
-	if (P_MonitorFromPoint == 0) {
-	    HINSTANCE hUser = LoadLibrary("user32.dll");
-	    // console_printf("hUser: %x\n", hUser);
-	    if (hUser) {
-		P_MonitorFromPoint = (HMONITOR (__stdcall *)(POINT, int ))
-				    GetProcAddress(hUser, "MonitorFromPoint");
-	    }
-	}
-	// console_printf("P_MonitorFromPoint: %x\n", P_MonitorFromPoint);
-
-	hMonitor = (*P_MonitorFromPoint)(p, MONITOR_DEFAULTTONULL);
-#else
-	hMonitor = MonitorFromPoint(p, MONITOR_DEFAULTTONULL);
-#endif
-	if (hMonitor == 0) {
-	    RETURN(nil);
-	}
-	RETURN ( __MKEXTERNALADDRESS(hMonitor) );
-    }
-%}
-    "
-     Screen current monitorHandleForPoint:(0@0)
-     Screen current monitorHandleForPoint:(1500@0)
-     Screen current monitorHandleForPoint:(3000@0)
-     Screen current monitorHandleForPoint:(Display pointFromUser)
-    "
-!
-
-monitorHandleForView:aWindowId
-    "given a window ID, return a handle to the monitor"
-
-%{
-    if (__isExternalAddress(aWindowId)) {
-        HWND hWnd = _HWNDVal(aWindowId);
-        HMONITOR hMonitor;
-#if 0
-        /* the following is only needed when we want
-         * to support very old NT/W95/W98 systems; we don't !
-         */
-        static HMONITOR (__stdcall *P_MonitorFromWindow)(HWND, int);
-
-        if (P_MonitorFromWindow == 0) {
-            HINSTANCE hUser = LoadLibrary("user32.dll");
-            // console_printf("hUser: %x\n", hUser);
-            if (hUser) {
-                P_MonitorFromWindow = (HMONITOR (__stdcall *)(HWND, int ))
-                                    GetProcAddress(hUser, "MonitorFromWindow");
-            }
-        }
-        // console_printf("P_MonitorFromWindow: %x\n", P_MonitorFromWindow);
-        hMonitor = (*P_MonitorFromWindow)(hWnd, MONITOR_DEFAULTTONULL);
-#else
-        hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONULL);
-#endif
-        if (hMonitor == 0) {
-            RETURN(nil);
-        }
-        RETURN ( __MKEXTERNALADDRESS(hMonitor) );
-    }
-%}
-    "
-     Screen current monitorHandleForView:(Transcript topView id)
-     Screen current monitorHandleForPoint:(0@0)
-    "
-!
-
-monitorHandles
-    "retrieve a list of monitor handles"
-
-    |handleArray|
-
-    handleArray := Array new:(self numberOfMonitors).
-%{
-    struct EnumDisplayMonitorsProcData data;
-
-    data.hArray = handleArray;
-    data.index = 0;
-    EnumDisplayMonitors(NULL, NULL, EnumDisplayMonitorsProc, (INT)&data);
-%}.
-    ^ handleArray
-
-    "
-     Screen default monitorHandles
-    "
-
-    "Modified (comment): / 28-01-2012 / 10:26:55 / cg"
-!
-
 setInputFocusTo:aWindowId
     self setInputFocusTo:aWindowId revertTo:nil
 !
@@ -20714,10 +21005,6 @@
 	height:workH - 1
 !
 
-isPrimary
-    ^ isPrimary
-!
-
 name
     ^ name
 !
@@ -20784,6 +21071,53 @@
     "Created: / 23-05-2019 / 11:06:15 / Stefan Vogel"
 ! !
 
+!WinWorkstation::MonitorInfo methodsFor:'printing'!
+
+printOn:aStream
+    aStream nextPutAll:self class nameWithoutPrefix.
+    aStream nextPutAll:'[origin:'.
+    aStream nextPutAll:(screenX@screenY) printString.
+    aStream nextPutAll:'|extent:'.
+    aStream nextPutAll:(screenW@screenH) printString.
+    aStream nextPutAll:']'.
+
+    "Created: / 21-11-2019 / 16:39:12 / Stefan Reise"
+! !
+
+!WinWorkstation::MonitorInfo methodsFor:'queries'!
+
+isCenterMonitor
+    "maybe the same as #isPrimary,
+     but I am not sure what #isPrimary does indicate exactly"
+
+    screenX == 0 ifFalse:[
+        ^ false
+    ].
+    screenY == 0 ifFalse:[
+        ^ false
+    ].   
+
+    ^ true
+
+    "Created: / 22-11-2019 / 10:31:16 / Stefan Reise"
+!
+
+isPrimary
+    ^ isPrimary
+!
+
+screenBottom
+    ^ screenY + screenH
+
+    "Created: / 21-11-2019 / 13:38:25 / Stefan Reise"
+!
+
+screenRight
+    ^ screenX + screenW
+
+    "Created: / 21-11-2019 / 13:38:17 / Stefan Reise"
+! !
+
 !WinWorkstation::NativeFileDialogCreationData methodsFor:'accessing'!
 
 dataAddress