utils.tcl 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #!/usr/bin/env tclsh
  2. #
  3. # Copyright (c) 2015-2017 OpenIndex.de
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. # THE SOFTWARE.
  22. #
  23. namespace eval ::support::utils {
  24. # Center a window on screen.
  25. proc center_window {w {width 640} {height 480}} {
  26. set x [expr { ( [winfo vrootwidth $w] - $width ) / 2 }]
  27. set y [expr { ( [winfo vrootheight $w] - $height ) / 2 }]
  28. wm geometry $w ${width}x${height}+${x}+${y}
  29. }
  30. # Load an image from application data.
  31. proc load_image_file {name} {
  32. set path [file join $::support::DATA_DIR $name]
  33. if {[file exists $path]} {
  34. return [image create photo -format png -file $path]
  35. }
  36. puts "Can't find an image at '$path'!"
  37. return
  38. }
  39. # Get path to temporary directory.
  40. proc get_temp_dir {} {
  41. global env
  42. if {[info exists env(TMPDIR)]} {
  43. return $env(TMPDIR)
  44. }
  45. if {[info exists env(TEMPDIR)]} {
  46. return $env(TEMPDIR)
  47. }
  48. if {[info exists env(TEMP)]} {
  49. return $env(TEMP)
  50. }
  51. if {[info exists env(TMP)]} {
  52. return $env(TMP)
  53. }
  54. if {![is_windows] && [file writable /usr/tmp]} {
  55. return /usr/tmp
  56. }
  57. if {![is_windows] && [file writable /tmp]} {
  58. return /tmp
  59. }
  60. if {[info exists env(HOME)]} {
  61. return $env(HOME)
  62. }
  63. return $::support::APP_DIR
  64. }
  65. # Test, if the program runs on Mac OS X / Darwin.
  66. proc is_darwin {} {
  67. global tcl_platform
  68. set os [string tolower $tcl_platform(os)]
  69. return [string match "darwin*" $os]
  70. }
  71. # Test, if the program runs on Linux.
  72. proc is_linux {} {
  73. global tcl_platform
  74. set os [string tolower $tcl_platform(os)]
  75. return [string match "linux*" $os]
  76. }
  77. # Test, if the program runs on Windows.
  78. proc is_windows {} {
  79. global tcl_platform
  80. set os [string tolower $tcl_platform(os)]
  81. return [string match "windows*" $os]
  82. }
  83. # Get a list of child processes.
  84. proc process_children {processIds} {
  85. if {[is_windows]} {
  86. error "Windows is not supported."
  87. }
  88. set children [list]
  89. if {[llength $processIds] < 1} {
  90. return $children
  91. }
  92. foreach processId $processIds {
  93. if {[is_darwin]} {
  94. lappend children {*}[process_children_darwin $processId]
  95. } elseif {[is_linux]} {
  96. lappend children {*}[process_children_linux $processId]
  97. }
  98. }
  99. return $children
  100. }
  101. # Get a list of child processes on Mac OS X.
  102. proc process_children_darwin {processId} {
  103. if {[catch {exec bash << "ps -o ppid= -o pid= -A | awk '\$1 == $processId\{print \$2\}'"} result]} {
  104. puts "Can't fetch children of process '$processId'!"
  105. puts $::errorInfo
  106. return [list]
  107. }
  108. return [split [string trim $result] "\n"]
  109. }
  110. # Get a list of child processes on Linux.
  111. proc process_children_linux {processId} {
  112. if {[catch {exec bash << "ps -o ppid= -o pid= -A | awk '\$1 == $processId\{print \$2\}'"} result]} {
  113. puts "Can't fetch children of process '$processId'!"
  114. puts $::errorInfo
  115. return [list]
  116. }
  117. return [split [string trim $result] "\n"]
  118. }
  119. # Test, if a certain process is running.
  120. proc process_is_running {processId} {
  121. if {[is_darwin] && [process_is_running_darwin $processId]} {
  122. return 1
  123. }
  124. if {[is_linux] && [process_is_running_linux $processId]} {
  125. return 1
  126. }
  127. if {[is_windows] && [process_is_running_windows $processId]} {
  128. return 1
  129. }
  130. return 0
  131. }
  132. # Test, if a certain process is running on Mac OS X.
  133. proc process_is_running_darwin {processId} {
  134. if {[catch {exec bash << "ps -p $processId -o state="} result]} {
  135. puts "Can't fetch process '$processId'!"
  136. puts $::errorInfo
  137. return 0
  138. }
  139. set state [lindex [split [string trim $result] "\n"] end]
  140. puts "Checking process $processId: $state"
  141. set s [string index $state 0]
  142. if {$s=="I" || $s=="R" || $s=="S" || $s=="U"} {
  143. return 1
  144. }
  145. return 0
  146. }
  147. # Test, if a certain process is running on Linux.
  148. proc process_is_running_linux {processId} {
  149. if {[catch {exec bash << "ps -p $processId -o state="} result]} {
  150. puts "Can't fetch process '$processId'!"
  151. puts $::errorInfo
  152. return 0
  153. }
  154. set state [lindex [split [string trim $result] "\n"] end]
  155. puts "Checking process $processId: $state"
  156. set s [string index $state 0]
  157. if {$s=="D" || $s=="R" || $s=="S" || $s=="W"} {
  158. return 1
  159. }
  160. return 0
  161. }
  162. # Test, if a certain process is running on Windows.
  163. proc process_is_running_windows {processId} {
  164. if {[catch {exec tasklist "/FI" "PID eq $processId" "/FO" "CSV" "/NH"} result]} {
  165. puts "Can't fetch process '$processId'!"
  166. puts $::errorInfo
  167. return 0
  168. }
  169. set result [string trim $result]
  170. puts "Checking process $processId: $result"
  171. if {[string first "\"$processId\"" $result] > -1} {
  172. return 1
  173. }
  174. return 0
  175. }
  176. # Stop a currently running process.
  177. proc process_kill {processId} {
  178. if {[is_darwin]} {
  179. return [process_kill_darwin $processId]
  180. }
  181. if {[is_linux]} {
  182. return [process_kill_linux $processId]
  183. }
  184. if {[is_windows]} {
  185. return [process_kill_windows $processId]
  186. }
  187. return 0
  188. }
  189. # Stop a currently running process on Mac OS X.
  190. proc process_kill_darwin {processId} {
  191. puts "Killing process '$processId'."
  192. if {[catch {exec bash << "kill $processId"} result]} {
  193. puts "Can't kill process '$processId'!"
  194. puts $::errorInfo
  195. return 0
  196. }
  197. return 1
  198. }
  199. # Stop a currently running process on Linux.
  200. proc process_kill_linux {processId} {
  201. puts "Killing process '$processId'."
  202. if {[catch {exec bash << "kill $processId"} result]} {
  203. puts "Can't kill process '$processId'!"
  204. puts $::errorInfo
  205. return 0
  206. }
  207. return 1
  208. }
  209. # Stop a currently running process on Windows.
  210. proc process_kill_windows {processId} {
  211. error "Not implemented yet!"
  212. }
  213. # Make a modal window.
  214. proc modal_init {id} {
  215. wm transient $id $::support::ApplicationWindow::ID
  216. raise $id
  217. focus $id
  218. grab $id
  219. }
  220. # Release a modal window.
  221. proc modal_release {id} {
  222. grab release $id
  223. wm withdraw $id
  224. update
  225. destroy $id
  226. }
  227. # Open a website in the web browser.
  228. proc open_browser {url} {
  229. # open is the OS X equivalent to xdg-open on Linux, start is used on Windows
  230. set commands {xdg-open open start}
  231. foreach browser $commands {
  232. if {$browser eq "start"} {
  233. set command [list {*}[auto_execok start] {}]
  234. } else {
  235. set command [auto_execok $browser]
  236. }
  237. if {[string length $command]} {
  238. break
  239. }
  240. }
  241. if {[string length $command] == 0} {
  242. return -code error "couldn't find browser"
  243. }
  244. if {[catch {exec {*}$command $url &} error]} {
  245. return -code error "couldn't execute '$command': $error"
  246. }
  247. }
  248. # Get the path of a certain application.
  249. proc get_application {name} {
  250. if {[is_darwin] || [is_linux]} {
  251. return [exec which $name]
  252. }
  253. if {[is_windows]} {
  254. return [exec where $name]
  255. }
  256. error "Can't get application path for this operating system!"
  257. }
  258. # Get a recursive list of files in a directory.
  259. proc get_files {{dir .}} {
  260. set res {}
  261. foreach i [lsort [glob -nocomplain -dir $dir *]] {
  262. if {[file type $i] eq {directory}} {
  263. eval lappend res [get_files $i]
  264. } else {
  265. lappend res $i
  266. }
  267. }
  268. set res
  269. }
  270. }