Gotcha's in Converting tcl/tk 3.6 to 4.0 James F. Carter , 950602 This is a report of issues I have encountered during about two weeks of converting tcl/tk 3.6 scripts to 4.0b3. I don't represent that all important issues are covered; these are just the ones I've broken teeth on. The URL for this document is http://www.math.ucla.edu/~jimc/tclconv; if I find any more interesting issues I'll expand the document. Bug reports have been posted for bugs mentioned. All of the mentioned bugs have been fixed in (or before) 4.0p2. Motif Borders: There is a new feature in the user interface: following the Motif look-and-feel standard, there is a border, in the default tan background color, around every widget which can credibly take the keyboard focus. Upon keyboard traversal (with Tab and Shift-Tab, as in Microsoft Windows, which is the prototype Motif system), the input focus changes forward and backward in the widget list and the border is drawn in black. By default a widget is eligible to get the input focus if it has any key bindings, is mapped, and is not disabled. The following options control keyboard traversal and borders. highlightBackground Color of non-focused border highlightColor Color of border when widget has focus highlightThickness Width of border. Set to 0 to omit border. -takefocus 1 means widget is eligible, 0 means it isn't, {} (the default) means use the above rule. A decision subroutine can also be specified. While you can say "scale .scl -highlightbackground PeachPuff3", the command line names are recognized by only some of the widgets; specifically, buttons do not recognize them. Probably this is an incompleteness and will be fixed in a later beta version. However, all widgets including buttons recognize the option database names as given above. Here is the command to set a color: option add *highlightBackground PeachPuff3 widgetDefault Note the star. The fifth parameter lets a user override. The following widgets formerly recognized the -geometry parameter but now do not, requiring separate -width and -height parameters like most widgets: listbox (formerly didn't recognize -height, -width) frame (recognized either) toplevel (recognized either) Button command: Buttons are bigger: the default internal padding is 1m (millimeter) vertically and 3m horizontally compared to 1 (pixel) in tk3.6. If your interface design depends on closely packed buttons, specify -padx and -pady explicitly, or add padX and padY to the option database. (Example in next section.) Menubutton gotcha: The appearance and geometry of the menubutton is different from a regular button. It was that way in tk3.6, but the difference is more in tk4.0. Here's an example that makes them most closely the same size. It would be nice to be able to pack both kinds of buttons together and have them look uniform. option add *highlightThickness 0 widgetDefault option add *padX 2 widgetDefault option add *padY 2 widgetDefault button .b1 -text B-1 pack .b1 -side left menubutton .b2 -text B-2 -relief raised -borderwidth 3 pack .b2 -side left The following was observed with a menubutton but is probably more general. If an event is bound to a command that destroys the toplevel window, a event for leaving the menubutton may sometimes be processed after the window is destroyed, causing at best "no such command", or at worst a segmentation fault. This is almost certainly a bug in 4.0b3. It appears to be fixed in 4.0p2 or earlier. Scales and scrollbars have a new, more consistent terminology for colors. OLD NEW Semantics activeforeground activebackground Color of active unit when focus is in it. (Old scale: when focus is anywhere in the scale) background (same) Old: background of trough and annot- ations. New: annotations, slider, arrows but not trough. foreground (same) Color of text annotations, if any. sliderforeground (use background) Slider color without focus (scale only). (none) troughcolor Color of trough. Scales have been upgraded but are mostly downward compatible. 1. All scale coordinates (-from, -to and the value argument of the -command) are real numbers, i.e. with a decimal point, provided that -resolution is specified and is other than an integer. 2. There is a new -variable option analogous to -textvariable of other widgets. It is set when the scale changes, and the scale changes when it is set. 3. See the new widget subcommands coords and identify, which relate screen coordinates and scale values or geometry. 4. Mouse and keyboard actions are more logical. Button 1 in the trough moves the value by one resolution unit. Formerly it moved the slider to the mouse, and the keyboard did nothing. Scrollbars interact with scrolled widgets using a different syntax; however, the old style will still work, though deprecated. 1. [.sbar set $first $last] (2 decimal fractions) means that the top and bottom of the visible data is at these fractions of the whole. The old syntax of [sbar set $whole $visible $top $bottom] still works. 2. The controlled widget, if it gives new-style set commands, should expect to get some new-style yview commands back. See the docs for details. The builtin widgets have this all coordinated. 3. [.sbar get] returns the arguments given to the most recent [.sbar set] command -- most likely new style, if the scrollbar controls a builtin widget such as text or listbox. If your program does [.sbar get] you need to deal with new-style results. 4. For the text widget, the new bbox subcommand gives you the screen coordinates of an index such as the insertion cursor (if on-screen). From this you can do many things that formerly required [.sbar get]. Listboxes: 1. While formerly they required -geometry ${width}x${height}, now they require separate -width and -height arguments. 2. Programmatic setting of the selection has been updated. Here are approximate correspondences; you'll have to read the man page for exactly how to use the new features. $lbox select from $index $lbox selection anchor $index $lbox select clear $lbox selection clear $first $last --- $lbox selection includes $index $lbox select to $index $lbox selection set $first $last $lbox select adjust $index --- Entry widget: 1. The view subcommand has changed to xview. 2. There's a new mouse binding: button 2 up (without motion) inserts the selection. If you provided this binding yourself you may get double insertion. 3. ^U no longer clears the entry. The default clear key is ctrl-\ according to the man page but it does nothing. ^A^K will do it. Text widget: 1. A line exactly as wide as the text widget will be wrapped with the newline on the next line (and nothing else). This is a bug in 4.0b3 and was fixed at or before 4.0p2. 2. There's a spiffy generalized tab stop feature, and a lot of new functionality. As far as I can see, all (except as noted) is downward compatible. See espectially the new search subcommand. 3. There's a new mouse binding: button 2 up (without motion) inserts the selection. If you provided this binding yourself you may get double insertion. 4. [.txt mark set insert end] puts the insert cursor on an invisible character (newline?) after the last visible character, i.e. the cursor becomes invisible. This is a bug in 4.0b3 and was fixed at or before 4.0p2. If you do [.text get 1.0 end] you will get the ending newline (which you did not put in) -- bug or feature, this is still the case in 4.0p2. 5. The new bbox subcommand returns {} when the mark is at column 0, and strange character widths when it's before a tab or newline. These are bugs and are fixed in 4.0p2. Bind command: Formerly, on Linux with a PC keyboard, or presumably a Sun type 4 or 5, included "alt" keys. In tk4.0 the meta and alt keys are carefully distinguished and your bindings to are ignored. To remedy this problem you need to do this (or include in your xmodmap input file): xmodmap -e "keysym Alt_L = Meta_L Alt_L" -e "keysym Alt_R = Meta_R Alt_R" This is a problem in 4.0b3, fixed in 4.0p2 or before: User-provided class bindings for builtin widgets are overwritten. Formerly many widget event bindings were to internal subroutines; now actual tcl scripts are used. tk.tcl initially does roughly the equivalent of this: foreach class {Text Button lots of other widgets} { bind $class "tk${class}Bind Enter" bind $class "tk${class}Bind FocusIn" } where tk${class}Bind is defined in library/$class.tcl (e.g. text.tcl). That subroutine installs the real class bindings upon the first Enter or FocusIn event. If you set your own class bindings, you certainly do it before the first Enter or FocusIn event, and your bindings will be overwritten. You must do more or less the following, before the first binding is set: tkScreenChanged [winfo screen .] ;#Set up tkPriv for all classes tkTextBind Enter ;#Arg ignored, comments lie. You need only one tkScreenChanged, but you must do tk${class}Bind for each class that you set class bindings on. This entanglement with private code is yucky and has been reported as a bug. It was fixed in or before 4.0p2. In a few beta releases including 4.0b3, class bindings were performed before individual widget bindings. In the production release the individual binding has priority over the class binding, as it was in tk3.6. A binding to an event with zero or more modifiers will match an event with additional unspecified modifiers; in tk3.6 was needed to get that effect. is deprecated and will be ignored silently. However, if several bindings match (e.g. you bind and , and press ) only one will be executed per level (see the man page for bind). But (gotcha), different bindings at other levels can be executed, such as an unmodified binding (see next section). If you bind to (or with Meta or Shift), there is an "all" binding to take the focus from one widget to the next. First your subroutine will be executed, and then the focus will go off your widget due to the keyboard traversal binding. You need to either remove the keyboard traversal binding or let "break" be the last command of your binding. But tk3.6 does not like breaks outside of loops. Most portable (but most destructive) is to remove the "all" binding, since tk3.6 knows about "all". Conditionalizing the script is a bit tricky; the syntax depends on the context where the script is bound. This example sets a mark which is moved to when the user presses a specified key with . if {[string compare $tk_version 4.0] >= 0} { set break4 {break} #tk4.0 version } else { set break4 {} #tk3.6 version, do not break } proc marks_set {viet j} { #$viet is the text widget global break4 $viet mark set umark$j insert #If the command is quoted: bind $viet "motion $viet umark$j ; eval \{$break4\}" #If the command is in braces: bind $viet {motion %W umark3 ; eval $break4} #I never figured out how to do it with [list xxx]. } Global focus: In tk3.6, "focus $window" attracts the keyboard focus to the tk application, and sets internal distribution to $window. In tk4.0 the keyboard focus comes to the tk app only if the window manager deigns to give it. Example: in Motif, if the user clicks in the app. But there is an option to unilaterally take focus: "focus -force $window". However, it does not take focus to a window with overrideredirect set. This behavior may (or may not) be new in tk4.0. Make the window transient first, execute "update" to map it, focus on it (you can't focus on a non-mapped window), then overrideredirect. Colormodel: In tk3.6 the command [tk colormodel $window] would return "color" or "monochrome". This support is cancelled. You instead need to do [string match "*color*" [winfo visual $window]]