# Register display window for Insight. # Copyright 1998, 1999, 2001 Red Hat, Inc. # # Written by Keith Seitz (keiths@redhat.com) # based on work by Martin Hunt (hunt@redhat.com) # # This program is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License (GPL) as published by # the Free Software Foundation; either version 2 of the License, or (at # your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # TODO # # Must fix: # o Edit menus -- weirdo interaction with tkTable. Seems okay on windows. # Needs more testing on unix (popup edit menu item). # # Want really badly: # o Multiple selections # o Register groups (gdb and user-defined) # o format register values before inserting into table? # (Instead of displaying "0x0", we should use "0x00000000" on # machines with 32-bit regs, "0x0000000000000000" on machines # with 64-bit regs, etc. Maybe user-defined formats, i.e., # "0x0000 0000 0000 0000 0000 0000"?) # ------------------------------------------------------------------ # NAME: RegWin::constructor # DESCRIPTION: Create a new register window # # ARGUMENTS: None # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::constructor {args} { eval itk_initialize $args gdbtk_busy window_name "Registers" "Regs" _build_win _layout_table # Clear gdb's changed list catch {gdb_reginfo changed} gdbtk_idle } # ------------------------------------------------------------------ # NAME: RegWin::destructor # DESCRIPTION: Destroys the register window # # ARGUMENTS: None # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::destructor {} { debug } # # Table layout/display methods # # ------------------------------------------------------------------ # NAME: private method RegWin::_build_win # DESCRIPTION: Builds the register window from widgets # # ARGUMENTS: None # RETURNS: Nothing # # NOTES: This method should only be called once for # each RegWin. To change the layout of the table # in the window, use RegWin::_layout_table. # ------------------------------------------------------------------ body RegWin::_build_win {} { # Create scrollbars and table itk_component add vscroll { scrollbar $itk_interior.vs -orient vertical } {} itk_component add hscroll { scrollbar $itk_interior.hs -orient horizontal } {} itk_component add table { ::table $itk_interior.tbl -variable [scope _data] \ -bg [pref get gdb/font/normal_bg] -fg [pref get gdb/font/normal_fg] \ -browsecmd [code $this _select_cell %S] -font src-font \ -colstretch unset -rowstretch unset -selectmode single \ -resizeborders none -multiline false -colwidth 18 \ -autoclear 0 -bg [pref get gdb/font/normal_bg] \ -padx 5 -xscrollcommand [code $itk_component(hscroll) set] \ -yscrollcommand [code $itk_component(vscroll) set] } {} bind $itk_component(table) <Up> \ [format "%s; break" [code $this _move up]] bind $itk_component(table) <Down> \ [format "%s; break" [code $this _move down]] bind $itk_component(table) <Left> \ [format "%s; break" [code $this _move left]] bind $itk_component(table) <Right> \ [format "%s; break" [code $this _move right]] bind $itk_component(table) <3> \ [code $this _but3 %x %y %X %Y] bind $itk_component(table) <Double-1> \ [code $this _edit %x %y] bind $itk_component(table) <Return> \ [format "%s; break" [code $this _accept_edit]] bind $itk_component(table) <KP_Enter> \ [format "%s; break" [code $this _accept_edit]] bind $itk_component(table) <Escape> \ [code $this _unedit] $itk_component(hscroll) configure -command [code $itk_component(table) xview] $itk_component(vscroll) configure -command [code $itk_component(table) yview] grid $itk_component(table) -row 0 -col 0 -sticky news grid $itk_component(vscroll) -row 0 -col 1 -sticky ns grid $itk_component(hscroll) -row 1 -col 0 -sticky ew grid columnconfigure $itk_interior 0 -weight 1 grid rowconfigure $itk_interior 0 -weight 1 # Add sizebox for windows if {[string compare $::tcl_platform(platform) "windows"] == 0} { ide_sizebox $itk_interior.sbox place $itk_interior.sbox -relx 1.0 -rely 1.0 -anchor se } # Create/configure tags for various display styles # normal - the "normal" display style # highlight - changed registers are highlighted # sel - the selection fg/bg should conform to standard # header - used on the register name cells and empty cells # edit - used on a cell being edited $itk_component(table) tag configure normal \ -foreground [pref get gdb/font/normal_fg] \ -background [pref get gdb/font/normal_bg] \ -state disabled $itk_component(table) tag configure highlight \ -foreground [pref get gdb/font/highlight_fg] \ -background [pref get gdb/font/highlight_bg] $itk_component(table) tag raise highlight $itk_component(table) tag configure sel \ -foreground [pref get gdb/font/select_fg] $itk_component(table) tag configure header \ -foreground [pref get gdb/font/header_fg] \ -background [pref get gdb/font/header_bg] \ -anchor w -state disabled -relief raised $itk_component(table) tag configure disabled \ -state disabled $itk_component(table) tag raise active $itk_component(table) tag configure edit \ -state normal $itk_component(table) tag raise edit $itk_component(table) tag raise sel # Register to receive notifications on preference changes # (Note that these are not supported by the preference dialogs, but...) foreach opt [list highlight select header] { pref add_hook gdb/font/${opt}_fg [code $this _prefs_changed] pref add_hook gdb/font/${opt}_bg [code $this _prefs_changed] } # Create toplevel menubar itk_component add menubar { menu $itk_interior.m -tearoff false } { ignore -tearoff } $_top configure -menu $itk_component(menubar) # Create register menu itk_component add reg_menu { menu $itk_component(menubar).reg -tearoff false \ -postcommand [code $this _post_menu] } { ignore -tearoff } $itk_component(menubar) add cascade -menu $itk_component(reg_menu) \ -label "Register" -underline 0 if {![pref get gdb/mode]} { $itk_component(reg_menu) add command -label "Edit" \ -underline 0 -state disabled set _menuitems(edit) [$itk_component(reg_menu) index last] } # Create register->format cascade menu itk_component add reg_format { menu $itk_component(reg_menu).format -tearoff false } { ignore -tearoff } $itk_component(reg_menu) add cascade -menu $itk_component(reg_format) \ -label "Format" -underline 0 $itk_component(reg_format) add radio -label "Hex" -value x \ -underline 0 -state disabled -command [code $this update dummy] $itk_component(reg_format) add radio -label "Decimal" -value d \ -underline 0 -state disabled -command [code $this update dummy] $itk_component(reg_format) add radio -label "Unsigned" -value u \ -underline 0 -state disabled -command [code $this update dummy] $itk_component(reg_format) add radio -label "Natural" -value {} \ -underline 0 -state disabled -command [code $this update dummy] $itk_component(reg_format) add radio -label "Binary" -value t \ -underline 0 -state disabled -command [code $this update dummy] $itk_component(reg_format) add radio -label "Octal" -value o \ -underline 0 -state disabled -command [code $this update dummy] $itk_component(reg_format) add radio -label "Raw" -value r \ -underline 0 -state disabled -command [code $this update dummy] $itk_component(reg_format) add radio -label "Floating Point" -value f \ -underline 0 -state disabled -command [code $this update dummy] $itk_component(reg_menu) add command -label "Add to Watch" \ -underline 7 -state disabled set _menuitems(add_to_watch) [$itk_component(reg_menu) index last] $itk_component(reg_menu) add separator $itk_component(reg_menu) add command -label "Remove from Display" \ -underline 0 -state disabled set _menuitems(remove_from_display) [$itk_component(reg_menu) index last] $itk_component(reg_menu) add command -label "Display all Registers" \ -underline 0 -state disabled -command [code $this _display_all] set _menuitems(display_all_registers) [$itk_component(reg_menu) index last] $itk_component(reg_menu) add separator $itk_component(reg_menu) add command -label "Close" \ -underline 0 -command [code delete object $this] # Add popup menu - we populate it in the event handler itk_component add popup { menu $itk_interior.pop -tearoff 0 } {} $itk_component(popup) configure \ -disabledforeground [$itk_component(menubar) cget -fg] } # ------------------------------------------------------------------ # NAME: private method RegWin::_dimensions # DESCRIPTION: Determine dimensions for the table # # ARGUMENTS: None # RETURNS: A list of {cols,rows} which may be used to # configure the table # # NOTES: I don't like this. (KRS 20010718) # ------------------------------------------------------------------ body RegWin::_dimensions {} { # Always layout the table based on the TOTAL number # of registers (not just the shown ones). set num [llength [gdb_reginfo name]] set rows [pref get gdb/reg/rows] set cols [expr {$num / $rows}] if {[expr {$num % $rows}] != 0} { incr cols } return [list [expr {2 * $cols}] $rows] } # ------------------------------------------------------------------ # NAME: private method RegWin::_layout_table # DESCRIPTION: Configures and lays out the table # # ARGUMENTS: None # RETURNS: Nothing # # NOTES: Uses preferences to determine if/how a register # is displayed # ------------------------------------------------------------------ body RegWin::_layout_table {} { # Set table dimensions lassign [_dimensions] cols rows $itk_component(table) configure -cols $cols -rows $rows if {[info exists _cell]} { unset _cell unset _register } set _register(hidden) {} # Find out largest register name length and register size length. set width 0; # for reg values set max_width 0; # for reg labels foreach r [gdb_reginfo name -numbers] { set nm [lindex $r 0] set rn [lindex $r 1] set size [string length $nm] if {$size > $max_width} { set max_width $size } set size [gdb_reginfo size $rn] if {$size > $width} { set width $size } } incr max_width 2; # padding # Minwidth = size * 2 (hex) + 2 ("0x") + 2 (padding, one space each side) set minwidth [expr {$size * 2 + 2 + 2}] # Clear any column spans foreach span [$itk_component(table) spans] { $itk_component(table) spans $span 0,0 } # Fill data array with register names. # # The table is indexed by (row,col). All odd columns will contain # register values and all even columns will contain the labels. # # This loop will also initialize _typed and _editable arrays. set x 0 set y 0 set _reg_display_list {} foreach r [gdb_reginfo name -numbers] { set name [lindex $r 0] set rn [lindex $r 1] # All registers shall be considered editable # and non-typed until proved otherwise set _typed($rn) 0 set _editable($rn) 0 # If user has no preference, show register in hex (if we can) set format [pref getd gdb/reg/${name}-format] if {$format == ""} { set format x } set _format($rn) $format # Check if the user prefers not to show this register if {[pref getd gdb/reg/$name] == "no"} { set _cell($rn) hidden lappend _register(hidden) $rn } else { lappend _reg_display_list $rn set _cell($rn) "$y,[expr {$x+1}]" set _register($_cell($rn)) $rn set _data($y,$x) $name _update_register $rn $itk_component(table) width $x $max_width $itk_component(table) width [expr {$x+1}] $width $itk_component(table) tag col header $x $itk_component(table) tag col normal [expr {$x+1}] # Go to next row/column incr y if {$y == $rows} { set _col_size([expr {$x+1}]) 0 # Size the column if {$::gdb_running} { _size_column [expr {$x+1}] 1 } set y 0 incr x 2 } } } # Mark empty cells while {$y != $rows && $x != $cols} { set _data($y,$x) "" set _data($y,[expr {$x+1}]) "" $itk_component(table) spans $y,$x 0,1 $itk_component(table) tag cell header $y,$x set _col_size([expr {$x+1}]) 0 incr y if {$y == $rows} { # Size the column if {$::gdb_running} { _size_column [expr {$x+1}] 1 } set y 0 incr x 2 } } # Update register menu if {[llength $_register(hidden)] != 0} { $itk_component(reg_menu) entryconfigure $_menuitems(display_all_registers) \ -state normal } } # ------------------------------------------------------------------ # NAME: private method RegWin::_size_cell_column # DESCRIPTION: Resize the column for a given cell. # # ARGUMENTS: # cell - the cell whose column is to be resized # down - whether the resizing should size the column # down or just up. # RETURNS: Nothing # # NOTES: See _size_column for the reasoning for the "down" # option. # ------------------------------------------------------------------ body RegWin::_size_cell_column {cell down} { set col [string trim [lindex [split $cell ,] 1] ()] _size_column $col $down } # ------------------------------------------------------------------ # NAME: private method RegWin::_size_column # DESCRIPTION: Resize the given column # # ARGUMENTS: # col - the column to be resized # down - whether the resizing should size the column # RETURNS: down or just up. # # NOTES: The down option allows column sizes to change down # as well as up. For most cases, this is what is # wanted. However, when the user is stepping, it is # really annoying to see the column sizes changing. # It's bad enough we must size up, but going down # is just too much. Consequently, when updating the # contents of the table, we specify that the columns # should not downsize. This helps mitigate the # annoyance. # ------------------------------------------------------------------ body RegWin::_size_column {col down} { set max 0 foreach cell [array names _data *,$col] { set len [string length $_data($cell)] if {$len > $max} { set max $len } } if {($down && $max != $_col_size($col)) || (!$down && $max > $_col_size($col))} { set _col_size($col) $max $itk_component(table) width $col [expr {$max + 2}] # Force the table to update itself after idle event generate $itk_component(table) <Configure> \ -width [winfo width $itk_component(table)] } } # ------------------------------------------------------------------ # NAME: private method RegWin::_prefs_changed # DESCRIPTION: Reconfigures register window when a preference # changes. # # ARGUMENTS: # pref - the preference which changed # value - preference's new value # RETURNS: Nothing # # NOTES: Callback from pref system # ------------------------------------------------------------------ body RegWin::_prefs_changed {pref value} { switch $pref { gdb/font/highlight_fg { $itk_component(table) tag configure highlight -fg $value } gdb/font/highlight_bg { $itk_component(table) tag configure highlight -bg $value } gdb/font/select_fg { $itk_component(table) tag configure sel -bg $value } gdb/font/select_bg { $itk_component(table) tag configure sel -bg $value } gdb/font/header_fg { $itk_component(table) tag configure header -bg $value } gdb/font/header_bg { $itk_component(table) tag configure header -bg $value } } } # # Table event handlers and related methods # # ------------------------------------------------------------------ # NAME: private method RegWin::_accept_edit # DESCRIPTION: Change a register's value # # ARGUMENTS: None # RETURNS: Nothing # # NOTES: Event handler for <Enter> and <KP_Enter> # in table # ------------------------------------------------------------------ body RegWin::_accept_edit {} { set cell [$itk_component(table) tag cell edit] if {[llength $cell] == 1 && [info exists _register($cell)]} { # Select the same cell again. This forces the table # to keep this value. Otherwise, we'll never see it... _select_cell $cell set n [gdb_reginfo name $_register($cell)] set v [string trim [$itk_component(table) curvalue] \ \r\n] if {$v != ""} { if {[catch {gdb_cmd "set \$${n}=$v"} result]} { tk_messageBox -icon error -type ok -message $result \ -title "Error in Expression" -parent $_top } } # Always update the register, even for error conditions. This # will ensure that the cell's old value is restored to the table. _update_register $_register($cell) _size_cell_column $cell 1 } # Reset the table bindings (see RegWin::_edit comments) bind $itk_component(table) <1> {} bind $itk_component(table) <ButtonRelease-1> {} } # ------------------------------------------------------------------ # NAME: private method RegWin::_add_to_watch # DESCRIPTION: Add a register to the watch window # # ARGUMENTS: rn - the register number to add to the WatchWin # RETURNS: Nothing # # NOTES: Only works with one WatchWin... # ------------------------------------------------------------------ body RegWin::_add_to_watch {rn} { [ManagedWin::open WatchWin] add "\$[gdb_reginfo name $rn]" } # ------------------------------------------------------------------ # NAME: private method RegWin::_but3 # DESCRIPTION: Configure the popup menu before posting it # # ARGUMENTS: x - x-coordinate of buttonpress # y - y-coordinate # X - x-root coordinate # Y - y-root coordinate # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::_but3 {x y X Y} { # Only post the menu when we're not executing the inferior, # the inferior is in a runnable state, and we're not in a disabled # cell. if {!$_running && $::gdb_running} { # Select the register set cell [_select_cell [$itk_component(table) index @$x,$y]] if {[info exists _register($cell)]} { set rn $_register($cell) set name [gdb_reginfo name $rn] $itk_component(popup) delete 0 end $itk_component(popup) add command -label $name -state disabled $itk_component(popup) add separator if {!$_typed($rn)} { $itk_component(popup) add radio -label "Hex" \ -variable [scope _format($rn)] -value x \ -command [code $this _change_format $rn] $itk_component(popup) add radio -label "Decimal" \ -variable [scope _format($rn)] -value d \ -command [code $this _change_format $rn] $itk_component(popup) add radio -label "Unsigned" \ -variable [scope _format($rn)] -value u \ -command [code $this _change_format $rn] $itk_component(popup) add radio -label "Natural" \ -variable [scope _format($rn)] -value {} \ -command [code $this _change_format $rn] $itk_component(popup) add radio -label "Binary" \ -variable [scope _format($rn)] -value t \ -command [code $this _change_format $rn] $itk_component(popup) add radio -label "Octal" \ -variable [scope _format($rn)] -value o \ -command [code $this _change_format $rn] $itk_component(popup) add radio -label "Raw" \ -variable [scope _format($rn)] -value r \ -command [code $this _change_format $rn] $itk_component(popup) add radio -label "Floating Point" \ -variable [scope _format($rn)] -value f \ -command [code $this _change_format $rn] $itk_component(popup) add separator } if {$_editable($rn)} { set state normal } else { set state disabled } # I'm disabling this, since it doesn't work very well. # All kinds of goofy interactions with the insertion cursor # and focus when editing is invoked from a menu. (KRS 20010717) if {1} { $itk_component(popup) add command \ -label "Edit" -command "after idle [code $this _edit $x $y]" -state $state } $itk_component(popup) add command \ -label "Add to Watch" -command [code $this _add_to_watch $rn] $itk_component(popup) add separator $itk_component(popup) add command \ -label "Remove from Display" \ -command [code $this _delete_from_display $rn] if {[llength $_register(hidden)] != 0} { $itk_component(popup) add command -label "Display all Registers" \ -command [code $this _display_all] } tk_popup $itk_component(popup) $X $Y } } } # ------------------------------------------------------------------ # NAME: private method RegWin::_delete_from_display # DESCRIPTION: Remove a register from the display # # ARGUMENTS: rn - the register number to remove # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::_delete_from_display {rn} { # Mark the cell as hidden set index [lsearch $_reg_display_list $rn] if {$index != -1} { pref setd gdb/reg/[gdb_reginfo name $rn] no set _reg_display_list [lreplace $_reg_display_list $index $index] # Relayout table _layout_table $itk_component(reg_menu) entryconfigure $_menuitems(display_all_registers) \ -state normal } } # ------------------------------------------------------------------ # NAME: private method RegWin::_display_all # DESCRIPTION: Display all registers in the window # # ARGUMENTS: None # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::_display_all {} { $itk_component(reg_menu) entryconfigure $_menuitems(display_all_registers) \ -state disabled # Unhide all hidden registers foreach r $_register(hidden) { pref setd gdb/reg/[gdb_reginfo name $r] {} } set _register(hidden) {} # Note which register is active and restore it if {[catch {$itk_component(table) index active} cell]} { set active {} } else { set active $_register($cell) } _layout_table if {$active != ""} { $itk_component(table) activate $_cell($active) } } # ------------------------------------------------------------------ # NAME: private method RegWin::_edit # DESCRIPTION: Enables a cell for editing # # ARGUMENTS: # x - the x coordinate of the button press # y - the y coordinate of the button press # RETURNS: Nothing # # NOTES: Event handler for <Double-1> in table. # Sets special bindings for <1> and <ButtonRelease-1>. # ------------------------------------------------------------------ body RegWin::_edit {x y} { global gdb_running focus $itk_component(table) # Get and select the cell and set the edit tag on it set cell [_select_cell [$itk_component(table) index @$x,$y]] # Ugh. In order to click on the label and keep the value # focused, we need to disrupt the ButtonRelease-1 event. bind $itk_component(table) <ButtonRelease-1> break # Disable the <1> binding while editing bind $itk_component(table) <1> break # Now mark the cell as being edited. if {$gdb_running && [info exists _register($cell)]} { $itk_component(table) tag cell edit $cell } } # ------------------------------------------------------------------ # NAME: private method RegWin::_edit_menu # DESCRIPTION: Enables a cell for editing when invoked from # a menu # # ARGUMENTS: # rn - the register to edit # RETURNS: Nothing # # NOTES: # ------------------------------------------------------------------ body RegWin::_edit_menu {rn} { set bbox [$itk_component(table) bbox $_cell($rn)] _edit [lindex $bbox 0] [lindex $bbox 1] event generate $_top <Enter> } # ------------------------------------------------------------------ # NAME: private method _move # DESCRIPTION: Handle arrow key events in table # # ARGUMENTS: direction - "up", "down", "left", "right" # RETURNS: Nothing # # NOTES: Event handler for <Up>, <Down>, <Left>, <Right> # in table. This is needed because the table # has some rather strange bindings for moving # the insertion cursor when editing a cell. # This method will move to the next cell when # we're not editing, or it will move the icursor # if we are editing. # ------------------------------------------------------------------ body RegWin::_move {direction} { # If there is no active cell, the table will call error if {[catch {$itk_component(table) index active row} row]} { return } if {[$itk_component(table) tag cell edit] != ""} { # Editing switch $direction { up { # Go to beginning $itk_component(table) icursor 0 } down { # Go to end $itk_component(table) icursor end } left { # Go left one character set ic [$itk_component(table) icursor] if {$ic > 0} { $itk_component(table) icursor [expr {$ic - 1}] } } right { # Go right one character set ic [$itk_component(table) icursor] if {$ic < [$itk_component(table) icursor end] } { $itk_component(table) icursor [expr {$ic + 1}] } } } } else { # Not editing set col [$itk_component(table) index active col] lassign [_dimensions] cols rows switch $direction { up { incr row -1 if {$row < 0} { # go to bottom set row $rows } } down { incr row 1 if {$row == $rows} { # go to top set row 0 } } left { incr col -2 if {$col < 0} { # go to right set col [expr {$cols -1}] } } right { incr col 2 if {$col > $cols} { # go to left set col 0 } } } # clear the selection # FIXME: multiple selections? $itk_component(table) selection clear all _select_cell $row,$col } } # ------------------------------------------------------------------ # NAME: private method RegWin::_post_menu # DESCRIPTION: Configures the Register menu before it is posted # # ARGUMENTS: None # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::_post_menu {} { global gdb_running # Configure the menu for the active cell if {![catch {$itk_component(table) index active} cell] && [info exists _register($cell)] && $gdb_running} { $itk_component(reg_menu) entryconfigure $_menuitems(remove_from_display) \ -state normal -command [code $this _delete_from_display $_register($cell)] if {$_typed($_register($cell))} { set state disabled } else { set state normal } for {set i 0} {$i <= [$itk_component(reg_format) index end]} {incr i} { $itk_component(reg_format) entryconfigure $i \ -state $state \ -variable [scope _format($_register($cell))] \ -command [code $this _change_format $_register($cell)] } $itk_component(reg_menu) entryconfigure $_menuitems(add_to_watch) \ -state normal -command [code $this _add_to_watch $_register($cell)] # This doesn't seem to work on my linux box. It works fine on # Cygwin, though... (KRS 010806) if {$_editable($_register($cell))} { $itk_component(reg_menu) entryconfigure $_menuitems(edit) \ -state normal -command [code $this _edit_menu $_register($cell)] } } else { # Disable everything $itk_component(reg_menu) entryconfigure $_menuitems(remove_from_display) \ -state disabled -command {} for {set i 0} {$i <= [$itk_component(reg_format) index end]} {incr i} { $itk_component(reg_format) entryconfigure $i -state disabled \ -variable {} } $itk_component(reg_menu) entryconfigure $_menuitems(add_to_watch) \ -state disabled -command {} if {0} { $itk_component(reg_menu) entryconfigure $_menuitems(edit) \ -state disabled -command {} } } } # ------------------------------------------------------------------ # NAME: private method RegWin::_select # DESCRIPTION: Selects the cell with the given coordinates # # ARGUMENTS: # x - the x-coordinate of the cell to select # y - the y-coordinate of the cell to select # RETURNS: The actual cell selected # ------------------------------------------------------------------ body RegWin::_select {x y} { return [_select_cell [$itk_component(table) index @$x,$y]] } # ------------------------------------------------------------------ # NAME: private method RegWin::_select_cell # DESCRIPTION: Selects a given cell in the table # # ARGUMENTS: # cell - the table index to select # RETURNS: The actual cell selected # # NOTES: Adjusts the cell index so that it always # selects the value cell for a register # ------------------------------------------------------------------ body RegWin::_select_cell {cell} { # Abort an edit _unedit # check if going to label. If so, highlight next set row [lindex [split $cell ,] 0] set col [lindex [split $cell ,] 1] if {[expr {$col % 2}] == 0} { # going onto a label incr col 1 } # Make the selected cell the active one $itk_component(table) activate $row,$col $itk_component(table) see active # Select this cell and its label # FIXME: multiple selections? $itk_component(table) selection clear all $itk_component(table) selection set $row,$col $row,[expr {$col-1}] return $row,$col } # ------------------------------------------------------------------ # NAME: private method RegWin::_unedit # DESCRIPTION: Cancels an edit # # ARGUMENTS: None # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::_unedit {} { # clear the tag set cell [$itk_component(table) tag cell edit] $itk_component(table) tag cell normal $cell # Reset the table binding (see RegWin::_edit comments) bind $itk_component(table) <ButtonRelease-1> {} bind $itk_component(table) <1> {} } # # Register operations # # ------------------------------------------------------------------ # NAME: private method RegWin::_get_value # DESCRIPTION: Get the value of a register # # ARGUMENTS: rn - the register number whose value should be # fetched # RETURNS: The register's value or "" # # NOTES: This function uses RegWin::_format to determine # how the value is returned # It also does some other weird stuff... # ------------------------------------------------------------------ body RegWin::_get_value {rn} { # Typed registers natural values start with a brace (escaped by a slash) if {[catch {gdb_reginfo value {} $rn} valtest]} { set value "" } else { if {[string index $valtest 1] == "\{"} { # If it is a typed register, we print it raw set format r set _format($rn) r set _typed($rn) 1 set _editable($rn) 0 } else { set format $_format($rn) set _editable($rn) 1 } if {[catch {gdb_reginfo value $format $rn} value]} { set value "" } else { set value [string trim $value \ ] } } return $value } # ------------------------------------------------------------------ # NAME: private method RegWin::_change_format # DESCRIPTION: Change the display format of the register # # ARGUMENTS: rn - the register number to change # RETURNS: Nothing # # NOTES: Assumes that hex, "x", is the default # ------------------------------------------------------------------ body RegWin::_change_format {rn} { # Set the new format. Hex (x) is the default. set name [gdb_reginfo name $rn] if {$_format($rn) == "x"} { set fmt "" } else { set fmt $_format($rn) } pref setd gdb/reg/${name}-format $fmt _update_register $rn _size_cell_column $_cell($rn) 1 # Show the active cell in case it's moved as a result # of resizing the columns. $itk_component(table) see active } # ------------------------------------------------------------------ # NAME: private_method RegWin::_update_register # DESCRIPTION: Updates the value of a register and refreshes # the table # # ARGUMENTS: # rn - the register number to update # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::_update_register {rn} { set _data($_cell($rn)) [_get_value $rn] } # # Gdb Events # # ------------------------------------------------------------------ # NAME: public method RegWin::arch_changed # DESCRIPTION: ArchChangedEvent handler # # ARGUMENTS: event - the ArchChangedEvent (not used) # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::arch_changed {event} { # When the arch changes, gdb will callback into gdbtk-register.c # to swap out the old register set, so we need only redraw the # window, updating the register names and numbers. _layout_table # Clear gdb's change list catch {gdb_reginfo changed} } # ------------------------------------------------------------------ # NAME: public method RegWin::busy # DESCRIPTION: BusyEvent handler # # ARGUMENTS: event - the BusyEvent (not used) # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::busy {event} { # Abort any edit. Need to check if the table is constructed, # since we call gdbtk_busy when we're created... if {[info exists itk_component(table)]} { _unedit } # Set fencepost set _running 1 # Set cursor $_top configure -cursor watch } # ------------------------------------------------------------------ # NAME: public method RegWin::idle # DESCRIPTION: IdleEvent handler # # ARGUMENTS: event - the IdleEvent (not used) # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::idle {event} { # Clear fencepost set _running 0 # Reset cursor $_top configure -cursor {} } # ------------------------------------------------------------------ # NAME: public method RegWin::set_variable # DESCRIPTION: SetVariableEvent handler # # ARGUMENTS: None # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::set_variable {event} { switch [$event get variable] { disassembly-flavor { _layout_table } } } # ------------------------------------------------------------------ # NAME: public method RegWin::update # DESCRIPTION: UpdateEvent handler # # ARGUMENTS: event - the UpdateEvent (not used) # RETURNS: Nothing # ------------------------------------------------------------------ body RegWin::update {event} { dbug I "START REGISTER UPDATE CALLBACK" # Change anything on the old change list back to normal foreach r $_change_list { if {$_cell($r) != "hidden"} { $itk_component(table) tag cell normal $_cell($r) } } # Now update and highlight the newly changed values set _change_list {} if {![catch {eval gdb_reginfo changed $_reg_display_list} changed]} { set _change_list $changed } # Problem: if the register was invalid (i.e, we were not running), # its old value will probably be "0x0". Now if we run and its real # value is "0x0", then it will appear as a blank in the register # window. Safegaurd against that here by adding any such register # which is not already in the change list. foreach r $_reg_display_list { if {$_data($_cell($r)) == "" && [lsearch $_change_list $r] == -1} { lappend _change_list $r } } # Tag the changed cells and resize the columns set cols {} foreach r $_change_list { _update_register $r $itk_component(table) tag cell highlight $_cell($r) set col [lindex [split $_cell($r) ,] 1] if {[lsearch $cols $col] == -1} { lappend cols $col } } foreach col $cols { set col [string trim $col ()] _size_column $col 0 } dbug I "END REGISTER UPDATE CALLBACK" }