home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 November / CPNL0711.ISO / beeld / teken / scribus-1.3.3.9-win32-install.exe / tcl / tk8.4 / safetk.tcl < prev    next >
Text File  |  2000-10-30  |  8KB  |  278 lines

  1. # safetk.tcl --
  2. #
  3. # Support procs to use Tk in safe interpreters.
  4. #
  5. # RCS: @(#) $Id: safetk.tcl,v 1.8 2000/10/31 01:11:51 hobbs Exp $
  6. #
  7. # Copyright (c) 1997 Sun Microsystems, Inc.
  8. #
  9. # See the file "license.terms" for information on usage and redistribution
  10. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  
  12. # see safetk.n for documentation
  13.  
  14. #
  15. #
  16. # Note: It is now ok to let untrusted code being executed
  17. #       between the creation of the interp and the actual loading
  18. #       of Tk in that interp because the C side Tk_Init will
  19. #       now look up the master interp and ask its safe::TkInit
  20. #       for the actual parameters to use for it's initialization (if allowed),
  21. #       not relying on the slave state.
  22. #
  23.  
  24. # We use opt (optional arguments parsing)
  25. package require opt 0.4.1;
  26.  
  27. namespace eval ::safe {
  28.  
  29.     # counter for safe toplevels
  30.     variable tkSafeId 0;
  31.  
  32.     #
  33.     # tkInterpInit : prepare the slave interpreter for tk loading
  34.     #                most of the real job is done by loadTk
  35.     # returns the slave name (tkInterpInit does)
  36.     #
  37.     proc ::safe::tkInterpInit {slave argv} {
  38.     global env tk_library
  39.  
  40.     # We have to make sure that the tk_library variable uses a file
  41.     # pathname that works better in Tk (of the style returned by
  42.     # [file join], ie C:/path/to/tk/lib, not C:\path\to\tk\lib
  43.     set tk_library [file join $tk_library]
  44.  
  45.     # Clear Tk's access for that interp (path).
  46.     allowTk $slave $argv
  47.  
  48.     # there seems to be an obscure case where the tk_library
  49.     # variable value is changed to point to a sym link destination
  50.     # dir instead of the sym link itself, and thus where the $tk_library
  51.     # would then not be anymore one of the auto_path dir, so we use
  52.     # the addToAccessPath which adds if it's not already in instead
  53.     # of the more conventional findInAccessPath.
  54.     # Might be usefull for masters without Tk really loaded too.
  55.     ::interp eval $slave [list set tk_library [::safe::interpAddToAccessPath $slave $tk_library]]
  56.     return $slave
  57.     }
  58.  
  59.  
  60. # tkInterpLoadTk : 
  61. # Do additional configuration as needed (calling tkInterpInit) 
  62. # and actually load Tk into the slave.
  63. # Either contained in the specified windowId (-use) or
  64. # creating a decorated toplevel for it.
  65.  
  66. # empty definition for auto_mkIndex
  67. proc ::safe::loadTk {} {}
  68.    
  69. ::tcl::OptProc loadTk {
  70.     {slave -interp "name of the slave interpreter"}
  71.     {-use  -windowId {} "window Id to use (new toplevel otherwise)"}
  72.     {-display -displayName {} "display name to use (current one otherwise)"}
  73. } {
  74.     set displayGiven [::tcl::OptProcArgGiven "-display"]
  75.     if {!$displayGiven} {
  76.     
  77.     # Try to get the current display from "."
  78.     # (which might not exist if the master is tk-less)
  79.     
  80.     if {[catch {set display [winfo screen .]}]} {
  81.         if {[info exists ::env(DISPLAY)]} {
  82.         set display $::env(DISPLAY)
  83.         } else {
  84.         Log $slave "no winfo screen . nor env(DISPLAY)" WARNING
  85.         set display ":0.0"
  86.         }
  87.     }
  88.     }
  89.     if {![::tcl::OptProcArgGiven "-use"]} {
  90.     
  91.     # create a decorated toplevel
  92.     
  93.     ::tcl::Lassign [tkTopLevel $slave $display] w use
  94.  
  95.     # set our delete hook (slave arg is added by interpDelete)
  96.     # to clean up both window related code and tkInit(slave)
  97.     Set [DeleteHookName $slave] [list tkDelete {} $w]
  98.  
  99.     } else {
  100.  
  101.     # set our delete hook (slave arg is added by interpDelete)
  102.     # to clean up tkInit(slave)
  103.         
  104.     Set [DeleteHookName $slave] [list disallowTk]
  105.  
  106.     # Let's be nice and also accept tk window names instead of ids
  107.     
  108.     if {[string match ".*" $use]} {
  109.         set windowName $use
  110.         set use [winfo id $windowName]
  111.         set nDisplay [winfo screen $windowName]
  112.     } else {
  113.  
  114.         # Check for a better -display value
  115.         # (works only for multi screens on single host, but not
  116.         #  cross hosts, for that a tk window name would be better
  117.         #  but embeding is also usefull for non tk names)
  118.         
  119.         if {![catch {winfo pathname $use} name]} {
  120.         set nDisplay [winfo screen $name]
  121.         } else {
  122.  
  123.         # Can't have a better one
  124.         
  125.         set nDisplay $display
  126.         }
  127.     }
  128.     if {[string compare $nDisplay $display]} {
  129.         if {$displayGiven} {
  130.         error "conflicting -display $display and -use\
  131.             $use -> $nDisplay"
  132.         } else {
  133.         set display $nDisplay
  134.         }
  135.     }
  136.     }
  137.  
  138.     # Prepares the slave for tk with those parameters
  139.     
  140.     tkInterpInit $slave [list "-use" $use "-display" $display]
  141.     
  142.     load {} Tk $slave
  143.  
  144.     return $slave
  145. }
  146.  
  147. proc ::safe::TkInit {interpPath} {
  148.     variable tkInit
  149.     if {[info exists tkInit($interpPath)]} {
  150.     set value $tkInit($interpPath)
  151.     Log $interpPath "TkInit called, returning \"$value\"" NOTICE
  152.     return $value
  153.     } else {
  154.     Log $interpPath "TkInit called for interp with clearance:\
  155.         preventing Tk init" ERROR
  156.     error "not allowed"
  157.     }
  158. }
  159.  
  160. # safe::allowTk --
  161. #
  162. #    Set tkInit(interpPath) to allow Tk to be initialized in
  163. #    safe::TkInit.
  164. #
  165. # Arguments:
  166. #    interpPath    slave interpreter handle
  167. #    argv        arguments passed to safe::TkInterpInit
  168. #
  169. # Results:
  170. #    none.
  171.  
  172. proc ::safe::allowTk {interpPath argv} {
  173.     variable tkInit
  174.     set tkInit($interpPath) $argv
  175.     return
  176. }
  177.  
  178.  
  179. # safe::disallowTk --
  180. #
  181. #    Unset tkInit(interpPath) to disallow Tk from getting initialized
  182. #    in safe::TkInit.
  183. #
  184. # Arguments:
  185. #    interpPath    slave interpreter handle
  186. #
  187. # Results:
  188. #    none.
  189.  
  190. proc ::safe::disallowTk {interpPath} {
  191.     variable tkInit
  192.     # This can already be deleted by the DeleteHook of the interp
  193.     if {[info exists tkInit($interpPath)]} {
  194.     unset tkInit($interpPath)
  195.     }
  196.     return
  197. }
  198.  
  199.  
  200. # safe::tkDelete --
  201. #
  202. #    Clean up the window associated with the interp being deleted.
  203. #
  204. # Arguments:
  205. #    interpPath    slave interpreter handle
  206. #
  207. # Results:
  208. #    none.
  209.  
  210. proc ::safe::tkDelete {W window slave} {
  211.  
  212.     # we are going to be called for each widget... skip untill it's
  213.     # top level
  214.  
  215.     Log $slave "Called tkDelete $W $window" NOTICE
  216.     if {[::interp exists $slave]} {
  217.     if {[catch {::safe::interpDelete $slave} msg]} {
  218.         Log $slave "Deletion error : $msg"
  219.     }
  220.     }
  221.     if {[winfo exists $window]} {
  222.     Log $slave "Destroy toplevel $window" NOTICE
  223.     destroy $window
  224.     }
  225.     
  226.     # clean up tkInit(slave)
  227.     disallowTk $slave
  228.     return
  229. }
  230.  
  231. proc ::safe::tkTopLevel {slave display} {
  232.     variable tkSafeId
  233.     incr tkSafeId
  234.     set w ".safe$tkSafeId"
  235.     if {[catch {toplevel $w -screen $display -class SafeTk} msg]} {
  236.     return -code error "Unable to create toplevel for\
  237.         safe slave \"$slave\" ($msg)"
  238.     }
  239.     Log $slave "New toplevel $w" NOTICE
  240.  
  241.     set msg "Untrusted Tcl applet ($slave)"
  242.     wm title $w $msg
  243.  
  244.     # Control frame
  245.     set wc $w.fc
  246.     frame $wc -bg red -borderwidth 3 -relief ridge
  247.  
  248.     # We will destroy the interp when the window is destroyed
  249.     bindtags $wc [concat Safe$wc [bindtags $wc]]
  250.     bind Safe$wc <Destroy> [list ::safe::tkDelete %W $w $slave]
  251.  
  252.     label $wc.l -text $msg -padx 2 -pady 0 -anchor w
  253.  
  254.     # We want the button to be the last visible item
  255.     # (so be packed first) and at the right and not resizing horizontally
  256.  
  257.     # frame the button so it does not expand horizontally
  258.     # but still have the default background instead of red one from the parent
  259.     frame  $wc.fb -bd 0
  260.     button $wc.fb.b -text "Delete" \
  261.         -bd 1  -padx 2 -pady 0 -highlightthickness 0 \
  262.         -command [list ::safe::tkDelete $w $w $slave]
  263.     pack $wc.fb.b -side right -fill both
  264.     pack $wc.fb -side right -fill both -expand 1
  265.     pack $wc.l -side left  -fill both -expand 1
  266.     pack $wc -side bottom -fill x
  267.  
  268.     # Container frame
  269.     frame $w.c -container 1
  270.     pack $w.c -fill both -expand 1
  271.     
  272.     # return both the toplevel window name and the id to use for embedding
  273.     list $w [winfo id $w.c]
  274. }
  275.  
  276. }
  277.