focus.tcl 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. # focus.tcl --
  2. #
  3. # This file defines several procedures for managing the input
  4. # focus.
  5. #
  6. # Copyright (c) 1994-1995 Sun Microsystems, Inc.
  7. #
  8. # See the file "license.terms" for information on usage and redistribution
  9. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10. #
  11. # ::tk_focusNext --
  12. # This procedure returns the name of the next window after "w" in
  13. # "focus order" (the window that should receive the focus next if
  14. # Tab is typed in w). "Next" is defined by a pre-order search
  15. # of a top-level and its non-top-level descendants, with the stacking
  16. # order determining the order of siblings. The "-takefocus" options
  17. # on windows determine whether or not they should be skipped.
  18. #
  19. # Arguments:
  20. # w - Name of a window.
  21. proc ::tk_focusNext w {
  22. set cur $w
  23. while {1} {
  24. # Descend to just before the first child of the current widget.
  25. set parent $cur
  26. set children [winfo children $cur]
  27. set i -1
  28. # Look for the next sibling that isn't a top-level.
  29. while {1} {
  30. incr i
  31. if {$i < [llength $children]} {
  32. set cur [lindex $children $i]
  33. if {[winfo toplevel $cur] eq $cur} {
  34. continue
  35. } else {
  36. break
  37. }
  38. }
  39. # No more siblings, so go to the current widget's parent.
  40. # If it's a top-level, break out of the loop, otherwise
  41. # look for its next sibling.
  42. set cur $parent
  43. if {[winfo toplevel $cur] eq $cur} {
  44. break
  45. }
  46. set parent [winfo parent $parent]
  47. set children [winfo children $parent]
  48. set i [lsearch -exact $children $cur]
  49. }
  50. if {$w eq $cur || [tk::FocusOK $cur]} {
  51. return $cur
  52. }
  53. }
  54. }
  55. # ::tk_focusPrev --
  56. # This procedure returns the name of the previous window before "w" in
  57. # "focus order" (the window that should receive the focus next if
  58. # Shift-Tab is typed in w). "Next" is defined by a pre-order search
  59. # of a top-level and its non-top-level descendants, with the stacking
  60. # order determining the order of siblings. The "-takefocus" options
  61. # on windows determine whether or not they should be skipped.
  62. #
  63. # Arguments:
  64. # w - Name of a window.
  65. proc ::tk_focusPrev w {
  66. set cur $w
  67. while {1} {
  68. # Collect information about the current window's position
  69. # among its siblings. Also, if the window is a top-level,
  70. # then reposition to just after the last child of the window.
  71. if {[winfo toplevel $cur] eq $cur} {
  72. set parent $cur
  73. set children [winfo children $cur]
  74. set i [llength $children]
  75. } else {
  76. set parent [winfo parent $cur]
  77. set children [winfo children $parent]
  78. set i [lsearch -exact $children $cur]
  79. }
  80. # Go to the previous sibling, then descend to its last descendant
  81. # (highest in stacking order. While doing this, ignore top-levels
  82. # and their descendants. When we run out of descendants, go up
  83. # one level to the parent.
  84. while {$i > 0} {
  85. incr i -1
  86. set cur [lindex $children $i]
  87. if {[winfo toplevel $cur] eq $cur} {
  88. continue
  89. }
  90. set parent $cur
  91. set children [winfo children $parent]
  92. set i [llength $children]
  93. }
  94. set cur $parent
  95. if {$w eq $cur || [tk::FocusOK $cur]} {
  96. return $cur
  97. }
  98. }
  99. }
  100. # ::tk::FocusOK --
  101. #
  102. # This procedure is invoked to decide whether or not to focus on
  103. # a given window. It returns 1 if it's OK to focus on the window,
  104. # 0 if it's not OK. The code first checks whether the window is
  105. # viewable. If not, then it never focuses on the window. Then it
  106. # checks the -takefocus option for the window and uses it if it's
  107. # set. If there's no -takefocus option, the procedure checks to
  108. # see if (a) the widget isn't disabled, and (b) it has some key
  109. # bindings. If all of these are true, then 1 is returned.
  110. #
  111. # Arguments:
  112. # w - Name of a window.
  113. proc ::tk::FocusOK w {
  114. set code [catch {$w cget -takefocus} value]
  115. if {($code == 0) && ($value ne "")} {
  116. if {$value == 0} {
  117. return 0
  118. } elseif {$value == 1} {
  119. return [winfo viewable $w]
  120. } else {
  121. set value [uplevel #0 $value [list $w]]
  122. if {$value ne ""} {
  123. return $value
  124. }
  125. }
  126. }
  127. if {![winfo viewable $w]} {
  128. return 0
  129. }
  130. set code [catch {$w cget -state} value]
  131. if {($code == 0) && $value eq "disabled"} {
  132. return 0
  133. }
  134. regexp Key|Focus "[bind $w] [bind [winfo class $w]]"
  135. }
  136. # ::tk_focusFollowsMouse --
  137. #
  138. # If this procedure is invoked, Tk will enter "focus-follows-mouse"
  139. # mode, where the focus is always on whatever window contains the
  140. # mouse. If this procedure isn't invoked, then the user typically
  141. # has to click on a window to give it the focus.
  142. #
  143. # Arguments:
  144. # None.
  145. proc ::tk_focusFollowsMouse {} {
  146. set old [bind all <Enter>]
  147. set script {
  148. if {"%d" eq "NotifyAncestor" || "%d" eq "NotifyNonlinear" \
  149. || "%d" eq "NotifyInferior"} {
  150. if {[tk::FocusOK %W]} {
  151. focus %W
  152. }
  153. }
  154. }
  155. if {$old ne ""} {
  156. bind all <Enter> "$old; $script"
  157. } else {
  158. bind all <Enter> $script
  159. }
  160. }