tk.tcl
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:17k
源码类别:

通讯编程

开发平台:

Visual C++

  1. # tk.tcl --
  2. #
  3. # Initialization script normally executed in the interpreter for each
  4. # Tk-based application.  Arranges class bindings for widgets.
  5. #
  6. # RCS: @(#) $Id: tk.tcl,v 1.46.2.7 2007/04/29 02:24:49 das Exp $
  7. #
  8. # Copyright (c) 1992-1994 The Regents of the University of California.
  9. # Copyright (c) 1994-1996 Sun Microsystems, Inc.
  10. # Copyright (c) 1998-2000 Ajuba Solutions.
  11. #
  12. # See the file "license.terms" for information on usage and redistribution
  13. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14. # Insist on running with compatible versions of Tcl and Tk.
  15. package require -exact Tk  8.4
  16. package require -exact Tcl 8.4
  17. # Create a ::tk namespace
  18. namespace eval ::tk {
  19.     # Set up the msgcat commands
  20.     namespace eval msgcat {
  21. namespace export mc mcmax
  22.         if {[interp issafe] || [catch {package require msgcat}]} {
  23.             # The msgcat package is not available.  Supply our own
  24.             # minimal replacement.
  25.             proc mc {src args} {
  26.                 return [eval [list format $src] $args]
  27.             }
  28.             proc mcmax {args} {
  29.                 set max 0
  30.                 foreach string $args {
  31.                     set len [string length $string]
  32.                     if {$len>$max} {
  33.                         set max $len
  34.                     }
  35.                 }
  36.                 return $max
  37.             }
  38.         } else {
  39.             # Get the commands from the msgcat package that Tk uses.
  40.             namespace import ::msgcat::mc
  41.             namespace import ::msgcat::mcmax
  42.             ::msgcat::mcload [file join $::tk_library msgs]
  43.         }
  44.     }
  45.     namespace import ::tk::msgcat::*
  46. }
  47. # Add Tk's directory to the end of the auto-load search path, if it
  48. # isn't already on the path:
  49. if {[info exists ::auto_path] && $::tk_library ne "" && 
  50. [lsearch -exact $::auto_path $::tk_library] < 0} {
  51.     lappend ::auto_path $::tk_library
  52. }
  53. # Turn off strict Motif look and feel as a default.
  54. set ::tk_strictMotif 0
  55. # Turn on useinputmethods (X Input Methods) by default.
  56. # We catch this because safe interpreters may not allow the call.
  57. catch {tk useinputmethods 1}
  58. # ::tk::PlaceWindow --
  59. #   place a toplevel at a particular position
  60. # Arguments:
  61. #   toplevel name of toplevel window
  62. #   ?placement? pointer ?center? ; places $w centered on the pointer
  63. # widget widgetPath ; centers $w over widget_name
  64. # defaults to placing toplevel in the middle of the screen
  65. #   ?anchor? center or widgetPath
  66. # Results:
  67. #   Returns nothing
  68. #
  69. proc ::tk::PlaceWindow {w {place ""} {anchor ""}} {
  70.     wm withdraw $w
  71.     update idletasks
  72.     set checkBounds 1
  73.     set place_len [string length $place]
  74.     if {$place eq ""} {
  75. set x [expr {([winfo screenwidth $w]-[winfo reqwidth $w])/2}]
  76. set y [expr {([winfo screenheight $w]-[winfo reqheight $w])/2}]
  77. set checkBounds 0
  78.     } elseif {[string equal -length $place_len $place "pointer"]} {
  79. ## place at POINTER (centered if $anchor == center)
  80. if {[string equal -length [string length $anchor] $anchor "center"]} {
  81.     set x [expr {[winfo pointerx $w]-[winfo reqwidth $w]/2}]
  82.     set y [expr {[winfo pointery $w]-[winfo reqheight $w]/2}]
  83. } else {
  84.     set x [winfo pointerx $w]
  85.     set y [winfo pointery $w]
  86. }
  87.     } elseif {[string equal -length $place_len $place "widget"] && 
  88.     [winfo exists $anchor] && [winfo ismapped $anchor]} {
  89. ## center about WIDGET $anchor, widget must be mapped
  90. set x [expr {[winfo rootx $anchor] + 
  91. ([winfo width $anchor]-[winfo reqwidth $w])/2}]
  92. set y [expr {[winfo rooty $anchor] + 
  93. ([winfo height $anchor]-[winfo reqheight $w])/2}]
  94.     } else {
  95. set x [expr {([winfo screenwidth $w]-[winfo reqwidth $w])/2}]
  96. set y [expr {([winfo screenheight $w]-[winfo reqheight $w])/2}]
  97. set checkBounds 0
  98.     }
  99.     set windowingsystem [tk windowingsystem]
  100.     if {$windowingsystem eq "win32"} {
  101.         # Bug 533519: win32 multiple desktops may produce negative geometry.
  102.         set checkBounds 0
  103.     }
  104.     if {$checkBounds} {
  105. if {$x < 0} {
  106.     set x 0
  107. } elseif {$x > ([winfo screenwidth $w]-[winfo reqwidth $w])} {
  108.     set x [expr {[winfo screenwidth $w]-[winfo reqwidth $w]}]
  109. }
  110. if {$y < 0} {
  111.     set y 0
  112. } elseif {$y > ([winfo screenheight $w]-[winfo reqheight $w])} {
  113.     set y [expr {[winfo screenheight $w]-[winfo reqheight $w]}]
  114. }
  115. if {$windowingsystem eq "classic" || $windowingsystem eq "aqua"} {
  116.     # Avoid the native menu bar which sits on top of everything.
  117.     if {$y < 22} { set y 22 }
  118. }
  119.     }
  120.     wm geometry $w +$x+$y
  121.     wm deiconify $w
  122. }
  123. # ::tk::SetFocusGrab --
  124. #   swap out current focus and grab temporarily (for dialogs)
  125. # Arguments:
  126. #   grab new window to grab
  127. #   focus window to give focus to
  128. # Results:
  129. #   Returns nothing
  130. #
  131. proc ::tk::SetFocusGrab {grab {focus {}}} {
  132.     set index "$grab,$focus"
  133.     upvar ::tk::FocusGrab($index) data
  134.     lappend data [focus]
  135.     set oldGrab [grab current $grab]
  136.     lappend data $oldGrab
  137.     if {[winfo exists $oldGrab]} {
  138. lappend data [grab status $oldGrab]
  139.     }
  140.     # The "grab" command will fail if another application
  141.     # already holds the grab.  So catch it.
  142.     catch {grab $grab}
  143.     if {[winfo exists $focus]} {
  144. focus $focus
  145.     }
  146. }
  147. # ::tk::RestoreFocusGrab --
  148. #   restore old focus and grab (for dialogs)
  149. # Arguments:
  150. #   grab window that had taken grab
  151. #   focus window that had taken focus
  152. #   destroy destroy|withdraw - how to handle the old grabbed window
  153. # Results:
  154. #   Returns nothing
  155. #
  156. proc ::tk::RestoreFocusGrab {grab focus {destroy destroy}} {
  157.     set index "$grab,$focus"
  158.     if {[info exists ::tk::FocusGrab($index)]} {
  159. foreach {oldFocus oldGrab oldStatus} $::tk::FocusGrab($index) { break }
  160. unset ::tk::FocusGrab($index)
  161.     } else {
  162. set oldGrab ""
  163.     }
  164.     catch {focus $oldFocus}
  165.     grab release $grab
  166.     if {$destroy eq "withdraw"} {
  167. wm withdraw $grab
  168.     } else {
  169. destroy $grab
  170.     }
  171.     if {[winfo exists $oldGrab] && [winfo ismapped $oldGrab]} {
  172. if {$oldStatus eq "global"} {
  173.     grab -global $oldGrab
  174. } else {
  175.     grab $oldGrab
  176. }
  177.     }
  178. }
  179. # ::tk::GetSelection --
  180. #   This tries to obtain the default selection.  On Unix, we first try
  181. #   and get a UTF8_STRING, a type supported by modern Unix apps for
  182. #   passing Unicode data safely.  We fall back on the default STRING
  183. #   type otherwise.  On Windows, only the STRING type is necessary.
  184. # Arguments:
  185. #   w The widget for which the selection will be retrieved.
  186. # Important for the -displayof property.
  187. #   sel The source of the selection (PRIMARY or CLIPBOARD)
  188. # Results:
  189. #   Returns the selection, or an error if none could be found
  190. #
  191. if {$tcl_platform(platform) eq "unix"} {
  192.     proc ::tk::GetSelection {w {sel PRIMARY}} {
  193. if {[catch {selection get -displayof $w -selection $sel 
  194. -type UTF8_STRING} txt] 
  195. && [catch {selection get -displayof $w -selection $sel} txt]} {
  196.     return -code error "could not find default selection"
  197. } else {
  198.     return $txt
  199. }
  200.     }
  201. } else {
  202.     proc ::tk::GetSelection {w {sel PRIMARY}} {
  203. if {[catch {selection get -displayof $w -selection $sel} txt]} {
  204.     return -code error "could not find default selection"
  205. } else {
  206.     return $txt
  207. }
  208.     }
  209. }
  210. # ::tk::ScreenChanged --
  211. # This procedure is invoked by the binding mechanism whenever the
  212. # "current" screen is changing.  The procedure does two things.
  213. # First, it uses "upvar" to make variable "::tk::Priv" point at an
  214. # array variable that holds state for the current display.  Second,
  215. # it initializes the array if it didn't already exist.
  216. #
  217. # Arguments:
  218. # screen - The name of the new screen.
  219. proc ::tk::ScreenChanged screen {
  220.     set x [string last . $screen]
  221.     if {$x > 0} {
  222. set disp [string range $screen 0 [expr {$x - 1}]]
  223.     } else {
  224. set disp $screen
  225.     }
  226.     uplevel #0 upvar #0 ::tk::Priv.$disp ::tk::Priv
  227.     variable ::tk::Priv
  228.     global tcl_platform
  229.     if {[info exists Priv]} {
  230. set Priv(screen) $screen
  231. return
  232.     }
  233.     array set Priv {
  234. activeMenu {}
  235. activeItem {}
  236. afterId {}
  237. buttons 0
  238. buttonWindow {}
  239. dragging 0
  240. focus {}
  241. grab {}
  242. initPos {}
  243. inMenubutton {}
  244. listboxPrev {}
  245. menuBar {}
  246. mouseMoved 0
  247. oldGrab {}
  248. popup {}
  249. postedMb {}
  250. pressX 0
  251. pressY 0
  252. prevPos 0
  253. selectMode char
  254.     }
  255.     set Priv(screen) $screen
  256.     set Priv(tearoff) [string equal [tk windowingsystem] "x11"]
  257.     set Priv(window) {}
  258. }
  259. # Do initial setup for Priv, so that it is always bound to something
  260. # (otherwise, if someone references it, it may get set to a non-upvar-ed
  261. # value, which will cause trouble later).
  262. tk::ScreenChanged [winfo screen .]
  263. # ::tk::EventMotifBindings --
  264. # This procedure is invoked as a trace whenever ::tk_strictMotif is
  265. # changed.  It is used to turn on or turn off the motif virtual
  266. # bindings.
  267. #
  268. # Arguments:
  269. # n1 - the name of the variable being changed ("::tk_strictMotif").
  270. proc ::tk::EventMotifBindings {n1 dummy dummy} {
  271.     upvar $n1 name
  272.     
  273.     if {$name} {
  274. set op delete
  275.     } else {
  276. set op add
  277.     }
  278.     event $op <<Cut>> <Control-Key-w>
  279.     event $op <<Copy>> <Meta-Key-w> 
  280.     event $op <<Paste>> <Control-Key-y>
  281.     event $op <<Undo>> <Control-underscore>
  282. }
  283. #----------------------------------------------------------------------
  284. # Define common dialogs on platforms where they are not implemented 
  285. # using compiled code.
  286. #----------------------------------------------------------------------
  287. if {[info commands tk_chooseColor] eq ""} {
  288.     proc ::tk_chooseColor {args} {
  289. return [eval tk::dialog::color:: $args]
  290.     }
  291. }
  292. if {[info commands tk_getOpenFile] eq ""} {
  293.     proc ::tk_getOpenFile {args} {
  294. if {$::tk_strictMotif} {
  295.     return [eval tk::MotifFDialog open $args]
  296. } else {
  297.     return [eval ::tk::dialog::file:: open $args]
  298. }
  299.     }
  300. }
  301. if {[info commands tk_getSaveFile] eq ""} {
  302.     proc ::tk_getSaveFile {args} {
  303. if {$::tk_strictMotif} {
  304.     return [eval tk::MotifFDialog save $args]
  305. } else {
  306.     return [eval ::tk::dialog::file:: save $args]
  307. }
  308.     }
  309. }
  310. if {[info commands tk_messageBox] eq ""} {
  311.     proc ::tk_messageBox {args} {
  312. return [eval tk::MessageBox $args]
  313.     }
  314. }
  315. if {[info command tk_chooseDirectory] eq ""} {
  316.     proc ::tk_chooseDirectory {args} {
  317. return [eval ::tk::dialog::file::chooseDir:: $args]
  318.     }
  319. }
  320. #----------------------------------------------------------------------
  321. # Define the set of common virtual events.
  322. #----------------------------------------------------------------------
  323. switch [tk windowingsystem] {
  324.     "x11" {
  325. event add <<Cut>> <Control-Key-x> <Key-F20> 
  326. event add <<Copy>> <Control-Key-c> <Key-F16>
  327. event add <<Paste>> <Control-Key-v> <Key-F18>
  328. event add <<PasteSelection>> <ButtonRelease-2>
  329. event add <<Undo>> <Control-Key-z>
  330. event add <<Redo>> <Control-Key-Z>
  331. # Some OS's define a goofy (as in, not <Shift-Tab>) keysym
  332. # that is returned when the user presses <Shift-Tab>.  In order for
  333. # tab traversal to work, we have to add these keysyms to the 
  334. # PrevWindow event.
  335. # We use catch just in case the keysym isn't recognized.
  336. # This is needed for XFree86 systems
  337. catch { event add <<PrevWindow>> <ISO_Left_Tab> }
  338. # This seems to be correct on *some* HP systems.
  339. catch { event add <<PrevWindow>> <hpBackTab> }
  340. trace add variable ::tk_strictMotif write ::tk::EventMotifBindings
  341. set ::tk_strictMotif $::tk_strictMotif
  342. # On unix, we want to always display entry/text selection,
  343. # regardless of which window has focus
  344. set ::tk::AlwaysShowSelection 1
  345.     }
  346.     "win32" {
  347. event add <<Cut>> <Control-Key-x> <Shift-Key-Delete>
  348. event add <<Copy>> <Control-Key-c> <Control-Key-Insert>
  349. event add <<Paste>> <Control-Key-v> <Shift-Key-Insert>
  350. event add <<PasteSelection>> <ButtonRelease-2>
  351.    event add <<Undo>> <Control-Key-z>
  352. event add <<Redo>> <Control-Key-y>
  353.     }
  354.     "aqua" {
  355. event add <<Cut>> <Command-Key-x> <Key-F2> 
  356. event add <<Copy>> <Command-Key-c> <Key-F3>
  357. event add <<Paste>> <Command-Key-v> <Key-F4>
  358. event add <<PasteSelection>> <ButtonRelease-2>
  359. event add <<Clear>> <Clear>
  360.    event add <<Undo>> <Command-Key-z>
  361. event add <<Redo>> <Command-Key-y>
  362.     }
  363.     "classic" {
  364. event add <<Cut>> <Control-Key-x> <Key-F2> 
  365. event add <<Copy>> <Control-Key-c> <Key-F3>
  366. event add <<Paste>> <Control-Key-v> <Key-F4>
  367. event add <<PasteSelection>> <ButtonRelease-2>
  368. event add <<Clear>> <Clear>
  369. event add <<Undo>> <Control-Key-z> <Key-F1>
  370. event add <<Redo>> <Control-Key-Z>
  371.     }
  372. }
  373. # ----------------------------------------------------------------------
  374. # Read in files that define all of the class bindings.
  375. # ----------------------------------------------------------------------
  376. if {$::tk_library ne ""} {
  377.     if {$tcl_platform(platform) eq "macintosh"} {
  378. proc ::tk::SourceLibFile {file} {
  379.     if {[catch {
  380. namespace eval :: 
  381. [list source [file join $::tk_library $file.tcl]]
  382.     }]} {
  383. namespace eval :: [list source -rsrc $file]
  384.     }
  385. }
  386.     } else {
  387. proc ::tk::SourceLibFile {file} {
  388.     namespace eval :: [list source [file join $::tk_library $file.tcl]]
  389. }
  390.     }
  391.     namespace eval ::tk {
  392. SourceLibFile button
  393. SourceLibFile entry
  394. SourceLibFile listbox
  395. SourceLibFile menu
  396. SourceLibFile panedwindow
  397. SourceLibFile scale
  398. SourceLibFile scrlbar
  399. SourceLibFile spinbox
  400. SourceLibFile text
  401.     }
  402. }
  403. # ----------------------------------------------------------------------
  404. # Default bindings for keyboard traversal.
  405. # ----------------------------------------------------------------------
  406. event add <<PrevWindow>> <Shift-Tab>
  407. bind all <Tab> {tk::TabToWindow [tk_focusNext %W]}
  408. bind all <<PrevWindow>> {tk::TabToWindow [tk_focusPrev %W]}
  409. # ::tk::CancelRepeat --
  410. # This procedure is invoked to cancel an auto-repeat action described
  411. # by ::tk::Priv(afterId).  It's used by several widgets to auto-scroll
  412. # the widget when the mouse is dragged out of the widget with a
  413. # button pressed.
  414. #
  415. # Arguments:
  416. # None.
  417. proc ::tk::CancelRepeat {} {
  418.     variable ::tk::Priv
  419.     after cancel $Priv(afterId)
  420.     set Priv(afterId) {}
  421. }
  422. # ::tk::TabToWindow --
  423. # This procedure moves the focus to the given widget.  If the widget
  424. # is an entry or a spinbox, it selects the entire contents of the widget.
  425. #
  426. # Arguments:
  427. # w - Window to which focus should be set.
  428. proc ::tk::TabToWindow {w} {
  429.     set wclass [winfo class $w]
  430.     if {$wclass eq "Entry" || $wclass eq "Spinbox"} {
  431. $w selection range 0 end
  432. $w icursor end
  433.     }
  434.     focus $w
  435. }
  436. # ::tk::UnderlineAmpersand --
  437. # This procedure takes some text with ampersand and returns
  438. # text w/o ampersand and position of the ampersand.
  439. # Double ampersands are converted to single ones.
  440. # Position returned is -1 when there is no ampersand.
  441. #
  442. proc ::tk::UnderlineAmpersand {text} {
  443.     set idx [string first "&" $text]
  444.     if {$idx >= 0} {
  445. set underline $idx
  446. # ignore "&&"
  447. while {[string match "&" [string index $text [expr {$idx + 1}]]]} {
  448.     set base [expr {$idx + 2}]
  449.     set idx  [string first "&" [string range $text $base end]]
  450.     if {$idx < 0} {
  451. break
  452.     } else {
  453. set underline [expr {$underline + $idx + 1}]
  454. incr idx $base
  455.     }
  456. }
  457.     }
  458.     if {$idx >= 0} {
  459. regsub -all -- {&([^&])} $text {1} text
  460.     } 
  461.     return [list $text $idx]
  462. }
  463. # ::tk::SetAmpText -- 
  464. # Given widget path and text with "magic ampersands",
  465. # sets -text and -underline options for the widget
  466. #
  467. proc ::tk::SetAmpText {widget text} {
  468.     foreach {newtext under} [::tk::UnderlineAmpersand $text] {
  469. $widget configure -text $newtext -underline $under
  470.     }
  471. }
  472. # ::tk::AmpWidget --
  473. # Creates new widget, turning -text option into -text and
  474. # -underline options, returned by ::tk::UnderlineAmpersand.
  475. #
  476. proc ::tk::AmpWidget {class path args} {
  477.     set wcmd [list $class $path]
  478.     foreach {opt val} $args {
  479. if {$opt eq "-text"} {
  480.     foreach {newtext under} [::tk::UnderlineAmpersand $val] {
  481. lappend wcmd -text $newtext -underline $under
  482.     }
  483. } else {
  484.     lappend wcmd $opt $val
  485. }
  486.     }
  487.     eval $wcmd
  488.     if {$class eq "button"} {
  489. bind $path <<AltUnderlined>> [list $path invoke]
  490.     }
  491.     return $path
  492. }
  493. # ::tk::FindAltKeyTarget --
  494. # search recursively through the hierarchy of visible widgets
  495. # to find button or label which has $char as underlined character
  496. #
  497. proc ::tk::FindAltKeyTarget {path char} {
  498.     switch [winfo class $path] {
  499. Button -
  500. Label {
  501.     if {[string equal -nocase $char 
  502. [string index [$path cget -text] 
  503. [$path cget -underline]]]} {return $path} else {return {}}
  504. }
  505. default {
  506.     foreach child 
  507. [concat [grid slaves $path] 
  508. [pack slaves $path] 
  509. [place slaves $path] ] {
  510. if {"" ne [set target [::tk::FindAltKeyTarget $child $char]]} {
  511.     return $target
  512. }
  513.     }
  514. }
  515.     }
  516.     return {}
  517. }
  518. # ::tk::AltKeyInDialog --
  519. # <Alt-Key> event handler for standard dialogs. Sends <<AltUnderlined>>
  520. # to button or label which has appropriate underlined character
  521. #
  522. proc ::tk::AltKeyInDialog {path key} {
  523.     set target [::tk::FindAltKeyTarget $path $key]
  524.     if { $target eq ""} return
  525.     event generate $target <<AltUnderlined>>
  526. }
  527. # ::tk::mcmaxamp --
  528. # Replacement for mcmax, used for texts with "magic ampersand" in it.
  529. #
  530. proc ::tk::mcmaxamp {args} {
  531.     set maxlen 0
  532.     foreach arg $args {
  533. set length [string length [lindex [::tk::UnderlineAmpersand [mc $arg]] 0]]
  534. if {$length>$maxlen} {
  535.     set maxlen $length
  536. }
  537.     }
  538.     return $maxlen
  539. }
  540. # For now, turn off the custom mdef proc for the mac:
  541. if {[tk windowingsystem] eq "aqua"} {
  542.     namespace eval ::tk::mac {
  543. set useCustomMDEF 0
  544.     }
  545. }