PageRenderTime 50ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/Coccinella-0.96.20Src/lib/WindowsUtils.tcl

#
TCL | 415 lines | 273 code | 71 blank | 71 comment | 39 complexity | 6a67347f91483115603463659301928c MD5 | raw file
Possible License(s): GPL-3.0
  1. # WindowsUtils.tcl ---
  2. #
  3. # This file is part of The Coccinella application. It implements things
  4. # that are windows only, like a glue to win only packages.
  5. #
  6. # Copyright (c) 2002-2007 Mats Bengtsson
  7. #
  8. # This program is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation, either version 3 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. #
  21. # See: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/programmersguide/shell_adv/registeringapps.asp
  22. #
  23. # $Id: WindowsUtils.tcl,v 1.16 2007-09-14 08:11:47 matben Exp $
  24. package require registry
  25. package provide WindowsUtils 1.0
  26. namespace eval ::Windows:: {
  27. variable ProgramFiles
  28. if {[info exists ::env(ProgramFiles)]} {
  29. set ProgramFiles $::env(ProgramFiles)
  30. } elseif {[info exists ::env(PROGRAMFILES)]} {
  31. set ProgramFiles $::env(PROGRAMFILES)
  32. }
  33. }
  34. proc ::Windows::OpenURI {uri} {
  35. variable ProgramFiles
  36. # uri MUST have the form "protocol:..."
  37. if {![regexp {^([^:]+):.+} $uri - name]} {
  38. return
  39. }
  40. set key [format {HKEY_CLASSES_ROOT\%s\shell\open\command} $name]
  41. if {[catch {registry get $key {}} appCmd]} {
  42. return
  43. }
  44. if {[info exists ProgramFiles]} {
  45. regsub -nocase "%programfiles%" $appCmd $ProgramFiles appCmd
  46. }
  47. regsub -all {\\} $appCmd {\\\\} appCmd
  48. # Outlook uses a mailurl:%1 which I don't know how to interpret.
  49. set appCmd [string map [list {%1} $uri] $appCmd]
  50. if {[catch {
  51. eval exec $appCmd &
  52. } err]} {
  53. tk_messageBox -icon error -title [mc "Error"] -message $err
  54. }
  55. }
  56. # Slight rewrite of Chris Nelson's Wiki contribution: http://wiki.tcl.tk/557
  57. proc ::Windows::OpenUrl {url} {
  58. variable ProgramFiles
  59. set ext .html
  60. # Get the application key for HTML files
  61. set appKey [registry get [format {HKEY_CLASSES_ROOT\%s} $ext] {}]
  62. set key [format {HKEY_CLASSES_ROOT\%s\shell\open\command} $appKey]
  63. # Get the command for opening HTML files
  64. if {[catch {registry get $key {}} appCmd]} {
  65. # Try a different key.
  66. set key [format {HKEY_CLASSES_ROOT\%s\shell\opennew\command} $appKey]
  67. if {[catch {
  68. set appCmd [registry get $key {}]
  69. } msg]} {
  70. return -code error $msg
  71. }
  72. }
  73. # Double up the backslashes for eval (below)
  74. regsub -all {\\} $appCmd {\\\\} appCmd
  75. if {[info exists ProgramFiles]} {
  76. regsub -nocase "%programfiles%" $appCmd $ProgramFiles appCmd
  77. }
  78. # Substitute the url name into the command for %1
  79. # Not always needed (opennew).
  80. set havePercent [string match {*"%1"*} $appCmd]
  81. set finCmd [string map [list {%1} $url] $appCmd]
  82. # Invoke the command.
  83. # It seems that if there is a "%1" we shall use that for url else just append?
  84. if {[catch {
  85. if {$havePercent} {
  86. eval exec $finCmd &
  87. } else {
  88. # This wont work with Firefox.
  89. eval exec $finCmd [list $url] &
  90. }
  91. } err]} {
  92. tk_messageBox -icon error -title [mc "Error"] -message $err
  93. }
  94. }
  95. # ::Windows::OpenFileFromSuffix --
  96. #
  97. # Uses the registry to try to find an application for a file using
  98. # its suffix.
  99. # If the path starts with "file://" we assume it is already uri encoded.
  100. proc ::Windows::OpenFileFromSuffix {path} {
  101. variable ProgramFiles
  102. set ext [file extension $path]
  103. # Get the application key for .ext files
  104. set appKey [registry get HKEY_CLASSES_ROOT\\$ext {}]
  105. set key [format {HKEY_CLASSES_ROOT\%s\shell\open\command} $appKey]
  106. # Get the command for opening $suff files
  107. if {[catch {
  108. set appCmd [registry get $key {}]
  109. } msg]} {
  110. return -code error $msg
  111. }
  112. # Double up the backslashes for eval (below)
  113. regsub -all {\\} $appCmd {\\\\} appCmd
  114. regsub {%1} $appCmd $path appCmd
  115. if {[info exists ProgramFiles]} {
  116. regsub -nocase "%programfiles%" $appCmd $ProgramFiles appCmd
  117. }
  118. # URI encode if necessary. We fixed this using [list $path] instead!
  119. if {0 && ![regexp {^file://.*} $path]} {
  120. #set path "file://[uriencode::quotepath $path]"
  121. }
  122. # Invoke the command
  123. if {[catch {
  124. eval exec $appCmd [list $path] &
  125. } err]} {
  126. tk_messageBox -icon error -title [mc "Error"] -message $err
  127. }
  128. }
  129. proc ::Windows::CanOpenFileWithSuffix {path} {
  130. # Look for the application under HKEY_CLASSES_ROOT
  131. set root HKEY_CLASSES_ROOT
  132. set suff [file extension $path]
  133. # Get the application key for .suff files
  134. if {[catch {registry get $root\\$suff ""} appKey]} {
  135. return 0
  136. }
  137. # Perhaps there can be other commands than 'open'.
  138. if {[catch {
  139. set appCmd [registry get $root\\$appKey\\shell\\open\\command ""]
  140. } msg]} {
  141. return 0
  142. }
  143. return 1
  144. }
  145. #--- Printer Utilities ---------------------------------------------------------
  146. #
  147. # Be sure that the 'printer' and 'gdi' packages are there.
  148. namespace eval ::Windows::Printer:: {
  149. }
  150. proc ::Windows::Printer::PageSetup { } {
  151. set ans [printer dialog page_setup]
  152. return $ans
  153. }
  154. proc ::Windows::Printer::Print {w args} {
  155. eval {printer::print_widget $w -name "Coccinella"} $args
  156. }
  157. proc ::Windows::Printer::DoPrintText {w} {
  158. variable p
  159. set ans [printer dialog select]
  160. if {[lindex $ans 1] != 1} {
  161. return
  162. }
  163. set hdc [lindex $ans 0]
  164. # For the time being we use a crude method of printing text.
  165. set str [::Text::TransformToPureText $w]
  166. printer::print_page_data $str
  167. if {0} {
  168. printer::page_args p
  169. printer job start
  170. printer page start
  171. ::Windows::Printer::PrintText $w $hdc p
  172. printer page end
  173. printer job end
  174. }
  175. }
  176. # Sketch...
  177. #
  178. # This should print images as well...
  179. proc ::Windows::Printer::PrintText {w hdc pName} {
  180. variable state
  181. variable tagConfig
  182. variable facx
  183. variable facy
  184. variable dcx
  185. variable dcy
  186. variable lm
  187. variable tm
  188. variable pw
  189. variable pl
  190. variable pix2dcx
  191. variable pix2dcy
  192. variable iLine 0
  193. upvar 1 $pName p
  194. if {[winfo class $w] ne "Text"} {
  195. error "::Windows::Printer::PrintText for text widgets only"
  196. }
  197. # Common scale factors etc.
  198. set facx [expr {$p(resx)/1000.0}]
  199. set facy [expr {$p(resy)/1000.0}]
  200. set lm [expr {round($p(lm) * $facx)}]
  201. set tm [expr {round($p(tm) * $facy)}]
  202. set pw [expr {round(($p(pw) - $p(lm) - $p(rm)) * $facx)}]
  203. set pl [expr {round(($p(pl) - $p(tm) - $p(bm)) * $facy)}]
  204. if {$::tcl_platform(platform) eq "windows"} {
  205. set ppiScreen 94
  206. } else {
  207. set ppiScreen 72
  208. }
  209. set pix2dcx [expr {double($p(resx))/$ppiScreen}]
  210. set pix2dcy [expr {double($p(resy))/$ppiScreen}]
  211. # Init state vars.
  212. set attrList {-background -borderwidth -font -foreground \
  213. -lmargin1 -lmargin2 -rmargin -spacing1 -spacing2 -spacing3 \
  214. -tabs}
  215. unset -nocomplain state
  216. foreach key $attrList {
  217. set state($key) {}
  218. }
  219. foreach {key a b c value} [$w configure] {
  220. if {[info exists state($key)]} {
  221. set state($key) $value
  222. }
  223. }
  224. # Get all tag configs.
  225. foreach tag [$w tag names] {
  226. set tagConfig($tag) [$w tag configure $tag]
  227. }
  228. # Get all gdi font metrics.
  229. set defFont [$w cget -font]
  230. gdi characters $hdc -font $defFont -array fm
  231. regsub " " $defFont "" fkey
  232. array set fmArr${fkey} [array get fm]
  233. foreach tag [array names tagConfig] {
  234. set ind [lsearch $tagConfig($tag) "-font"]
  235. if {$ind >= 0} {
  236. set font [lindex $tagConfig($tag) [expr {$ind+1}]]
  237. regsub " " $font "" fkey
  238. if {![info exists fmArr${fkey}]} {
  239. variable fmArr${fkey}
  240. gdi characters $hdc -font $font -array fm
  241. array set fmArr${fkey} [array get fm]
  242. }
  243. }
  244. }
  245. # Start position.
  246. set dcx $tm
  247. set dcy $tm
  248. # And finally...
  249. foreach {key value index} [$w dump 1.0 end] {
  250. ::Windows::Printer::TextDumpCallback $hdc $key $value $index
  251. }
  252. # Cleanup
  253. unset -nocomplain facx facy
  254. }
  255. proc ::Windows::Printer::TextDumpCallback {hdc key value index} {
  256. variable state
  257. variable iLine
  258. variable dcx
  259. variable dcy
  260. variable facx
  261. variable facy
  262. variable lm
  263. variable tm
  264. variable pw
  265. variable pl
  266. variable tagConfig
  267. variable pix2dcx
  268. variable pix2dcy
  269. puts "$hdc, key=$key, value=$value, index=$index"
  270. switch -- $key {
  271. tagon {
  272. foreach {tkey tval} $tagConfig($value) {
  273. set state($tkey) [linsert $state($tkey) 0 $tval]
  274. }
  275. }
  276. tagoff {
  277. foreach {tkey tval} $tagConfig($value) {
  278. set state($tkey) [lreplace $state($tkey) 0 0]
  279. }
  280. }
  281. text {
  282. set font [lindex $state(-font) 0]
  283. regsub " " $font "" fkey
  284. array set fm [array get fmArr${fkey}]
  285. set fg [lindex $state(-foreground) 0]
  286. set bg [lindex $state(-background) 0]
  287. set len 0
  288. set totlen [string length $value]
  289. set dcwidth 0
  290. if {$bg eq "white"} {
  291. set backfill {}
  292. } else {
  293. set backfill [list -backfill $bg]
  294. }
  295. while {$len < $totlen} {
  296. set str [string range $value $len end]
  297. # Handle text paragraph by paragraph, separated by \n.
  298. # split \n to list ??
  299. set end [string first "\n" $str]
  300. if {$str eq ""} {
  301. set str " "
  302. }
  303. set maxlen [string length $str]
  304. for {set i 0} {($i < $maxlen) && ($dcwidth < $pw)} {incr i} {
  305. incr dcwidth $fm([string index $str $i])
  306. }
  307. set endi $i
  308. set starti $i
  309. # Keep track of max y for each line so we know to offset next.
  310. set dcyMax 0
  311. # If not the complete string used up. Break on a word.
  312. if {$i < $maxlen} {
  313. set endi [expr {[string wordstart $str $endi] - 1}]
  314. set starti [expr {$endi + 1}]
  315. # No word boundary found. Cut.
  316. if {$endi <= 1} {
  317. set endi $i
  318. set starti $i
  319. }
  320. }
  321. set res [eval {gdi text $hdc $dcx $dcy -anchor nw -justify left \
  322. -text $str -font $font -fill $fg} $backfill]
  323. incr len [lindex $res 0]
  324. incr dcx $dcwidth
  325. if {$newline} {
  326. incr dcy $dcyMax
  327. set dcyMax 0
  328. } else {
  329. set y [lindex $res 1]
  330. set dcyMax [expr {$y > $dcyMax ? $y : $dcyMax}]
  331. }
  332. }
  333. }
  334. image {
  335. # value is image name?
  336. set dcImw [expr {round( $facx * [image width $value] )}]
  337. set dcImh [expr {round( $facy * [image height $value] )}]
  338. # Fix anchor later. Wrong position.
  339. gdi rectangle $hdc $dcx $dcy [expr {$dcx + $dcImw}] \
  340. [expr {$dcy - $dcImh}]
  341. }
  342. }
  343. }
  344. #-------------------------------------------------------------------------------