Ticket UUID: | b64e03e54890420e8c80c6ad94d04f49fdceee2d | |||
Title: | Multi monitors issue on Windows | |||
Type: | Patch | Version: | 1.9.5 | |
Submitter: | anonymous | Created on: | 2015-09-12 15:13:56 | |
Subsystem: | bwidget 1.x | Assigned To: | oehhar | |
Priority: | 5 Medium | Severity: | Minor | |
Status: | Closed | Last Modified: | 2015-11-04 09:57:46 | |
Resolution: | Fixed | Closed By: | oehhar | |
Closed on: | 2015-11-04 09:57:46 | |||
Description: |
Hello , I noticed that in the file "dynhelp.tcl" BWidget 1.9.5, There is a comment stating : # On windows multi screen configurations, coordinates may get outside # the main screen. We suppose that all screens have the same size # because it is not possible to query the size of the other screens. Actually i faced this issue in my work and i came up with the following implementation to handle multi screens in Windows using the windows registry #This Function return Info about all the Monitors connected in Case of Windows Platform #Function Input : None #Function Output : list of lists, each sub list contains info about one of the screens. #Example : #Assume you have two screens, the output will look like {{0x0 0x0 0x690 0x41a} {0xfffffb00 0x0 0x500 0x400}} #The sub list contains in order relativeX , realtiveY , resolutionX , resolutionY for each screen #For primary screen relativeX and relativeY should be Zeros, and the relativeX and relativeY of the other screen is related to it. #In the above case the primary screen is on the right, thats why the relativeX of the second screen is negative. #The resolutionX and resolutionY is the resolution of each screen. # Note that i grep these values from the registry thats why they appear in Hex. #By comparing the relativeX and relativeY values of all the screens, you should be #able to easily allocate your primary screen and the location of other screens with respect to it. #Function was tested under Tcl8.4 under cygwin (Windows XP). #Function was tested under Tcl8.4 under Linux (RH4). #Function was tested under Tcl8.5 Active state (Windows 7). #Function was tested under Tcl8.5 under cygwin (Windows 7). proc getMonitorsInfo {} { global tcl_platform set resultList "" if {$tcl_platform(os) != "Linux"} { # get the number of monitors set monitors [exec reg query {HKLM\SYSTEM\CurrentControlSet\services\monitor\Enum }] set monitors [exec echo $monitors | grep Count] set monitors [split $monitors " " ] set monitors [lindex $monitors end] # search the registry to get the screens resolutions and find the main screen set my_query "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Hardware\ Profiles\\UnitedVideo\\CONTROL\\VIDEO\\" set tmp [exec reg query $my_query] # split the result into lines to loop on them set tmp [split $tmp "\n"] #loop to find all under \\VIDEO for {set it 0} {$it < [llength $tmp] } {incr it} { set my_query "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Hardware\ Profiles\\UnitedVideo\\CONTROL\\VIDEO\\" # get the line set for_tmp [lindex $tmp $it] #puts $for_tmp # split the line by backslashes set for_tmp [split $for_tmp "\\"] # get the last item after splitting,will be like "{21B5061B-2F71-4D25-8BB5-5CD5A8833140}" set for_tmp [lindex $for_tmp end] #make sure empty strings in the list are not used if { [string length $for_tmp] < 10 } { continue } #puts $for_tmp # concat the original query with the new part ,and execute it set my_query $my_query$for_tmp set temp [exec reg query $my_query] # split again to loop on entries of the sub key line by line set temp [split $temp "\n"] #puts $temp #loop to find all under each sub key of \\VIDEO for {set i 0} {$i < [llength $temp]} {incr i} { # get each line set for_temp [lindex $temp $i ] #puts $for_temp # make sure empty strings in the list are not used if { [string length $for_temp] < 10 } { continue } # get the values of resolution x , resolution y , relative x , and attach.todektop # execute query with the new sub key set for_temp [exec reg query $for_temp] # grep on the values you want set att_x [exec echo $for_temp | grep Attach.ToDesktop] set att_x [split $att_x " "] set att_x [lindex $att_x end] #if attach.todesktop != 1, then this screen is not used, ignore it #else check if this is the main screen (relative x == 0) if {$att_x != "0x01"} { break } set monitorList "" set rel_x [exec echo $for_temp | grep Attach.RelativeX] set rel_x [split $rel_x " "] set rel_x [lindex $rel_x end] lappend monitorList $rel_x set rel_y [exec echo $for_temp | grep Attach.RelativeY] set rel_y [split $rel_y " "] set rel_y [lindex $rel_y end] lappend monitorList $rel_y set res_x [exec echo $for_temp | grep XResolution] set res_x [split $res_x " "] set res_x [lindex $res_x end] lappend monitorList $res_x set res_y [exec echo $for_temp | grep YResolution] set res_y [split $res_y " "] set res_y [lindex $res_y end] lappend monitorList $res_y lappend resultList $monitorList } } return $resultList } else { puts "This Function is not supported in Linux" return $resultList } } #just for testing set x [getMonitorsInfo] puts $x | |||
User Comments: |
oehhar added on 2015-11-04 09:57:46:
(text/x-fossil-wiki)
The proposed code has some advantages. Nevertheless, this may be done to some limits with vrootx/vrooty with a little amount of code. This was implemented by checkin [0371bea522]. This does not cover the two cases: - dynhelp may be on a screen border of two virtual screens - On windows, a screen portion on the virtual screen may have no real representation, if the screens have different heights. Point 1 is accepted to be compatible to Unix. Point 2 is accepted as minor drawback Thank you, I am closing the ticket. Maybee, the contributed code may be copied somewhere else... oehhar added on 2015-10-23 14:06:03: (text/x-fossil-wiki) The following twapi command gives the same result in some other words: <verbatim> twapi::get_multiple_display_monitor_info {-extent {0 0 1920 1080} -workarea {0 0 1920 1040} -primary 1 -name {\\.\DISPLAY1}}\ {-extent {1920 0 3200 720} -workarea {1920 0 3200 680} -primary 0 -name {\\.\DISPLAY2}} </verbatim> Basically, the contents of the rectangles in -extend give valid monitor coordinates. oehhar added on 2015-10-23 13:28:49: (text/x-fossil-wiki) apn commented on the wiki: <verbatim> twapi does have get_display_monitors and get_display_monitor_info commands for that purpose </verbatim> oehhar added on 2015-10-23 12:27:04: (text/x-fossil-wiki) I have tested the code. For me, it results in to many monitors. This is due to the fact, that I have multiple control sets under HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\UnitedVideo\CONTROL\VIDEO The key HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\IDConfigDB->CurrentConfig tells you, which is the current. So, only this key should be taken. Here is the modified code: <verbatim> #This Function return Info about all the Monitors connected in Case of Windows Platform #Function Input : None #Function Output : list of lists, each sub list contains info about one of the screens. #Example : #Assume you have two screens, the output will look like {{0 0 1680 1050} {-1280 0 1280 1024}} #The sub list contains in order relativeX , realtiveY , resolutionX , resolutionY for each screen #For primary screen relativeX and relativeY should be Zeros, and the relativeX and relativeY of the other screen is related to it. #In the above case the primary screen is on the right, thats why the relativeX of the second screen is negative. #The resolutionX and resolutionY is the resolution of each screen. #By comparing the relativeX and relativeY values of all the screens, you should be #able to easily allocate your primary screen and the location of other screens with respect to it. proc getMonitorsInfo {} { # > This will fail on non-windows package require registry set resultList {} set rootKey {HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Hardware Profiles\UnitedVideo\CONTROL\VIDEO} # get the list of monitor control set subkeys set keyList [registry keys $rootKey] # If there is only one->take it, otherwise look for current switch -exact -- [llength $keyList] { 0 { return -code error "No monitor information" } 1 { set keyCur [lindex $keyList 0] } default { # Search the active set (0 based index) if there are multiple set currentSet [registry get\ {HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\IDConfigDB}\ CurrentConfig] if {$currentSet < 0 || $currentSet >= [llength $keyList]} { return -code error "Wrong current set" } set keyCur [lindex $keyList $currentSet] } } append rootKey "\\" $keyCur # loop over the monitor subkeys foreach keyCur [registry keys $rootKey] { set monitorKey ${rootKey}\\$keyCur #if attach.todesktop != 1, then this screen is not used, ignore it if { ![string equal "1" [registry get $monitorKey Attach.ToDesktop]] } { continue } lappend resultList [list\ [registry get $monitorKey Attach.RelativeX]\ [registry get $monitorKey Attach.RelativeY]\ [registry get $monitorKey DefaultSettings.XResolution]\ [registry get $monitorKey DefaultSettings.YResolution]] } return $resultList } </verbatim> anonymous (claiming to be Remove the exec at all, and now the function result is in Decimal not Hex) added on 2015-09-14 09:51:59: #This Function return Info about all the Monitors connected in Case of Windows Platform #Function Input : None #Function Output : list of lists, each sub list contains info about one of the screens. #Example : #Assume you have two screens, the output will look like {{0 0 1680 1050} {-1280 0 1280 1024}} #The sub list contains in order relativeX , realtiveY , resolutionX , resolutionY for each screen #For primary screen relativeX and relativeY should be Zeros, and the relativeX and relativeY of the other screen is related to it. #In the above case the primary screen is on the right, thats why the relativeX of the second screen is negative. #The resolutionX and resolutionY is the resolution of each screen. #By comparing the relativeX and relativeY values of all the screens, you should be #able to easily allocate your primary screen and the location of other screens with respect to it. #Function was tested under Tcl8.4 under cygwin (Windows XP). #Function was tested under Tcl8.4 under Linux (RH4). #Function was tested under Tcl8.5 Active state (Windows 7). #Function was tested under Tcl8.5 under cygwin (Windows 7). package require registry proc getMonitorsInfo {} { global tcl_platform set resultList "" if {$tcl_platform(os) != "Linux"} { # get the number of monitors # search the registry to get the screens resolutions and find the main screen set tmp [registry keys HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Hardware\ Profiles\\UnitedVideo\\CONTROL\\VIDEO] #puts $tmp #loop to find all under \\VIDEO for {set it 0} {$it < [llength $tmp] } {incr it} { set my_query "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Hardware\ Profiles\\UnitedVideo\\CONTROL\\VIDEO\\" # get the line set for_tmp [lindex $tmp $it] # puts $for_tmp #make sure empty strings in the list are not used if { [string length $for_tmp] < 10 } { continue } #puts $for_tmp # concat the original query with the new part ,and execute it set my_query $my_query$for_tmp set temp [registry keys $my_query] # puts $temp #loop to find all under each sub key of \\VIDEO for {set i 0} {$i < [llength $temp]} {incr i} { # get each line set for_temp [lindex $temp $i ] #puts $for_temp # get the values of resolution x , resolution y , relative x , and attach.todektop # execute query with the new sub key set for_temp "\\$for_temp" set my_query1 $my_query$for_temp # grep on the values you want set att_x [registry get $my_query1 Attach.ToDesktop] #if attach.todesktop != 1, then this screen is not used, ignore it #else check if this is the main screen (relative x == 0) if {$att_x != 1} { break } set monitorList "" set rel_x [registry get $my_query1 Attach.RelativeX] lappend monitorList $rel_x set rel_y [registry get $my_query1 Attach.RelativeY] lappend monitorList $rel_y set res_x [registry get $my_query1 DefaultSettings.XResolution] lappend monitorList $res_x set res_y [registry get $my_query1 DefaultSettings.YResolution] lappend monitorList $res_y lappend resultList $monitorList } } return $resultList } else { puts "This Function is not supported in Linux" return $resultList } } set x [getMonitorsInfo] puts $x oehhar added on 2015-09-14 09:00:52: (text/x-fossil-wiki) Thank you for the revised version. The initial exec to query the registry should also be done by the registry package... Thank you, Harald anonymous (claiming to be New verison of the code reducing the number of "exec" calls) added on 2015-09-14 07:52:34: #This Function return Info about all the Monitors connected in Case of Windows Platform #Function Input : None #Function Output : list of lists, each sub list contains info about one of the screens. #Example : #Assume you have two screens, the output will look like {{0x0 0x0 0x690 0x41a} {0xfffffb00 0x0 0x500 0x400}} #The sub list contains in order relativeX , realtiveY , resolutionX , resolutionY for each screen #For primary screen relativeX and relativeY should be Zeros, and the relativeX and relativeY of the other screen is related to it. #In the above case the primary screen is on the right, thats why the relativeX of the second screen is negative. #The resolutionX and resolutionY is the resolution of each screen. # Note that i grep these values from the registry thats why they appear in Hex. #By comparing the relativeX and relativeY values of all the screens, you should be #able to easily allocate your primary screen and the location of other screens with respect to it. #Function was tested under Tcl8.4 under cygwin (Windows XP). #Function was tested under Tcl8.4 under Linux (RH4). #Function was tested under Tcl8.5 Active state (Windows 7). #Function was tested under Tcl8.5 under cygwin (Windows 7). proc getMonitorsInfo {} { global tcl_platform set resultList "" if {$tcl_platform(os) != "Linux"} { # get the number of monitors set monitors [exec reg query {HKLM\SYSTEM\CurrentControlSet\services\monitor\Enum }] set monitors [split $monitors "\n" ] set monitors [lsearch -inline $monitors *Count* ] set monitors [split $monitors " " ] set monitors [lindex $monitors end] # search the registry to get the screens resolutions and find the main screen set my_query "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Hardware\ Profiles\\UnitedVideo\\CONTROL\\VIDEO\\" set tmp [exec reg query $my_query] # split the result into lines to loop on them set tmp [split $tmp "\n"] #loop to find all under \\VIDEO for {set it 0} {$it < [llength $tmp] } {incr it} { set my_query "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Hardware\ Profiles\\UnitedVideo\\CONTROL\\VIDEO\\" # get the line set for_tmp [lindex $tmp $it] #puts $for_tmp # split the line by backslashes set for_tmp [split $for_tmp "\\"] # get the last item after splitting,will be like "{21B5061B-2F71-4D25-8BB5-5CD5A8833140}" set for_tmp [lindex $for_tmp end] #make sure empty strings in the list are not used if { [string length $for_tmp] < 10 } { continue } #puts $for_tmp # concat the original query with the new part ,and execute it set my_query $my_query$for_tmp set temp [exec reg query $my_query] # split again to loop on entries of the sub key line by line set temp [split $temp "\n"] #puts $temp #loop to find all under each sub key of \\VIDEO for {set i 0} {$i < [llength $temp]} {incr i} { # get each line set for_temp [lindex $temp $i ] #puts $for_temp # make sure empty strings in the list are not used if { [string length $for_temp] < 10 } { continue } # get the values of resolution x , resolution y , relative x , and attach.todektop # execute query with the new sub key set for_temp [exec reg query $for_temp] # grep on the values you want set att_x [split $for_temp "\n"] set att_x [lsearch -inline $att_x *Attach.ToDesktop*] set att_x [split $att_x " "] set att_x [lindex $att_x end] #if attach.todesktop != 1, then this screen is not used, ignore it #else check if this is the main screen (relative x == 0) if {$att_x != "0x01"} { break } set monitorList "" set rel_x [split $for_temp "\n"] set rel_x [lsearch -inline $rel_x *Attach.RelativeX*] set rel_x [split $rel_x " "] set rel_x [lindex $rel_x end] lappend monitorList $rel_x set rel_y [split $for_temp "\n"] set rel_y [lsearch -inline $rel_y *Attach.RelativeY*] set rel_y [split $rel_y " "] set rel_y [lindex $rel_y end] lappend monitorList $rel_y set res_x [split $for_temp "\n"] set res_x [lsearch -inline $res_x *DefaultSettings.XResolution*] set res_x [split $res_x " "] set res_x [lindex $res_x end] lappend monitorList $res_x set res_y [split $for_temp "\n"] set res_y [lsearch -inline $res_y *DefaultSettings.YResolution*] set res_y [split $res_y " "] set res_y [lindex $res_y end] lappend monitorList $res_y lappend resultList $monitorList } } return $resultList } else { puts "This Function is not supported in Linux" return $resultList } } set x [getMonitorsInfo] puts $x oehhar added on 2015-09-14 07:00:20: (text/x-fossil-wiki) Thank you for the proposal, looks promissing. It would we great to have this in Tk itself. I will look to integrate this in BWidget. Your function requires a bit rewrite to not use exec for performance. Thank you, Harald |