print.tcl 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343
  1. # print.tcl --
  2. # This file defines the 'tk print' command for printing of the canvas
  3. # widget and text on X11, Windows, and macOS. It implements an abstraction
  4. # layer that presents a consistent API across the three platforms.
  5. # Copyright © 2009 Michael I. Schwartz.
  6. # Copyright © 2021 Kevin Walzer/WordTech Communications LLC.
  7. # Copyright © 2021 Harald Oehlmann, Elmicron GmbH
  8. # Copyright © 2022 Emiliano Gavilan
  9. #
  10. # See the file "license.terms" for information on usage and redistribution
  11. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12. namespace eval ::tk::print {
  13. namespace import -force ::tk::msgcat::*
  14. # makeTempFile:
  15. # Create a temporary file and populate its contents
  16. # Arguments:
  17. # filename - base of the name of the file to create
  18. # contents - what to put in the file; defaults to empty
  19. # Returns:
  20. # Full filename for created file
  21. #
  22. proc makeTempFile {filename {contents ""}} {
  23. set dumpfile [file join /tmp rawprint.txt]
  24. set tmpfile [file join /tmp $filename]
  25. set f [open $dumpfile w]
  26. try {
  27. puts -nonewline $f $contents
  28. } finally {
  29. close $f
  30. if {[file extension $filename] == ".ps"} {
  31. #don't apply formatting to PostScript
  32. file rename -force $dumpfile $tmpfile
  33. } else {
  34. #Make text fixed width for improved printed output
  35. exec fmt -w 75 $dumpfile > $tmpfile
  36. }
  37. return $tmpfile
  38. }
  39. }
  40. if {[tk windowingsystem] eq "win32"} {
  41. variable printer_name
  42. variable copies
  43. variable dpi_x
  44. variable dpi_y
  45. variable paper_width
  46. variable paper_height
  47. variable margin_left
  48. variable margin_top
  49. variable printargs
  50. array set printargs {}
  51. # Multiple utility procedures for printing text based on the
  52. # C printer primitives.
  53. # _set_dc:
  54. # Select printer and set device context and other parameters
  55. # for print job.
  56. #
  57. proc _set_dc {} {
  58. variable printargs
  59. variable printer_name
  60. variable paper_width
  61. variable paper_height
  62. variable dpi_x
  63. variable dpi_y
  64. variable copies
  65. #First, we select the printer.
  66. _selectprinter
  67. #Next, set values. Some are taken from the printer,
  68. #some are sane defaults.
  69. if {[info exists printer_name] && $printer_name ne ""} {
  70. set printargs(hDC) $printer_name
  71. set printargs(pw) $paper_width
  72. set printargs(pl) $paper_height
  73. set printargs(lm) 1000
  74. set printargs(tm) 1000
  75. set printargs(rm) 1000
  76. set printargs(bm) 1000
  77. set printargs(resx) $dpi_x
  78. set printargs(resy) $dpi_y
  79. set printargs(copies) $copies
  80. set printargs(resolution) [list $dpi_x $dpi_y]
  81. }
  82. }
  83. # _print_data
  84. # This function prints multiple-page files, using a line-oriented
  85. # function, taking advantage of knowing the character widths.
  86. # Arguments:
  87. # data - Text data for printing
  88. # breaklines - If non-zero, keep newlines in the string as
  89. # newlines in the output.
  90. # font - Font for printing
  91. proc _print_data {data {breaklines 1} {font ""}} {
  92. variable printargs
  93. variable printer_name
  94. _set_dc
  95. if {![info exists printer_name]} {
  96. return
  97. }
  98. if {$font eq ""} {
  99. _gdi characters $printargs(hDC) -array printcharwid
  100. } else {
  101. _gdi characters $printargs(hDC) -font $font -array printcharwid
  102. }
  103. set pagewid [expr {($printargs(pw) - $printargs(rm) ) / 1000 * $printargs(resx)}]
  104. set pagehgt [expr {($printargs(pl) - $printargs(bm) ) / 1000 * $printargs(resy)}]
  105. set totallen [string length $data]
  106. set curlen 0
  107. set curhgt [expr {$printargs(tm) * $printargs(resy) / 1000}]
  108. _opendoc
  109. _openpage
  110. while {$curlen < $totallen} {
  111. set linestring [string range $data $curlen end]
  112. if {$breaklines} {
  113. set endind [string first "\n" $linestring]
  114. if {$endind >= 0} {
  115. set linestring [string range $linestring 0 $endind]
  116. # handle blank lines....
  117. if {$linestring eq ""} {
  118. set linestring " "
  119. }
  120. }
  121. }
  122. set result [_print_page_nextline $linestring \
  123. printcharwid printargs $curhgt $font]
  124. incr curlen [lindex $result 0]
  125. incr curhgt [lindex $result 1]
  126. if {$curhgt + [lindex $result 1] > $pagehgt} {
  127. _closepage
  128. _openpage
  129. set curhgt [expr {$printargs(tm) * $printargs(resy) / 1000}]
  130. }
  131. }
  132. _closepage
  133. _closedoc
  134. }
  135. # _print_file
  136. # This function prints multiple-page files
  137. # It will either break lines or just let them run over the
  138. # margins (and thus truncate).
  139. # The font argument is JUST the font name, not any additional
  140. # arguments.
  141. # Arguments:
  142. # filename - File to open for printing
  143. # breaklines - 1 to break lines as done on input, 0 to ignore newlines
  144. # font - Optional arguments to supply to the text command
  145. proc _print_file {filename {breaklines 1} {font ""}} {
  146. set fn [open $filename r]
  147. set data [read $fn]
  148. close $fn
  149. _print_data $data $breaklines $font
  150. }
  151. # _print_page_nextline
  152. # Returns the pair "chars y"
  153. # where chars is the number of characters printed on the line
  154. # and y is the height of the line printed
  155. # Arguments:
  156. # string - Data to print
  157. # pdata - Array of values for printer characteristics
  158. # cdata - Array of values for character widths
  159. # y - Y value to begin printing at
  160. # font - if non-empty specifies a font to draw the line in
  161. proc _print_page_nextline {string carray parray y font} {
  162. upvar #0 $carray charwidths
  163. upvar #0 $parray printargs
  164. variable printargs
  165. set endindex 0
  166. set totwidth 0
  167. set maxwidth [expr {
  168. (($printargs(pw) - $printargs(rm)) / 1000) * $printargs(resx)
  169. }]
  170. set maxstring [string length $string]
  171. set lm [expr {$printargs(lm) * $printargs(resx) / 1000}]
  172. for {set i 0} {($i < $maxstring) && ($totwidth < $maxwidth)} {incr i} {
  173. incr totwidth $charwidths([string index $string $i])
  174. # set width($i) $totwidth
  175. }
  176. set endindex $i
  177. set startindex $endindex
  178. if {$i < $maxstring} {
  179. # In this case, the whole data string is not used up, and we
  180. # wish to break on a word. Since we have all the partial
  181. # widths calculated, this should be easy.
  182. set endindex [expr {[string wordstart $string $endindex] - 1}]
  183. set startindex [expr {$endindex + 1}]
  184. # If the line is just too long (no word breaks), print as much
  185. # as you can....
  186. if {$endindex <= 1} {
  187. set endindex $i
  188. set startindex $i
  189. }
  190. }
  191. set txt [string trim [string range $string 0 $endindex] "\r\n"]
  192. if {$font ne ""} {
  193. set result [_gdi text $printargs(hDC) $lm $y \
  194. -anchor nw -justify left \
  195. -text $txt -font $font]
  196. } else {
  197. set result [_gdi text $printargs(hDC) $lm $y \
  198. -anchor nw -justify left -text $txt]
  199. }
  200. return "$startindex $result"
  201. }
  202. # These procedures read in the canvas widget, and write all of
  203. # its contents out to the Windows printer.
  204. variable option
  205. variable vtgPrint
  206. proc _init_print_canvas {} {
  207. variable option
  208. variable vtgPrint
  209. variable printargs
  210. set vtgPrint(printer.bg) white
  211. }
  212. proc _is_win {} {
  213. variable printargs
  214. return [info exist tk_patchLevel]
  215. }
  216. # _print_widget
  217. # Main procedure for printing a widget. Currently supports
  218. # canvas widgets. Handles opening and closing of printer.
  219. # Arguments:
  220. # wid - The widget to be printed.
  221. # printer - Flag whether to use the default printer.
  222. # name - App name to pass to printer.
  223. proc _print_widget {wid {printer default} {name "Tk Print Output"}} {
  224. variable printargs
  225. variable printer_name
  226. _set_dc
  227. if {![info exists printer_name]} {
  228. return
  229. }
  230. _opendoc
  231. _openpage
  232. # Here is where any scaling/gdi mapping should take place
  233. # For now, scale so the dimensions of the window are sized to the
  234. # width of the page. Scale evenly.
  235. # For normal windows, this may be fine--but for a canvas, one
  236. # wants the canvas dimensions, and not the WINDOW dimensions.
  237. if {[winfo class $wid] eq "Canvas"} {
  238. set sc [$wid cget -scrollregion]
  239. # if there is no scrollregion, use width and height.
  240. if {$sc eq ""} {
  241. set window_x [$wid cget -width]
  242. set window_y [$wid cget -height]
  243. } else {
  244. set window_x [lindex $sc 2]
  245. set window_y [lindex $sc 3]
  246. }
  247. } else {
  248. set window_x [winfo width $wid]
  249. set window_y [winfo height $wid]
  250. }
  251. set printer_x [expr {
  252. ( $printargs(pw) - $printargs(lm) - $printargs(rm) ) *
  253. $printargs(resx) / 1000.0
  254. }]
  255. set printer_y [expr {
  256. ( $printargs(pl) - $printargs(tm) - $printargs(bm) ) *
  257. $printargs(resy) / 1000.0
  258. }]
  259. set factor_x [expr {$window_x / $printer_x}]
  260. set factor_y [expr {$window_y / $printer_y}]
  261. if {$factor_x < $factor_y} {
  262. set lo $window_y
  263. set ph $printer_y
  264. } else {
  265. set lo $window_x
  266. set ph $printer_x
  267. }
  268. _gdi map $printargs(hDC) -logical $lo -physical $ph \
  269. -offset $printargs(resolution)
  270. # Handling of canvas widgets.
  271. switch [winfo class $wid] {
  272. Canvas {
  273. _print_canvas $printargs(hDC) $wid
  274. }
  275. default {
  276. puts "Can't print items of type [winfo class $wid]. No handler registered"
  277. }
  278. }
  279. # End printing process.
  280. _closepage
  281. _closedoc
  282. }
  283. # _print_canvas
  284. # Main procedure for writing canvas widget items to printer.
  285. # Arguments:
  286. # hdc - The printer handle.
  287. # cw - The canvas widget.
  288. proc _print_canvas {hdc cw} {
  289. variable vtgPrint
  290. variable printargs
  291. # Get information about page being printed to
  292. # print_canvas.CalcSizing $cw
  293. set vtgPrint(canvas.bg) [string tolower [$cw cget -background]]
  294. # Re-write each widget from cw to printer
  295. foreach id [$cw find all] {
  296. set type [$cw type $id]
  297. if {[info commands _print_canvas.$type] eq "_print_canvas.$type"} {
  298. _print_canvas.[$cw type $id] $printargs(hDC) $cw $id
  299. } else {
  300. puts "Omitting canvas item of type $type since there is no handler registered for it"
  301. }
  302. }
  303. }
  304. # These procedures support the various canvas item types, reading the
  305. # information about the item on the real canvas and then writing a
  306. # similar item to the printer.
  307. # _print_canvas.line
  308. # Description:
  309. # Prints a line item.
  310. # Arguments:
  311. # hdc - The printer handle.
  312. # cw - The canvas widget.
  313. # id - The id of the canvas item.
  314. proc _print_canvas.line {hdc cw id} {
  315. variable vtgPrint
  316. variable printargs
  317. set color [_print_canvas.TransColor [$cw itemcget $id -fill]]
  318. if {[string match $vtgPrint(printer.bg) $color]} {
  319. return
  320. }
  321. set coords [$cw coords $id]
  322. set wdth [$cw itemcget $id -width]
  323. set arrow [$cw itemcget $id -arrow]
  324. set arwshp [$cw itemcget $id -arrowshape]
  325. set dash [$cw itemcget $id -dash]
  326. set smooth [$cw itemcget $id -smooth]
  327. set splinesteps [$cw itemcget $id -splinesteps]
  328. set cmdargs {}
  329. if {$wdth > 1} {
  330. lappend cmdargs -width $wdth
  331. }
  332. if {$dash ne ""} {
  333. lappend cmdargs -dash $dash
  334. }
  335. if {$smooth ne ""} {
  336. lappend cmdargs -smooth $smooth
  337. }
  338. if {$splinesteps ne ""} {
  339. lappend cmdargs -splinesteps $splinesteps
  340. }
  341. set result [_gdi line $hdc {*}$coords \
  342. -fill $color -arrow $arrow -arrowshape $arwshp \
  343. {*}$cmdargs]
  344. if {$result ne ""} {
  345. puts $result
  346. }
  347. }
  348. # _print_canvas.arc
  349. # Prints a arc item.
  350. # Args:
  351. # hdc - The printer handle.
  352. # cw - The canvas widget.
  353. # id - The id of the canvas item.
  354. proc _print_canvas.arc {hdc cw id} {
  355. variable vtgPrint
  356. variable printargs
  357. set color [_print_canvas.TransColor [$cw itemcget $id -outline]]
  358. if {[string match $vtgPrint(printer.bg) $color]} {
  359. return
  360. }
  361. set coords [$cw coords $id]
  362. set wdth [$cw itemcget $id -width]
  363. set style [$cw itemcget $id -style]
  364. set start [$cw itemcget $id -start]
  365. set extent [$cw itemcget $id -extent]
  366. set fill [$cw itemcget $id -fill]
  367. set cmdargs {}
  368. if {$wdth > 1} {
  369. lappend cmdargs -width $wdth
  370. }
  371. if {$fill ne ""} {
  372. lappend cmdargs -fill $fill
  373. }
  374. _gdi arc $hdc {*}$coords \
  375. -outline $color -style $style -start $start -extent $extent \
  376. {*}$cmdargs
  377. }
  378. # _print_canvas.polygon
  379. # Prints a polygon item.
  380. # Arguments:
  381. # hdc - The printer handle.
  382. # cw - The canvas widget.
  383. # id - The id of the canvas item.
  384. proc _print_canvas.polygon {hdc cw id} {
  385. variable vtgPrint
  386. variable printargs
  387. set fcolor [_print_canvas.TransColor [$cw itemcget $id -fill]]
  388. if {$fcolor eq ""} {
  389. set fcolor $vtgPrint(printer.bg)
  390. }
  391. set ocolor [_print_canvas.TransColor [$cw itemcget $id -outline]]
  392. if {$ocolor eq ""} {
  393. set ocolor $vtgPrint(printer.bg)
  394. }
  395. set coords [$cw coords $id]
  396. set wdth [$cw itemcget $id -width]
  397. set smooth [$cw itemcget $id -smooth]
  398. set splinesteps [$cw itemcget $id -splinesteps]
  399. set cmdargs {}
  400. if {$smooth ne ""} {
  401. lappend cmdargs -smooth $smooth
  402. }
  403. if {$splinesteps ne ""} {
  404. lappend cmdargs -splinesteps $splinesteps
  405. }
  406. _gdi polygon $hdc {*}$coords \
  407. -width $wdth -fill $fcolor -outline $ocolor {*}$cmdargs
  408. }
  409. # _print_canvas.oval
  410. # Prints an oval item.
  411. # Arguments:
  412. # hdc - The printer handle.
  413. # cw - The canvas widget.
  414. # id - The id of the canvas item.
  415. proc _print_canvas.oval {hdc cw id} {
  416. variable vtgPrint
  417. set fcolor [_print_canvas.TransColor [$cw itemcget $id -fill]]
  418. if {$fcolor eq ""} {
  419. set fcolor $vtgPrint(printer.bg)
  420. }
  421. set ocolor [_print_canvas.TransColor [$cw itemcget $id -outline]]
  422. if {$ocolor eq ""} {
  423. set ocolor $vtgPrint(printer.bg)
  424. }
  425. set coords [$cw coords $id]
  426. set wdth [$cw itemcget $id -width]
  427. _gdi oval $hdc {*}$coords \
  428. -width $wdth -fill $fcolor -outline $ocolor
  429. }
  430. # _print_canvas.rectangle
  431. # Prints a rectangle item.
  432. # Arguments:
  433. # hdc - The printer handle.
  434. # cw - The canvas widget.
  435. # id - The id of the canvas item.
  436. proc _print_canvas.rectangle {hdc cw id} {
  437. variable vtgPrint
  438. set fcolor [_print_canvas.TransColor [$cw itemcget $id -fill]]
  439. if {$fcolor eq ""} {
  440. set fcolor $vtgPrint(printer.bg)
  441. }
  442. set ocolor [_print_canvas.TransColor [$cw itemcget $id -outline]]
  443. if {$ocolor eq ""} {
  444. set ocolor $vtgPrint(printer.bg)
  445. }
  446. set coords [$cw coords $id]
  447. set wdth [$cw itemcget $id -width]
  448. _gdi rectangle $hdc {*}$coords \
  449. -width $wdth -fill $fcolor -outline $ocolor
  450. }
  451. # _print_canvas.text
  452. # Prints a text item.
  453. # Arguments:
  454. # hdc - The printer handle.
  455. # cw - The canvas widget.
  456. # id - The id of the canvas item.
  457. proc _print_canvas.text {hdc cw id} {
  458. variable vtgPrint
  459. variable printargs
  460. set color [_print_canvas.TransColor [$cw itemcget $id -fill]]
  461. # if {"white" eq [string tolower $color]} {return}
  462. # set color black
  463. set txt [$cw itemcget $id -text]
  464. if {$txt eq ""} {
  465. return
  466. }
  467. set coords [$cw coords $id]
  468. set anchr [$cw itemcget $id -anchor]
  469. set bbox [$cw bbox $id]
  470. set wdth [expr {[lindex $bbox 2] - [lindex $bbox 0]}]
  471. set just [$cw itemcget $id -justify]
  472. # Get the real canvas font info and create a compatible font,
  473. # suitable for printer name extraction.
  474. set font [font create {*}[font actual [$cw itemcget $id -font]]]
  475. # Just get the name and family, or some of the _gdi commands will
  476. # fail.
  477. set font [list [font configure $font -family] \
  478. -[font configure $font -size]]
  479. _gdi text $hdc {*}$coords \
  480. -fill $color -text $txt -font $font \
  481. -anchor $anchr -width $wdth -justify $just
  482. }
  483. # _print_canvas.image
  484. # Prints an image item.
  485. # Arguments:
  486. # hdc - The printer handle.
  487. # cw - The canvas widget.
  488. # id - The id of the canvas item.
  489. proc _print_canvas.image {hdc cw id} {
  490. # First, we have to get the image name.
  491. set imagename [$cw itemcget $id -image]
  492. # Now we get the size.
  493. set wid [image width $imagename]
  494. set hgt [image height $imagename]
  495. # Next, we get the location and anchor
  496. set anchor [$cw itemcget $id -anchor]
  497. set coords [$cw coords $id]
  498. _gdi photo $hdc -destination $coords -photo $imagename
  499. }
  500. # _print_canvas.bitmap
  501. # Prints a bitmap item.
  502. # Arguments:
  503. # hdc - The printer handle.
  504. # cw - The canvas widget.
  505. # id - The id of the canvas item.
  506. proc _print_canvas.bitmap {hdc cw id} {
  507. variable option
  508. variable vtgPrint
  509. # First, we have to get the bitmap name.
  510. set imagename [$cw itemcget $id -image]
  511. # Now we get the size.
  512. set wid [image width $imagename]
  513. set hgt [image height $imagename]
  514. #Next, we get the location and anchor.
  515. set anchor [$cw itemcget $id -anchor]
  516. set coords [$cw coords $id]
  517. # Since the GDI commands don't yet support images and bitmaps,
  518. # and since this represents a rendered bitmap, we CAN use
  519. # copybits IF we create a new temporary toplevel to hold the beast.
  520. # If this is too ugly, change the option!
  521. if {[info exist option(use_copybits)]} {
  522. set firstcase $option(use_copybits)
  523. } else {
  524. set firstcase 0
  525. }
  526. if {$firstcase > 0} {
  527. set tl [toplevel .tmptop[expr {int( rand() * 65535 )}] \
  528. -height $hgt -width $wid \
  529. -background $vtgPrint(canvas.bg)]
  530. canvas $tl.canvas -width $wid -height $hgt
  531. $tl.canvas create image 0 0 -image $imagename -anchor nw
  532. pack $tl.canvas -side left -expand false -fill none
  533. tkwait visibility $tl.canvas
  534. update
  535. set srccoords [list 0 0 [expr {$wid - 1}] [expr {$hgt - 1}]]
  536. set dstcoords [list [lindex $coords 0] [lindex $coords 1] [expr {$wid - 1}] [expr {$hgt - 1}]]
  537. _gdi copybits $hdc -window $tl -client \
  538. -source $srccoords -destination $dstcoords
  539. destroy $tl
  540. } else {
  541. _gdi bitmap $hdc {*}$coords \
  542. -anchor $anchor -bitmap $imagename
  543. }
  544. }
  545. # These procedures transform attribute setting from the real
  546. # canvas to the appropriate setting for printing to paper.
  547. # _print_canvas.TransColor
  548. # Does the actual transformation of colors from the
  549. # canvas widget to paper.
  550. # Arguments:
  551. # color - The color value to be transformed.
  552. proc _print_canvas.TransColor {color} {
  553. variable vtgPrint
  554. variable printargs
  555. switch [string toupper $color] {
  556. $vtgPrint(canvas.bg) {return $vtgPrint(printer.bg)}
  557. }
  558. return $color
  559. }
  560. # Initialize all the variables once.
  561. _init_print_canvas
  562. }
  563. #end win32 procedures
  564. }
  565. # Begin X11 procedures. They depends on Cups being installed.
  566. # X11 procedures abstracts print management with a "cups" ensemble command
  567. # cups defaultprinter returns the default printer
  568. # cups getprinters returns a dictionary of printers along
  569. # with printer info
  570. # cups print $printer $data ?$options?
  571. # print the data (binary) on a given printer
  572. # with the provided (supported) options:
  573. # -colormode -copies -format -margins
  574. # -media -nup -orientation
  575. # -prettyprint -title -tzoom
  576. # Some output configuration that on other platforms is managed through
  577. # the printer driver/dialog is configured through the canvas postscript command.
  578. if {[tk windowingsystem] eq "x11"} {
  579. if {[info commands ::tk::print::cups] eq ""} {
  580. namespace eval ::tk::print::cups {
  581. # Pure Tcl cups ensemble command implementation
  582. variable pcache
  583. }
  584. proc ::tk::print::cups::defaultprinter {} {
  585. set default {}
  586. regexp {: ([^[:space:]]+)$} [exec lpstat -d] _ default
  587. return $default
  588. }
  589. proc ::tk::print::cups::getprinters {} {
  590. variable pcache
  591. # Test for existence of lpstat command to obtain the list of
  592. # printers.
  593. # Return an error if not found.
  594. set res {}
  595. try {
  596. set printers [lsort -unique [split [exec lpstat -e] \n]]
  597. foreach printer $printers {
  598. set options [Parseoptions [exec lpoptions -p $printer]]
  599. dict set res $printer $options
  600. }
  601. } trap {POSIX ENOENT} {e o} {
  602. # no such command in PATH
  603. set cmd [lindex [dict get $o -errorstack ] 1 2]
  604. return -code error "Unable to obtain the list of printers.\
  605. Command \"$cmd\" not found.\
  606. Please install the CUPS package for your system."
  607. } trap {CHILDSTATUS} {} {
  608. # command returns a non-0 exit status. Wrong print system?
  609. set cmd [lindex [dict get $o -errorstack ] 1 2]
  610. return -code error "Command \"$cmd\" return with errors"
  611. }
  612. return [set pcache $res]
  613. }
  614. # Parseoptions
  615. # Parse lpoptions -d output. It has three forms
  616. # option-key
  617. # option-key=option-value
  618. # option-key='option value with spaces'
  619. # Arguments:
  620. # data - data to process.
  621. #
  622. proc ::tk::print::cups::Parseoptions {data} {
  623. set res {}
  624. set re {[^ =]+|[^ ]+='[^']+'|[^ ]+=[^ ']+}
  625. foreach tok [regexp -inline -all $re $data] {
  626. lassign [split $tok "="] k v
  627. dict set res $k [string trim $v "'"]
  628. }
  629. return $res
  630. }
  631. proc ::tk::print::cups::print {printer data args} {
  632. variable pcache
  633. if {$printer ni [dict keys $pcache]} {
  634. return -code error "unknown printer or class \"$printer\""
  635. }
  636. set title "Tk print job"
  637. set options {
  638. -colormode -copies -format -margins -media -nup -orientation
  639. -prettyprint -title -tzoom
  640. }
  641. while {[llength $args]} {
  642. set opt [tcl::prefix match $options [lpop args 0]]
  643. switch $opt {
  644. -colormode {
  645. set opts {auto monochrome color}
  646. set val [tcl::prefix match $opts [lpop args 0]]
  647. lappend printargs -o print-color-mode=$val
  648. }
  649. -copies {
  650. set val [lpop args 0]
  651. if {![string is integer -strict $val] ||
  652. $val < 0 || $val > 100
  653. } {
  654. # save paper !!
  655. return -code error "copies must be an integer\
  656. between 0 and 100"
  657. }
  658. lappend printargs -o copies=$val
  659. }
  660. -format {
  661. set opts {auto pdf postscript text}
  662. set val [tcl::prefix match $opts [lpop args 0]]
  663. # lpr uses auto always
  664. }
  665. -margins {
  666. set val [lpop args 0]
  667. if {[llength $val] != 4 ||
  668. ![string is integer -strict [lindex $val 0]] ||
  669. ![string is integer -strict [lindex $val 1]] ||
  670. ![string is integer -strict [lindex $val 2]] ||
  671. ![string is integer -strict [lindex $val 3]]
  672. } {
  673. return -code error "margins must be a list of 4\
  674. integers: top left bottom right"
  675. }
  676. lappend printargs -o page-top=[lindex $val 0]
  677. lappend printargs -o page-left=[lindex $val 1]
  678. lappend printargs -o page-bottom=[lindex $val 2]
  679. lappend printargs -o page-right=[lindex $val 3]
  680. }
  681. -media {
  682. set opts {a4 legal letter}
  683. set val [tcl::prefix match $opts [lpop args 0]]
  684. lappend printargs -o media=$val
  685. }
  686. -nup {
  687. set val [lpop args 0]
  688. if {$val ni {1 2 4 6 9 16}} {
  689. return -code error "number-up must be 1, 2, 4, 6, 9 or\
  690. 16"
  691. }
  692. lappend printargs -o number-up=$val
  693. }
  694. -orientation {
  695. set opts {portrait landscape}
  696. set val [tcl::prefix match $opts [lpop args 0]]
  697. if {$val eq "landscape"}
  698. lappend printargs -o landscape=true
  699. }
  700. -prettyprint {
  701. lappend printargs -o prettyprint=true
  702. # prettyprint mess with these default values if set
  703. # so we force them.
  704. # these will be overriden if set after this point
  705. if {[lsearch $printargs {cpi=*}] == -1} {
  706. lappend printargs -o cpi=10.0
  707. lappend printargs -o lpi=6.0
  708. }
  709. }
  710. -title {
  711. set title [lpop args 0]
  712. }
  713. -tzoom {
  714. set val [lpop args 0]
  715. if {![string is double -strict $val] ||
  716. $val < 0.5 || $val > 2.0
  717. } {
  718. return -code error "text zoom must be a number between\
  719. 0.5 and 2.0"
  720. }
  721. # CUPS text filter defaults to lpi=6 and cpi=10
  722. lappend printargs -o cpi=[expr {10.0 / $val}]
  723. lappend printargs -o lpi=[expr {6.0 / $val}]
  724. }
  725. default {
  726. # shouldn't happen
  727. }
  728. }
  729. }
  730. # build our options
  731. lappend printargs -T $title
  732. lappend printargs -P $printer
  733. # open temp file
  734. set fd [file tempfile fname tk_print]
  735. chan configure $fd -translation binary
  736. chan puts $fd $data
  737. chan close $fd
  738. # add -r to automatically delete temp files
  739. exec lpr {*}$printargs -r $fname &
  740. }
  741. namespace eval ::tk::print::cups {
  742. namespace export defaultprinter getprinters print
  743. namespace ensemble create
  744. }
  745. };# ::tk::print::cups
  746. namespace eval ::tk::print {
  747. variable mcmap
  748. set mcmap(media) [dict create \
  749. [mc "Letter"] letter \
  750. [mc "Legal"] legal \
  751. [mc "A4"] a4]
  752. set mcmap(orient) [dict create \
  753. [mc "Portrait"] portrait \
  754. [mc "Landscape"] landscape]
  755. set mcmap(color) [dict create \
  756. [mc "RGB"] color \
  757. [mc "Grayscale"] gray]
  758. # available print options
  759. variable optlist
  760. set optlist(printer) {}
  761. set optlist(media) [dict keys $mcmap(media)]
  762. set optlist(orient) [dict keys $mcmap(orient)]
  763. set optlist(color) [dict keys $mcmap(color)]
  764. set optlist(number-up) {1 2 4 6 9 16}
  765. # selected options
  766. variable option
  767. set option(printer) {}
  768. # Initialize with sane defaults.
  769. set option(copies) 1
  770. set option(media) [mc "A4"]
  771. # Canvas options
  772. set option(orient) [mc "Portrait"]
  773. set option(color) [mc "RGB"]
  774. set option(czoom) 100
  775. # Text options.
  776. # See libcupsfilter's cfFilterTextToPDF() and cups-filters's texttopdf
  777. # known options:
  778. # prettyprint, wrap, columns, lpi, cpi
  779. set option(number-up) 1
  780. set option(tzoom) 100; # we derive lpi and cpi from this value
  781. set option(pprint) 0 ; # pretty print
  782. set option(margin-top) 20 ; # ~ 7mm (~ 1/4")
  783. set option(margin-left) 20 ; # ~ 7mm (~ 1/4")
  784. set option(margin-right) 20 ; # ~ 7mm (~ 1/4")
  785. set option(margin-bottom) 20 ; # ~ 7mm (~ 1/4")
  786. # array to collect printer information
  787. variable pinfo
  788. array set pinfo {}
  789. # a map for printer state -> human readable message
  790. variable statemap
  791. dict set statemap 3 [mc "Idle"]
  792. dict set statemap 4 [mc "Printing"]
  793. dict set statemap 5 [mc "Printer stopped"]
  794. }
  795. # ttk version of [tk_optionMenu]
  796. # var should be a full qualified varname
  797. proc ::tk::print::ttk_optionMenu {w var args} {
  798. ttk::menubutton $w -textvariable $var -menu $w.menu
  799. menu $w.menu
  800. foreach option $args {
  801. $w.menu add command \
  802. -label $option \
  803. -command [list set $var $option]
  804. }
  805. # return the same value as tk_optionMenu
  806. return $w.menu
  807. }
  808. # _setprintenv
  809. # Set the print environtment - list of printers, state and options.
  810. # Arguments:
  811. # none.
  812. #
  813. proc ::tk::print::_setprintenv {} {
  814. variable option
  815. variable optlist
  816. variable pinfo
  817. set optlist(printer) {}
  818. dict for {printer options} [cups getprinters] {
  819. lappend optlist(printer) $printer
  820. set pinfo($printer) $options
  821. }
  822. # It's an error to not have any printer configured
  823. if {[llength $optlist(printer)] == 0} {
  824. return -code error "No installed printers found.\
  825. Please check or update your CUPS installation."
  826. }
  827. # If no printer is selected, check for the default one
  828. # If none found, use the first one from the list
  829. if {$option(printer) eq ""} {
  830. set option(printer) [cups defaultprinter]
  831. if {$option(printer) eq ""} {
  832. set option(printer) [lindex $optlist(printer) 0]
  833. }
  834. }
  835. }
  836. # _print
  837. # Main printer dialog.
  838. # Select printer, set options, and fire print command.
  839. # Arguments:
  840. # w - widget with contents to print.
  841. #
  842. proc ::tk::print::_print {w} {
  843. variable optlist
  844. variable option
  845. variable pinfo
  846. variable statemap
  847. # default values for dialog widgets
  848. option add *Printdialog*TLabel.anchor e
  849. option add *Printdialog*TMenubutton.Menu.tearOff 0
  850. option add *Printdialog*TMenubutton.width 12
  851. option add *Printdialog*TSpinbox.width 12
  852. # this is tempting to add, but it's better to leave it to
  853. # user's taste.
  854. # option add *Printdialog*Menu.background snow
  855. set class [winfo class $w]
  856. if {$class ni {Text Canvas}} {
  857. return -code error "printing windows of class \"$class\"\
  858. is not supported"
  859. }
  860. # Should this be called with every invocaton?
  861. # Yes. It allows dynamic discovery of newly added printers
  862. # whithout having to restart the app
  863. _setprintenv
  864. set p ._print
  865. destroy $p
  866. # Copy the current values to a dialog's temporary variable.
  867. # This allow us to cancel the dialog discarding any changes
  868. # made to the options
  869. namespace eval dlg {variable option}
  870. array set dlg::option [array get option]
  871. set var [namespace which -variable dlg::option]
  872. # The toplevel of our dialog
  873. toplevel $p -class Printdialog
  874. place [ttk::frame $p.background] -x 0 -y 0 -relwidth 1.0 -relheight 1.0
  875. wm title $p [mc "Print"]
  876. wm resizable $p 0 0
  877. wm attributes $p -type dialog
  878. wm transient $p [winfo toplevel $w]
  879. # The printer to use
  880. set pf [ttk::frame $p.printerf]
  881. pack $pf -side top -fill x -expand no -padx 9p -pady 9p
  882. ttk::label $pf.printerl -text "[mc "Printer"]"
  883. set tv [ttk::treeview $pf.prlist -height 5 \
  884. -columns {printer location state} \
  885. -show headings \
  886. -selectmode browse]
  887. $tv configure \
  888. -yscrollcommand [namespace code [list _scroll $pf.sy]] \
  889. -xscrollcommand [namespace code [list _scroll $pf.sx]]
  890. ttk::scrollbar $pf.sy -command [list $tv yview]
  891. ttk::scrollbar $pf.sx -command [list $tv xview] -orient horizontal
  892. $tv heading printer -text [mc "Printer"]
  893. $tv heading location -text [mc "Location"]
  894. $tv heading state -text [mc "State"]
  895. $tv column printer -width 200 -stretch 0
  896. $tv column location -width 100 -stretch 0
  897. $tv column state -width 250 -stretch 0
  898. foreach printer $optlist(printer) {
  899. set location [dict getdef $pinfo($printer) printer-location ""]
  900. set nstate [dict getdef $pinfo($printer) printer-state 0]
  901. set state [dict getdef $statemap $nstate ""]
  902. switch -- $nstate {
  903. 3 - 4 {
  904. set accepting [dict getdef $pinfo($printer) \
  905. printer-is-accepting-jobs ""]
  906. if {$accepting ne ""} {
  907. append state ". " [mc "Printer is accepting jobs"]
  908. }
  909. }
  910. 5 {
  911. set reason [dict getdef $pinfo($printer) \
  912. printer-state-reasons ""]
  913. if {$reason ne ""} {
  914. append state ". (" $reason ")"
  915. }
  916. }
  917. }
  918. set id [$tv insert {} end \
  919. -values [list $printer $location $state]]
  920. if {$option(printer) eq $printer} {
  921. $tv selection set $id
  922. }
  923. }
  924. grid $pf.printerl -sticky w
  925. grid $pf.prlist $pf.sy -sticky news
  926. grid $pf.sx -sticky ew
  927. grid remove $pf.sy $pf.sx
  928. bind $tv <<TreeviewSelect>> [namespace code {_onselect %W}]
  929. # Start of printing options
  930. set of [ttk::labelframe $p.optionsframe -text [mc "Options"]]
  931. pack $of -fill x -padx 9p -pady {0 9p} -ipadx 2p -ipady 2p
  932. # COPIES
  933. ttk::label $of.copiesl -text "[mc "Copies"] :"
  934. ttk::spinbox $of.copies -textvariable ${var}(copies) \
  935. -from 1 -to 1000
  936. grid $of.copiesl $of.copies -sticky ew -padx 2p -pady 2p
  937. $of.copies state readonly
  938. # PAPER SIZE
  939. ttk::label $of.medial -text "[mc "Paper"] :"
  940. ttk_optionMenu $of.media ${var}(media) {*}$optlist(media)
  941. grid $of.medial $of.media -sticky ew -padx 2p -pady 2p
  942. if {$class eq "Canvas"} {
  943. # additional options for Canvas output
  944. # SCALE
  945. ttk::label $of.percentl -text "[mc "Scale"] :"
  946. ttk::spinbox $of.percent -textvariable ${var}(czoom) \
  947. -from 5 -to 500 -increment 5
  948. grid $of.percentl $of.percent -sticky ew -padx 2p -pady 2p
  949. $of.percent state readonly
  950. # ORIENT
  951. ttk::label $of.orientl -text "[mc "Orientation"] :"
  952. ttk_optionMenu $of.orient ${var}(orient) {*}$optlist(orient)
  953. grid $of.orientl $of.orient -sticky ew -padx 2p -pady 2p
  954. # COLOR
  955. ttk::label $of.colorl -text "[mc "Output"] :"
  956. ttk_optionMenu $of.color ${var}(color) {*}$optlist(color)
  957. grid $of.colorl $of.color -sticky ew -padx 2p -pady 2p
  958. } elseif {$class eq "Text"} {
  959. # additional options for Text output
  960. # NUMBER-UP
  961. ttk::label $of.nupl -text "[mc "Pages per sheet"] :"
  962. ttk_optionMenu $of.nup ${var}(number-up) {*}$optlist(number-up)
  963. grid $of.nupl $of.nup -sticky ew -padx 2p -pady 2p
  964. # TEXT SCALE
  965. ttk::label $of.tzooml -text "[mc "Text scale"] :"
  966. ttk::spinbox $of.tzoom -textvariable ${var}(tzoom) \
  967. -from 50 -to 200 -increment 5
  968. grid $of.tzooml $of.tzoom -sticky ew -padx 2p -pady 2p
  969. $of.tzoom state readonly
  970. # PRETTY PRINT (banner on top)
  971. ttk::checkbutton $of.pprint -onvalue 1 -offvalue 0 \
  972. -text [mc "Pretty print"] \
  973. -variable ${var}(pprint)
  974. grid $of.pprint - -sticky ew -padx 2p -pady 2p
  975. }
  976. # The buttons frame.
  977. set bf [ttk::frame $p.buttonf]
  978. pack $bf -fill x -expand no -side bottom -padx 9p -pady {0 9p}
  979. ttk::button $bf.print -text [mc "Print"] \
  980. -command [namespace code [list _runprint $w $class $p]]
  981. ttk::button $bf.cancel -text [mc "Cancel"] \
  982. -command [list destroy $p]
  983. pack $bf.print -side right
  984. pack $bf.cancel -side right -padx {0 4.5p}
  985. # cleanup binding
  986. bind $bf <Destroy> [namespace code [list _cleanup $p]]
  987. # Center the window as a dialog.
  988. ::tk::PlaceWindow $p
  989. }
  990. # _onselect
  991. # Updates the selected printer when treeview selection changes.
  992. # Arguments:
  993. # tv - treeview pathname.
  994. #
  995. proc ::tk::print::_onselect {tv} {
  996. variable dlg::option
  997. set id [$tv selection]
  998. if {$id eq ""} {
  999. # is this even possible?
  1000. set option(printer) ""
  1001. } else {
  1002. set option(printer) [$tv set $id printer]
  1003. }
  1004. }
  1005. # _scroll
  1006. # Implements autoscroll for the printers view
  1007. #
  1008. proc ::tk::print::_scroll {sbar from to} {
  1009. if {$from == 0.0 && $to == 1.0} {
  1010. grid remove $sbar
  1011. } else {
  1012. grid $sbar
  1013. $sbar set $from $to
  1014. }
  1015. }
  1016. # _cleanup
  1017. # Perform cleanup when the dialog is destroyed.
  1018. # Arguments:
  1019. # p - print dialog pathname (not used).
  1020. #
  1021. proc ::tk::print::_cleanup {p} {
  1022. namespace delete dlg
  1023. }
  1024. # _runprint -
  1025. # Execute the print command--print the file.
  1026. # Arguments:
  1027. # w - widget with contents to print.
  1028. # class - class of the widget to print (Canvas or Text).
  1029. # p - print dialog pathname.
  1030. #
  1031. proc ::tk::print::_runprint {w class p} {
  1032. variable option
  1033. variable mcmap
  1034. # copy the values back from the dialog
  1035. array set option [array get dlg::option]
  1036. # get (back) name of media from the translated one
  1037. set media [dict get $mcmap(media) $option(media)]
  1038. set printargs {}
  1039. lappend printargs -title "[tk appname]: Tk window $w"
  1040. lappend printargs -copies $option(copies)
  1041. lappend printargs -media $media
  1042. if {$class eq "Canvas"} {
  1043. set colormode [dict get $mcmap(color) $option(color)]
  1044. set rotate 0
  1045. if {[dict get $mcmap(orient) $option(orient)] eq "landscape"} {
  1046. set rotate 1
  1047. }
  1048. # Scale based on size of widget, not size of paper.
  1049. # TODO: is this correct??
  1050. set printwidth [expr {
  1051. $option(czoom) / 100.0 * [winfo width $w]
  1052. }]
  1053. set data [encoding convertto iso8859-1 [$w postscript \
  1054. -colormode $colormode -rotate $rotate -pagewidth $printwidth]]
  1055. } elseif {$class eq "Text"} {
  1056. set tzoom [expr {$option(tzoom) / 100.0}]
  1057. if {$option(tzoom) != 100} {
  1058. lappend printargs -tzoom $tzoom
  1059. }
  1060. if {$option(pprint)} {
  1061. lappend printargs -prettyprint
  1062. }
  1063. if {$option(number-up) != 1} {
  1064. lappend printargs -nup $option(number-up)
  1065. }
  1066. # these are hardcoded. Should we allow the user to control
  1067. # margins?
  1068. lappend printargs -margins [list \
  1069. $option(margin-top) $option(margin-left) \
  1070. $option(margin-bottom) $option(margin-right) ]
  1071. # get the data in shape. Cupsfilter's text filter wraps lines
  1072. # at character level, not words, so we do it by ourselves.
  1073. # compute usable page width in inches
  1074. set pw [dict get {a4 8.27 legal 8.5 letter 8.5} $media]
  1075. set pw [expr {
  1076. $pw - ($option(margin-left) + $option(margin-right)) / 72.0
  1077. }]
  1078. # set the wrap length at 98% of computed page width in chars
  1079. # the 9.8 constant is the product 10.0 (default cpi) * 0.95
  1080. set wl [expr {int( 9.8 * $pw / $tzoom )}]
  1081. set data [encoding convertto utf-8 [_wrapLines [$w get 1.0 end] $wl]]
  1082. }
  1083. # launch the job in the background
  1084. after idle [namespace code \
  1085. [list cups print $option(printer) $data {*}$printargs]]
  1086. destroy $p
  1087. }
  1088. # _wrapLines -
  1089. # wrap long lines into lines of at most length wl at word boundaries
  1090. # Arguments:
  1091. # str - string to be wrapped
  1092. # wl - wrap length
  1093. #
  1094. proc ::tk::print::_wrapLines {str wl} {
  1095. # This is a really simple algorithm: it breaks a line on space or tab
  1096. # character, collapsing them only at the breaking point.
  1097. # Leading space is left as-is.
  1098. # For a full fledged line breaking algorithm see
  1099. # Unicode® Standard Annex #14 "Unicode Line Breaking Algorithm"
  1100. set res {}
  1101. incr wl -1
  1102. set re [format {((?:^|[^[:blank:]]).{0,%d})(?:[[:blank:]]|$)} $wl]
  1103. foreach line [split $str \n] {
  1104. lappend res {*}[lmap {_ l} [regexp -all -inline -- $re $line] {
  1105. set l
  1106. }]
  1107. }
  1108. return [join $res \n]
  1109. }
  1110. }
  1111. #end X11 procedures
  1112. namespace eval ::tk::print {
  1113. #begin macOS Aqua procedures
  1114. if {[tk windowingsystem] eq "aqua"} {
  1115. # makePDF -
  1116. # Convert a file to PDF
  1117. # Arguments:
  1118. # inFilename - file containing the data to convert; format is
  1119. # autodetected.
  1120. # outFilename - base for filename to write to; conventionally should
  1121. # have .pdf as suffix
  1122. # Returns:
  1123. # The full pathname of the generated PDF.
  1124. #
  1125. proc makePDF {inFilename outFilename} {
  1126. set out [::tk::print::makeTempFile $outFilename]
  1127. try {
  1128. exec /usr/sbin/cupsfilter $inFilename > $out
  1129. } trap NONE {msg} {
  1130. # cupsfilter produces a lot of debugging output, which we
  1131. # don't want.
  1132. regsub -all -line {^(?:DEBUG|INFO):.*$} $msg "" msg
  1133. set msg [string trimleft [regsub -all {\n+} $msg "\n"] "\n"]
  1134. if {$msg ne ""} {
  1135. # Lines should be prefixed with WARN or ERROR now
  1136. puts $msg
  1137. }
  1138. }
  1139. return $out
  1140. }
  1141. }
  1142. #end macOS Aqua procedures
  1143. namespace export canvas text
  1144. namespace ensemble create
  1145. }
  1146. # tk print --
  1147. # This procedure prints the canvas and text widgets using platform-
  1148. # native API's.
  1149. # Arguments:
  1150. # w: Widget to print.
  1151. proc ::tk::print {w} {
  1152. switch [winfo class $w],[tk windowingsystem] {
  1153. "Canvas,win32" {
  1154. tailcall ::tk::print::_print_widget $w 0 "Tk Print Output"
  1155. }
  1156. "Canvas,x11" {
  1157. tailcall ::tk::print::_print $w
  1158. }
  1159. "Canvas,aqua" {
  1160. ::tk::print::_printcanvas $w
  1161. set printfile /tmp/tk_canvas.pdf
  1162. ::tk::print::_print $printfile
  1163. }
  1164. "Text,win32" {
  1165. tailcall ::tk::print::_print_data [$w get 1.0 end] 1 {Arial 12}
  1166. }
  1167. "Text,x11" {
  1168. tailcall ::tk::print::_print $w
  1169. }
  1170. "Text,aqua" {
  1171. set txtfile [::tk::print::makeTempFile tk_text.txt [$w get 1.0 end]]
  1172. try {
  1173. set printfile [::tk::print::makePDF $txtfile [file join /tmp tk_text.pdf]]
  1174. ::tk::print::_print $printfile
  1175. } finally {
  1176. file delete $txtfile
  1177. }
  1178. }
  1179. default {
  1180. return -code error -errorcode {TK PRINT CLASS_UNSUPPORTED} \
  1181. "widgets of class [winfo class $w] are not supported on\
  1182. this platform"
  1183. }
  1184. }
  1185. }
  1186. #Add this command to the tk command ensemble: tk print
  1187. #Thanks to Christian Gollwitzer for the guidance here
  1188. namespace ensemble configure tk -map \
  1189. [dict merge [namespace ensemble configure tk -map] \
  1190. {print ::tk::print}]
  1191. return
  1192. # Local Variables:
  1193. # mode: tcl
  1194. # fill-column: 78
  1195. # End: