1 # Variable display window for GDBtk.
2 # Copyright 1997, 1998, 1999 Cygnus Solutions
4 # This program is free software; you can redistribute it and/or modify it
5 # under the terms of the GNU General Public License (GPL) as published by
6 # the Free Software Foundation; either version 2 of the License, or (at
7 # your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
15 # ----------------------------------------------------------------------
16 # Implements variable windows for gdb. LocalsWin and WatchWin both
17 # inherit from this class. You need only override the method
18 # 'getVariablesBlankPath' and a few other things...
19 # ----------------------------------------------------------------------
22 inherit EmbeddedWin GDBWin
23 protected variable Sizebox 1
25 # ------------------------------------------------------------------
26 # CONSTRUCTOR - create new watch window
27 # ------------------------------------------------------------------
30 # Create a window with the same name as this object
33 set _queue [Queue \#auto]
34 build_win $itk_interior
37 add_hook gdb_update_hook "$this update"
38 add_hook gdb_busy_hook "$this disable_ui"
39 add_hook gdb_no_inferior_hook "$this no_inferior"
40 add_hook gdb_idle_hook [list $this idle]
41 add_hook gdb_clear_file_hook [code $this clear_file]
44 # ------------------------------------------------------------------
45 # METHOD: build_win - build the watch window
46 # ------------------------------------------------------------------
47 method build_win {f} {
48 global tixOption tcl_platform Display
49 # debug "VariableWin::build_win"
50 set width [font measure src-font "W"]
51 # Choose the default width to be...
52 set width [expr {40 * $width}]
53 if {$tcl_platform(platform) == "windows"} {
60 set Tree [tixTree $f.tree \
61 -opencmd "$this open" \
62 -closecmd "$this close" \
65 -browsecmd [list $this selectionChanged] \
66 -scrollbar $scrollmode \
68 if {![pref get gdb/mode]} {
69 $Tree configure -command [list $this editEntry]
71 set Hlist [$Tree subwidget hlist]
73 # FIXME: probably should use columns instead.
74 $Hlist configure -header 1
76 set l [expr {$EntryLength - $Length - [string length "Name"]}]
77 # Ok, this is as hack as it gets
79 $Hlist header create 0 -itemtype text \
80 -text "Name[string range $blank 0 $l]Value"
82 # Configure the look of the tree
83 set sbg [$Hlist cget -bg]
84 set fg [$Hlist cget -fg]
85 set bg $tixOption(input1_bg)
86 set width [font measure src-font $LengthString]
87 $Hlist configure -indent $width -bg $bg \
88 -selectforeground $fg -selectbackground $sbg \
89 -selectborderwidth 0 -separator . -font src-font
92 set normal_fg [$Hlist cget -fg]
93 set highlight_fg [pref get gdb/variable/highlight_fg]
94 set disabled_fg [pref get gdb/variable/disabled_fg]
95 set NormalTextStyle [tixDisplayStyle text -refwindow $Hlist \
96 -bg $bg -fg $normal_fg -font src-font]
97 set HighlightTextStyle [tixDisplayStyle text -refwindow $Hlist \
98 -bg $bg -fg $highlight_fg -font src-font]
99 set DisabledTextStyle [tixDisplayStyle text -refwindow $Hlist \
100 -bg $bg -fg $disabled_fg -font src-font]
102 if {[catch {gdb_cmd "show output-radix"} msg]} {
105 regexp {[0-9]+} $msg Radix
109 # Update the tree display
111 pack $Tree -expand yes -fill both
113 # Create the popup menu for this widget
114 bind $Hlist <3> "$this postMenu %X %Y"
115 bind $Hlist <KeyPress-space> [code $this toggleView]
117 # Do not use the tixPopup widget...
118 set Popup [menu $f.menu -tearoff 0]
119 set disabled_foreground [$Popup cget -foreground]
120 $Popup configure -disabledforeground $disabled_foreground
121 set ViewMenu [menu $Popup.view]
123 # Populate the view menu
124 $ViewMenu add radiobutton -label "Hex" -variable Display($this) \
126 $ViewMenu add radiobutton -label "Decimal" -variable Display($this) \
128 $ViewMenu add radiobutton -label "Binary" -variable Display($this) \
130 $ViewMenu add radiobutton -label "Octal" -variable Display($this) \
132 $ViewMenu add radiobutton -label "Natural" -variable Display($this) \
135 $Popup add command -label "dummy" -state disabled
137 $Popup add cascade -label "Format" -menu $ViewMenu
138 # $Popup add checkbutton -label "Auto Update"
139 # $Popup add command -label "Update Now"
140 if {![pref get gdb/mode]} {
141 $Popup add command -label "Edit"
144 # Make sure to update menu info.
147 window_name "Local Variables" "Locals"
150 # ------------------------------------------------------------------
151 # DESTRUCTOR - destroy window containing widget
152 # ------------------------------------------------------------------
154 # debug "VariableWin::destructor"
155 # Make sure to clean up the frame
156 catch {destroy $_frame}
158 # Delete the display styles used with this window
159 destroy $NormalTextStyle
160 destroy $HighlightTextStyle
161 destroy $DisabledTextStyle
163 # Remove this window and all hooks
164 remove_hook gdb_update_hook "$this update"
165 remove_hook gdb_busy_hook "$this disable_ui"
166 remove_hook gdb_no_inferior_hook "$this no_inferior"
167 remove_hook gdb_idle_hook [list $this idle]
168 remove_hook gdb_clear_file_hook [code $this clear_file]
171 # ------------------------------------------------------------------
172 # METHOD: clear_file - Clear out state and prepare for loading
174 # ------------------------------------------------------------------
175 method clear_file {} {
179 # ------------------------------------------------------------------
180 # METHOD: reconfig - used when preferences change
181 # ------------------------------------------------------------------
183 # debug "VariableWin::reconfig"
184 foreach win [winfo children $itk_interior] {
188 build_win $itk_interior
191 # ------------------------------------------------------------------
192 # METHOD: build_menu_helper - Create the menu for a subclass.
193 # ------------------------------------------------------------------
194 method build_menu_helper {first} {
196 menu [namespace tail $this].mmenu
198 [namespace tail $this].mmenu add cascade -label $first -underline 0 -menu [namespace tail $this].mmenu.var
200 menu [namespace tail $this].mmenu.var
201 if {![pref get gdb/mode]} {
202 [namespace tail $this].mmenu.var add command -label Edit -underline 0 -state disabled \
204 %s editEntry [%s getSelection]
207 [namespace tail $this].mmenu.var add cascade -label Format -underline 0 \
208 -menu [namespace tail $this].mmenu.var.format
210 menu [namespace tail $this].mmenu.var.format
211 foreach label {Hex Decimal Binary Octal Natural} fmt {hexadecimal decimal binary octal natural} {
212 [namespace tail $this].mmenu.var.format add radiobutton \
213 -label $label -underline 0 \
214 -value $fmt -variable Display($this) \
216 %s setDisplay [%s getSelection] %s
220 # [namespace tail $this].mmenu add cascade -label Update -underline 0 -menu [namespace tail $this].mmenu.update
221 # menu [namespace tail $this].mmenu.update
223 # The -variable is set when a selection is made in the tree.
224 # [namespace tail $this].mmenu.update add checkbutton -label "Auto Update" -underline 0 \
226 # %s toggleUpdate [%s getSelection]
228 # [namespace tail $this].mmenu.update add command -label "Update Now" -underline 0 \
229 # -accelerator "Ctrl+U" -command [format {
230 # %s updateNow [%s getSelection]
233 set top [winfo toplevel [namespace tail $this]]
234 $top configure -menu [namespace tail $this].mmenu
235 bind_plain_key $top Control-u [format {
237 if {[%s getSelection] != ""} {
238 %s updateNow [%s getSelection]
243 return [namespace tail $this].mmenu.var
246 # Return the current selection, or the empty string if none.
247 method getSelection {} {
248 return [$Hlist info selection]
251 # This is called when a selection is made. It updates the main
253 method selectionChanged {variable} {
257 # Clear the selection, too
258 $Hlist selection clear
262 # if something is being edited, cancel it
263 if {[info exists EditEntry]} {
267 if {$variable == ""} {
273 foreach menu [list [namespace tail $this].mmenu.var [namespace tail $this].mmenu.var.format ] {
274 set i [$menu index last]
276 if {[$menu type $i] != "cascade"} {
277 $menu entryconfigure $i -state $state
283 if {$variable != "" && [$variable editable]} {
289 if {$variable != ""} {
290 set Display($this) [$variable format]
293 foreach label {Hex Decimal Binary Octal Natural} {
294 [namespace tail $this].mmenu.var.format entryconfigure $label
295 if {$label != "Hex"} {
296 [namespace tail $this].mmenu.var.format entryconfigure $label -state $state
299 # [namespace tail $this].mmenu.update entryconfigure 0 -variable Update($this,$name)
302 method updateNow {variable} {
303 # debug "VariableWin::updateNow $variable"
306 set text [label $variable]
307 $Hlist entryconfigure $variable -itemtype text -text $text
311 method getEntry {x y} {
312 set realY [expr {$y - [winfo rooty $Hlist]}]
314 # Get the tree entry which we are over
315 return [$Hlist nearest $realY]
318 method editEntry {variable} {
320 if {$variable != "" && [$variable editable]} {
326 method postMenu {X Y} {
327 global Update Display
328 # debug "VariableWin::postMenu"
330 # Quicky for menu posting problems.. How to unpost and post??
332 if {[winfo ismapped $Popup] || $Running} {
336 set variable [getEntry $X $Y]
337 if {[string length $variable] > 0} {
338 # Configure menu items
339 # the title is always first..
340 #set labelIndex [$Popup index "dummy"]
341 set viewIndex [$Popup index "Format"]
342 # set autoIndex [$Popup index "Auto Update"]
343 # set updateIndex [$Popup index "Update Now"]
344 set noEdit [catch {$Popup index "Edit"} editIndex]
346 # Retitle and set update commands
347 $Popup entryconfigure 0 -label "[$variable name]"
348 # $Popup entryconfigure $autoIndex -command "$this toggleUpdate \{$entry\}" \
349 -variable Update($this,$entry)
350 # $Popup entryconfigure $updateIndex -command "$this updateNow \{$entry\}"
353 if {$variable != "" && [$variable editable]} {
355 $Popup delete $editIndex
357 if {![pref get gdb/mode]} {
358 $Popup add command -label Edit -command "$this edit \{$variable\}"
362 $Popup delete $editIndex
367 set Display($this) [$variable format]
368 foreach i {0 1 2 3 4} fmt {hexadecimal decimal binary octal natural} {
369 debug "configuring entry $i ([$ViewMenu entrycget $i -label]) to $fmt"
370 $ViewMenu entryconfigure $i \
371 -command "$this setDisplay \{$variable\} $fmt"
374 tk_popup $Popup $X $Y
378 # ------------------------------------------------------------------
379 # METHOD edit -- edit a variable
380 # ------------------------------------------------------------------
381 method edit {variable} {
382 global Update tixOption
386 debug "editing \"$variable\""
388 set fg [$Hlist cget -foreground]
389 set bg [$Hlist cget -background]
391 if {$Editing == ""} {
392 # Must create the frame
393 set Editing [frame $Hlist.frame -bg $bg -bd 0 -relief flat]
394 set lbl [::label $Editing.lbl -fg $fg -bg $bg -font src-font]
395 set ent [entry $Editing.ent -bg $tixOption(bg) -font src-font]
396 pack $lbl $ent -side left
399 if {[info exists EditEntry]} {
400 # We already are editing something... So reinstall it first
401 # I guess we discard any changes?
405 # Update the label/entry widgets for this instance
406 set Update($this,$variable) 1
407 set EditEntry $variable
408 set label [label $variable 1]; # do not append value
409 $Editing.lbl configure -text "$label "
410 $Editing.ent delete 0 end
412 # Strip the pointer type, text, etc, from pointers, and such
413 set err [catch {$variable value} text]
415 if {[$variable format] == "natural"} {
416 # Natural formats must be stripped. They often contain
417 # things like strings and characters after them.
418 set index [string first \ $text]
420 set text [string range $text 0 [expr {$index - 1}]]
423 $Editing.ent insert 0 $text
425 # Find out what the previous entry is
426 set previous [getPrevious $variable]
429 $Hlist delete entry $variable
432 %s add {%s} %s -itemtype window -window %s \
433 } $Hlist $variable $previous $Editing]
436 if {[$variable numChildren] > 0} {
437 $Tree setmode $variable open
442 $Editing.ent selection to end
445 bind $Editing.ent <Return> "$this changeValue"
446 bind $Hlist <Return> "$this changeValue"
447 bind $Editing.ent <Escape> "$this UnEdit"
448 bind $Hlist <Escape> "$this UnEdit"
451 method getPrevious {variable} {
452 set prev [$Hlist info prev $variable]
453 set parent [$Hlist info parent $variable]
456 # A problem occurs with PREV if its parent is not the same as the entry's
457 # parent. For example, consider these variables in the window:
463 # if you attempt to edit "local", previous will be set at "bar.b", not
465 if {[$Hlist info parent $prev] != $parent} {
466 # This is the problem!
467 # Find this object's sibling in that parent and place it there.
468 set children [$Hlist info children $parent]
470 foreach child $children {
471 if {$child == $variable} {
478 # This is the topmost child
479 set previous "-before [lindex $children 1]"
481 set previous "-after $p"
484 set previous "-after \{$prev\}"
491 if {$prev == "$parent"} {
492 # This is the topmost-member of a sub-grouping..
500 set previous [getPrevious $EditEntry]
502 $Hlist delete entry $EditEntry
504 %s add {%s} %s -itemtype text -text {%s} \
505 } $Hlist $EditEntry $previous [label $EditEntry]]
507 if {[$EditEntry numChildren] > 0} {
508 $Tree setmode $EditEntry open
512 bind $Hlist <Return> {}
513 bind $Hlist <Escape> {}
514 if {$Editing != ""} {
515 bind $Editing.ent <Return> {}
516 bind $Editing.ent <Escape> {}
523 method changeValue {} {
525 set new [string trim [$Editing.ent get] \ \r\n]
531 if {[catch {$EditEntry value $new} errTxt]} {
532 tk_messageBox -icon error -type ok -message $errTxt \
533 -title "Error in Expression" -parent [winfo toplevel $itk_interior]
535 $Editing.ent selection to end
539 # Get rid of entry... and replace it with new value
545 # ------------------------------------------------------------------
546 # METHOD: toggleView: Toggle open/close the current selection.
547 # ------------------------------------------------------------------
548 method toggleView {} {
551 set mode [$Tree getmode $v]
553 # In the tixTree widget, "open" means "openable", not that it is open...
558 $Tree setmode $v close
563 $Tree setmode $v open
568 dbug E "What happened?"
573 method toggleUpdate {variable} {
576 if {$Update($this,$variable)} {
578 $Hlist entryconfigure $variable \
579 -style $NormalTextStyle \
580 -text [label $variable]
582 $Hlist entryconfigure $variable \
583 -style $DisabledTextStyle
588 method setDisplay {variable format} {
589 debug "$variable $format"
591 $variable format $format
592 set ::Display($this) $format
593 $Hlist entryconfigure $variable -text [label $variable]
597 # ------------------------------------------------------------------
598 # METHOD: label - used to label the entries in the tree
599 # ------------------------------------------------------------------
600 method label {variable {noValue 0}} {
601 # Ok, this is as hack as it gets
603 # Use protected data Length to determine how big variable
604 # name should be. This should clean the display up a little
605 set name [$variable name]
606 set indent [llength [split $variable .]]
607 set indent [expr {$indent * $Length}]
608 set len [string length $name]
609 set l [expr {$EntryLength - $len - $indent}]
610 set label "$name[string range $blank 0 $l]"
611 #debug "label=$label $noValue"
616 set err [catch {$variable value} value]
617 set value [string trim $value \ \r\t\n]
618 #debug "err=$err value=$value"
620 # Insert the variable's type for things like ptrs, etc.
621 set type [$variable type]
623 if {$value == "{...}"} {
624 set val " $type $value"
625 } elseif {[string first * $type] != -1} {
626 set val " ($type) $value"
627 } elseif {[string first \[ $type] != -1} {
639 # ------------------------------------------------------------------
640 # METHOD: open - used to open an entry in the variable tree
641 # ------------------------------------------------------------------
644 # We must lookup all the variables for this struct
645 # debug "VariableWin::open $path"
648 # Do not open disabled paths
649 if {$Update($this,$path)} {
655 $Tree setmode $path open
659 # ------------------------------------------------------------------
660 # METHOD: close - used to close an entry in the variable tree
661 # ------------------------------------------------------------------
662 method close {path} {
664 debug "VariableWin::close $path"
665 # Close the path and destroy all the entry widgets
668 if {[info exists EditEntry]} {
673 # Only update when we we are not disabled
674 if {$Update($this,$path)} {
676 # Delete the offspring of this entry
677 $Hlist delete offspring $path
680 $Tree setmode $path close
684 method isVariable {var} {
686 set err [catch {gdb_cmd "output $var"} msg]
688 || [regexp -nocase "no symbol|syntax error" $msg]} {
695 # OVERRIDE THIS METHOD
696 method getVariablesBlankPath {} {
697 debug "You forgot to override getVariablesBlankPath!!"
705 # ------------------------------------------------------------------
706 # METHOD: populate - populate an entry in the tree
707 # ------------------------------------------------------------------
708 method populate {parent} {
710 debug "VariableWin::populate \"$parent\""
712 if {[string length $parent] == 0} {
713 set variables [getVariablesBlankPath]
715 set variables [$parent children]
718 debug "variables=$variables"
719 eval $_queue push $variables
720 for {set variable [$_queue pop]} {$variable != ""} {set variable [$_queue pop]} {
721 debug "inserting variable: $variable"
722 set Update($this,$variable) 1
724 $Hlist add $variable \
726 -text [label $variable]
727 if {[$variable numChildren] > 0} {
728 # Make sure we get this labeled as openable
729 $Tree setmode $variable open
732 # Special case: If we see "public" with no value or type, then we
733 # have one of our special c++/java children. Open it automagically
735 if {[string compare [$variable name] "public"] == 0
736 && [$variable type] == "" && [$variable value] == ""} {
737 eval $_queue push [$variable children]
738 $Tree setmode $variable close
742 debug "done with populate"
745 # Get all current locals
749 set err [catch {gdb_get_args} v]
751 set vars [concat $vars $v]
754 set err [catch {gdb_get_locals} v]
756 set vars [concat $vars $v]
759 debug "--getLocals:\n$vars\n--getLocals"
763 method context_switch {} {
764 set err [catch {gdb_selected_frame} current_frame]
765 debug "1: err=$err; _frame=\"$_frame\"; current_frame=\"$current_frame\""
766 if {$err && $_frame != ""} {
768 debug "no current frame"
769 catch {destroy $_frame}
772 } elseif {$current_frame == "" && $_frame == ""} {
775 } elseif {$_frame == "" || $current_frame != [$_frame address]} {
776 # We've changed frames. If we knew something about
777 # the stack layout, we could be more intelligent about
778 # destroying variables, but we don't know that here (yet).
779 debug "switching to frame at $current_frame"
781 # Destroy the old frame and create the new one
782 catch {destroy $_frame}
783 set _frame [Frame ::\#auto $current_frame]
784 debug "created new frame: $_frame at [$_frame address]"
793 # OVERRIDE THIS METHOD and call it from there
796 debug "VariableWin::update"
798 # First, reset color on label to black
799 foreach w $ChangeList {
801 $Hlist entryconfigure $w -style $NormalTextStyle
805 # Tell toplevel variables to update themselves. This will
806 # give us a list of all the variables in the table that
807 # have changed values.
809 set variables [$Hlist info children {}]
810 foreach var $variables {
811 # debug "VARIABLE: $var ($Update($this,$var))"
812 set ChangeList [concat $ChangeList [$var update]]
815 foreach var $ChangeList {
816 $Hlist entryconfigure $var \
817 -style $HighlightTextStyle \
828 method displayedVariables {top} {
829 # debug "VariableWin::displayedVariables"
831 set variables [$Hlist info children $top]
832 foreach var $variables {
833 set mode [$Tree getmode $var]
834 if {$mode == "close"} {
835 set moreVars [displayedVariables $var]
836 lappend variableList [join $moreVars]
838 lappend variableList $var
841 return [join $variableList]
844 method deleteTree {} {
847 # debug "VariableWin::deleteTree"
848 # set variables [displayedVariables {}]
850 # Delete all HList entries
853 # Delete the variable objects
854 # foreach i [array names Variables] {
855 # $Variables($i) delete
856 # unset Variables($i)
857 # catch {unset Update($this,$i)}
861 # ------------------------------------------------------------------
863 # Enable all ui elements.
864 # ------------------------------------------------------------------
865 method enable_ui {} {
872 # ------------------------------------------------------------------
874 # Disable all ui elements that could affect gdb's state
875 # ------------------------------------------------------------------
876 method disable_ui {} {
882 if {[info exists EditEntry]} {
890 # ------------------------------------------------------------------
891 # METHOD: no_inferior
893 # ------------------------------------------------------------------
894 method no_inferior {} {
896 # Clear out the Hlist
905 # ------------------------------------------------------------------
906 # METHOD: cursor - change the toplevel's cursor
907 # ------------------------------------------------------------------
908 method cursor {what} {
909 [winfo toplevel [namespace tail $this]] configure -cursor $what
921 # the tixTree widget for this class
922 protected variable Tree {}
924 # the hlist of this widget
925 protected variable Hlist {}
927 # entry widgets which need to have their color changed back to black
928 # when idle (used in conjunction with update)
929 protected variable ChangeList {}
931 protected variable ViewMenu
932 protected variable Popup
934 # These are for setting the indent level to an number of characters.
935 # This will help clean the tree a little
936 common EntryLength 15
938 common LengthString " "
940 # These should be common... but deletion?
941 # Display styles for HList
942 protected variable HighlightTextStyle
943 protected variable NormalTextStyle
944 protected variable DisabledTextStyle
946 protected variable Radix
948 # Frame object for the selected frame
949 protected variable _frame {}
951 protected variable Editing {}
952 protected variable EditEntry
954 # Fencepost for enable/disable_ui and idle/busy hooks.
955 protected variable Running 0
957 # little queue for convenience
958 protected variable _queue {}