scaling.tcl 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. # scaling.tcl --
  2. #
  3. # Contains scaling-related utility procedures.
  4. #
  5. # Copyright © 2022 Csaba Nemethi <csaba.nemethi@t-online.de>
  6. # ::tk::ScalingPct --
  7. #
  8. # Returns the display's "scaling percentage" (the display resolution expressed
  9. # as a percentage of 96dpi), rounded to the nearest multiple of 25 that is at
  10. # least 100.
  11. #
  12. # On X11 systems (but not on SDL systems that claim to be X11), the first call
  13. # of the command also sets [tk scaling] and ::tk::fontScalingFactor to values
  14. # extracted from the X11 configuration.
  15. #
  16. # The command is called during Tk initialization, from icons.tcl, when the
  17. # latter is sourced by tk.tcl.
  18. proc ::tk::ScalingPct {} {
  19. set pct [expr {[tk scaling] * 75}]
  20. variable doneScalingInitX11
  21. if {![info exists doneScalingInitX11]} {
  22. set pct [::tk::ScalingInitX11 $pct]
  23. set doneScalingInitX11 1
  24. }
  25. #
  26. # Save the value of pct rounded to the nearest multiple
  27. # of 25 that is at least 100, in the variable scalingPct.
  28. # See "man n tk_scalingPct" for use of ::tk::scalingPct.
  29. #
  30. variable scalingPct
  31. for {set scalingPct 100} {1} {incr scalingPct 25} {
  32. if {$pct < $scalingPct + 12.5} {
  33. break
  34. }
  35. }
  36. return $scalingPct
  37. }
  38. proc ::tk::ScalingInitX11 {pct} {
  39. set onX11 [expr {[tk windowingsystem] eq "x11"}]
  40. set usingSDL [expr {[info exists ::tk::sdltk] && $::tk::sdltk}]
  41. if {$onX11 && !$usingSDL} {
  42. set origPct $pct
  43. #
  44. # Try to get the window scaling factor (1 or 2), partly
  45. # based on https://wiki.archlinux.org/title/HiDPI
  46. #
  47. set winScalingFactor 1
  48. variable fontScalingFactor 1 ;# needed in the file ttk/fonts
  49. if {[catch {exec ps -e | grep xfce4-session}] == 0} { ;# Xfce
  50. if {[catch {exec xfconf-query -c xsettings \
  51. -p /Gdk/WindowScalingFactor} result] == 0} {
  52. set winScalingFactor $result
  53. if {$winScalingFactor >= 2} {
  54. set fontScalingFactor 2
  55. }
  56. }
  57. #
  58. # The DPI value can be set in the "Fonts" tab of the "Appearance"
  59. # dialog or (on Linux Lite 5+) via the "HiDPI Settings" dialog.
  60. #
  61. } elseif {[catch {exec ps -e | grep mate-session}] == 0} { ;# MATE
  62. if {[catch {exec gsettings get org.mate.interface \
  63. window-scaling-factor} result] == 0} {
  64. if {$result == 0} { ;# means: "Auto-detect"
  65. #
  66. # Try to get winScalingFactor from the cursor size
  67. #
  68. if {[catch {exec xrdb -query | grep Xcursor.size} result]
  69. == 0 &&
  70. [catch {exec gsettings get org.mate.peripherals-mouse \
  71. cursor-size} defCursorSize] == 0} {
  72. set cursorSize [lindex $result 1]
  73. set winScalingFactor \
  74. [expr {($cursorSize + $defCursorSize - 1) /
  75. $defCursorSize}]
  76. }
  77. } else {
  78. set winScalingFactor $result
  79. }
  80. }
  81. #
  82. # The DPI value can be set via the "Font Rendering Details"
  83. # dialog, which can be opened using the "Details..." button
  84. # in the "Fonts" tab of the "Appearance Preferences" dialog.
  85. #
  86. } elseif {[catch {exec ps -e | grep gnome-session}] == 0 &&
  87. [catch {exec gsettings get \
  88. org.gnome.settings-daemon.plugins.xsettings overrides} \
  89. result] == 0 &&
  90. [set idx \
  91. [string first "'Gdk/WindowScalingFactor'" $result]] >= 0} {
  92. scan [string range $result $idx end] "%*s <%d>" winScalingFactor
  93. }
  94. #
  95. # Get the scaling percentage
  96. #
  97. if {$winScalingFactor >= 2} {
  98. set pct 200
  99. } elseif {[catch {exec xrdb -query | grep Xft.dpi} result] == 0} {
  100. #
  101. # Derive the value of pct from that of the font DPI
  102. #
  103. set dpi [lindex $result 1]
  104. set pct [expr {100.0 * $dpi / 96}]
  105. } elseif {[catch {exec ps -e | grep gnome-session}] == 0 &&
  106. ![info exists ::env(WAYLAND_DISPLAY)] &&
  107. [catch {exec xrandr | grep " connected"} result] == 0 &&
  108. [catch {open $::env(HOME)/.config/monitors.xml} chan] == 0} {
  109. #
  110. # Update pct by scanning the file ~/.config/monitors.xml
  111. #
  112. ScanMonitorsFile $result $chan pct
  113. }
  114. if {($pct != 100) && ($pct != $origPct) && (![interp issafe])} {
  115. #
  116. # Set Tk's scaling factor according to $pct
  117. #
  118. tk scaling [expr {$pct / 75.0}]
  119. }
  120. }
  121. return $pct
  122. }
  123. # ::tk::ScaleNum --
  124. #
  125. # Scales an integer according to the display's current scaling percentage.
  126. #
  127. # Arguments:
  128. # num - An integer.
  129. proc ::tk::ScaleNum num {
  130. return [expr {round($num * [tk scaling] * 0.75)}]
  131. }
  132. # ::tk::FontScalingFactor --
  133. #
  134. # Accessor command for variable ::tk::fontScalingFactor.
  135. proc ::tk::FontScalingFactor {} {
  136. variable fontScalingFactor
  137. if {[info exists fontScalingFactor]} {
  138. return $fontScalingFactor
  139. } else {
  140. return 1
  141. }
  142. }
  143. # ::tk::ScanMonitorsFile --
  144. #
  145. # Updates the scaling percentage by scanning the file ~/.config/monitors.xml.
  146. #
  147. # Arguments:
  148. # xrandrResult - The output of 'xrandr | grep " connected"'.
  149. # chan - Returned from 'open ~/.config/monitors.xml'.
  150. # pctName - The name of a variable containing the scaling percentage.
  151. proc ::tk::ScanMonitorsFile {xrandrResult chan pctName} {
  152. upvar $pctName pct
  153. #
  154. # Get the list of connected outputs reported by xrandr
  155. #
  156. set outputList {}
  157. foreach line [split $xrandrResult "\n"] {
  158. set idx [string first " " $line]
  159. set output [string range $line 0 [incr idx -1]]
  160. lappend outputList $output
  161. }
  162. set outputList [lsort $outputList]
  163. #
  164. # Get the content of the file ~/.config/monitors.xml
  165. #
  166. set str [read $chan]
  167. close $chan
  168. #
  169. # Run over the file's "configuration" sections
  170. #
  171. set idx 0
  172. while {[set idx2 [string first "<configuration>" $str $idx]] >= 0} {
  173. set idx2 [string first ">" $str $idx2]
  174. set idx [string first "</configuration>" $str $idx2]
  175. set config [string range $str [incr idx2] [incr idx -1]]
  176. #
  177. # Get the list of connectors within this configuration
  178. #
  179. set connectorList {}
  180. foreach {dummy connector} [regexp -all -inline \
  181. {<connector>([^<]+)</connector>} $config] {
  182. lappend connectorList $connector
  183. }
  184. set connectorList [lsort $connectorList]
  185. #
  186. # If $outputList and $connectorList are identical then set the
  187. # variable pct to 100, 200, 300, 400, or 500, depending on the
  188. # max. scaling within this configuration, and exit the loop
  189. #
  190. if {$outputList eq $connectorList} {
  191. set maxScaling 1.0
  192. foreach {dummy scaling} [regexp -all -inline \
  193. {<scale>([^<]+)</scale>} $config] {
  194. if {$scaling > $maxScaling} {
  195. set maxScaling $scaling
  196. }
  197. }
  198. foreach n {4 3 2 1 0} {
  199. if {$maxScaling > $n} {
  200. set pct [expr {($n + 1) * 100}]
  201. break
  202. }
  203. }
  204. break
  205. }
  206. }
  207. }