[PATCH] 680376 - Local variables in nested scopes don't get refreshed automatically



Hello,

To understand this bug, consider this test case (line numbers were
added to ease explanations):

     1  int
     2  main ()
     3  {
     4      int a = 0;
     5      a += 1;
     6      a *= 2;
     7  
     8      {
     9          int b = a;
    10          b += 2;
    11          a = b;
    12      }
    13  
    14      int c = a;
    15      c++;
    16      return c;
    17  }

When Nemiver first enters the function, it queries the back-end (which
is GDB nowadays) for the list of local variables.  GDB says that the
list of variables known at the beginning of the function are: 'a' and
'c'.  Then, each time the program stops, Nemiver queries GDB for the
state of 'a' and 'c'.

But then when we enter the nested scope (that starts at line 8),
Nemiver has no way to detect that we are entering a new scope.  So it
won't know that there is a new variable 'c' in this scope and --
that's the bug -- it just won't show you the variable 'c', unless you
manually hit the 'refresh local variables' button.

The patch below instructs Nemiver to query the back-end -- at each
stop -- for the list of local variables, and then, asks for the
content of each of these variables.

As this might be slow for functions that have a lot of variables, the
patch adds a user preference to disable the feature and get back to
the behaviour that we had prior to the patch.

The patch is a little bit complicated because I had to add a new
overload to IDebugger::list_local_variables, that accepts a signal
slot to be invoked upon reception of the list of variables.  That way,
it becomes easier to chain actions that need to be taken upon the
occurence of asynchronous events like:

  * get the list of local variables
  * when the list of local variables is available (this is async)
    update our current list of local variable with it
  * when our current list of local variable is updated, query the
    state of each local variable we have.
  * etc ...

Lightly tested on Rawhide and applied to master.  I'll be testing
master for a little while and fix fall-outs as I see them.

        * data/schemas/gconf/nemiver-dbgperspective.schemas
        (/apps/nemiver/dbgperspective/update-local-vars-at-each-stop): New
        GConf key.
        * data/schemas/gsettings/org.nemiver.gschema.xml
        (update-local-vars-at-each-stop): New GSettings key.
        * src/confmgr/nmv-conf-keys.h
        (CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP): Declare the variable
        for the new conf key above.
        * src/confmgr/nmv-gconf-keys-defs.cc
        (CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP): Define the key above
        for the GConf backend.
        * src/confmgr/nmv-gsettings-keys-defs.cc
        (CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP): Likewise for the the
        GSettings backend.
        * src/persp/dbgperspective/ui/preferencesdialog.ui: Add a new
        check button in the debugger tab to let the user choose whether
        or not to update the list of local variables at each stop in the
        function.
        * src/persp/dbgperspective/nmv-preferences-dialog.cc
        (Priv::update_local_vars_check_button): New check button, to set
        the new conf key above.
        (Priv::{on_local_vars_list_updated_signal,update_local_var_list_keys}):
        New functions.
        (Priv::init): Initialize the new
        Priv::update_local_vars_check_button with the check button we get
        from glade.  Wire the signal_toggled signal.
        (Priv::update_widget_from_source_dirs_key): Update the new
        Priv::update_widget_from_source_dirs_key check button with the
        value of the key CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP.
        * src/dbgengine/nmv-i-debugger.h (IDebugger::list_local_variables):
        Add a new overload that takes a slot to be invoked whenever local
        variables are listed.
        * src/dbgengine/nmv-gdb-engine.h
        (GDBEngine::list_local_variables): Re-declare the overload above
        here.
        * src/dbgengine/nmv-gdb-engine.cc
        (GDBEngine::list_local_variables):  Define the above here.
        Implement the former overload in terms of the new one.
        * src/persp/dbgperspective/nmv-local-vars-inspector.cc
        (Priv::{append_a_local_variable_and_update_all,
        erase_variable_from_list, remove_a_local_variable,
        add_new_local_vars_and_update_olders,
        maybe_update_list_of_local_vars_and_then_update_older_ones,
        is_variable_in_list}): New functions.
        (Priv::on_local_vars_list_updated_signal): Removed.
        (finish_handling_debugger_stopped_event): Use the new
        IDebugger::list_local_variables overload that takes a signal slot
        in argument.  Use the new function
        maybe_update_list_of_local_vars_and_then_update_older_ones.
        (LocalVarsInspector::show_local_variables_of_current_function):
        Use the new overload of IDebugger::list_local_variables.
        * src/persp/dbgperspective/nmv-dbg-perspective.cc
        (Priv::current_thread_id): New member, initialized to zero.
        (DBGPerspective::on_thread_list_thread_selected_signal): Do not
        select the thread id if we are currently already on that same
        thread id.  prevents Nemiver from calling
        show_local_variables_of_current_function on the variable
        inspector; calling that function would be redundant with the fact
        that the variable inspector already queries the list of variables
        when the debugger stops.  So the widget would have each local
        variables twice.
        (DBGPerspective::on_debugger_stopped_signal): Set
        m_priv->current_thread_id here too, so that
        DBGPerspective::on_thread_list_thread_selected_signal can have a
        chance to know if it is being called on the same thread as the
        previous thread or not.
        * tests/locals-in-middle.cc: New program for testing.
        * tests/Makefile: Build the new tests/locals-in-middle.cc program
        for testing.
---
 data/schemas/gconf/nemiver-dbgperspective.schemas  |  11 ++
 data/schemas/gsettings/org.nemiver.gschema.xml     |   6 +
 src/confmgr/nmv-conf-keys.h                        |   1 +
 src/confmgr/nmv-gconf-keys-defs.cc                 |   2 +
 src/confmgr/nmv-gsettings-keys-defs.cc             |   2 +
 src/dbgengine/nmv-gdb-engine.cc                    |  17 +-
 src/dbgengine/nmv-gdb-engine.h                     |   3 +
 src/dbgengine/nmv-i-debugger.h                     |   3 +
 src/persp/dbgperspective/nmv-dbg-perspective.cc    |  18 +-
 .../dbgperspective/nmv-local-vars-inspector.cc     | 204 ++++++++++++++++++---
 src/persp/dbgperspective/nmv-preferences-dialog.cc |  39 +++-
 src/persp/dbgperspective/ui/preferencesdialog.ui   |  93 ++++++----
 tests/Makefile.am                                  |   5 +-
 tests/locals-in-middle.cc                          |  17 ++
 14 files changed, 348 insertions(+), 73 deletions(-)
 create mode 100644 tests/locals-in-middle.cc

diff --git a/data/schemas/gconf/nemiver-dbgperspective.schemas 
b/data/schemas/gconf/nemiver-dbgperspective.schemas
index 3e519a3..cdfd27b 100644
--- a/data/schemas/gconf/nemiver-dbgperspective.schemas
+++ b/data/schemas/gconf/nemiver-dbgperspective.schemas
@@ -213,6 +213,17 @@
       </locale>
     </schema>
     <schema>
+      <key>/schemas/apps/nemiver/dbgperspective/update-local-vars-at-each-stop</key>
+      <applyto>/apps/nemiver/dbgperspective/update-local-vars-at-each-stop</applyto>
+      <owner>nemiver</owner>
+      <type>bool</type>
+      <default>true</default>
+      <locale name="C">
+       <short>Whether to update the list of local variables at each stop</short>
+       <long>Updating the list of local variables lets the debugger show variables that are created way 
after the beginning of the function.  Disabling this option might speed up stepping but leads the debugger to 
miss local variables that are created after the beginning of the function.</long>
+      </locale>
+    </schema>
+    <schema>
       <key>/schemas/apps/nemiver/dbgperspective/asm-style-pure</key>
       <applyto>/apps/nemiver/dbgperspective/asm-style-pure</applyto>
       <owner>nemiver</owner>
diff --git a/data/schemas/gsettings/org.nemiver.gschema.xml b/data/schemas/gsettings/org.nemiver.gschema.xml
index ff2bdcd..2c44332 100644
--- a/data/schemas/gsettings/org.nemiver.gschema.xml
+++ b/data/schemas/gsettings/org.nemiver.gschema.xml
@@ -120,6 +120,12 @@
       <description>If set to yes, pure assembly code is shown when switching to assembly view. Otherwise, 
source code mixed with assembly code is shown.</description>
     </key>
 
+    <key name="update-local-vars-at-each-stop" type="b">
+      <default>true</default>
+      <summary>Whether to update the list of local variables at each stop</summary>
+      <description>Updating the list of local variables lets the debugger show variables that are created 
way after the beginning of the function.  Disabling this option might speed up stepping but leads the 
debugger to miss local variables that are created after the beginning of the function.</description>
+    </key>
+
     <key name="default-num-asm-instrs" type="i">
       <default>25</default>
       <summary>The number of assembly instructions to show by default</summary>
diff --git a/src/confmgr/nmv-conf-keys.h b/src/confmgr/nmv-conf-keys.h
index 0d01639..854da56 100644
--- a/src/confmgr/nmv-conf-keys.h
+++ b/src/confmgr/nmv-conf-keys.h
@@ -54,6 +54,7 @@ extern const char* CONF_KEY_TWO_PANE_LAYOUT_STATUS_HPANE_LOCATION;
 extern const char* CONF_KEY_TWO_PANE_LAYOUT_STATUS_VPANE_LOCATION;
 extern const char* CONF_KEY_DEBUGGER_ENGINE_DYNMOD_NAME;
 extern const char* CONF_KEY_EDITOR_STYLE_SCHEME;
+extern const char* CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP;
 extern const char* CONF_KEY_ASM_STYLE_PURE;
 extern const char* CONF_KEY_GDB_BINARY;
 extern const char* CONF_KEY_DEFAULT_NUM_ASM_INSTRS;
diff --git a/src/confmgr/nmv-gconf-keys-defs.cc b/src/confmgr/nmv-gconf-keys-defs.cc
index 950526c..f5169c2 100644
--- a/src/confmgr/nmv-gconf-keys-defs.cc
+++ b/src/confmgr/nmv-gconf-keys-defs.cc
@@ -72,6 +72,8 @@ const char* CONF_KEY_DEBUGGER_ENGINE_DYNMOD_NAME =
                 "/apps/nemiver/dbgperspective/debugger-engine-dynmod";
 const char* CONF_KEY_EDITOR_STYLE_SCHEME =
                 "/apps/nemiver/dbgperspective/editor-style-scheme";
+const char* CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP =
+  "/apps/nemiver/dbgperspective/update-local-vars-at-each-stop";
 const char* CONF_KEY_ASM_STYLE_PURE =
                 "/apps/nemiver/dbgperspective/asm-style-pure";
 const char* CONF_KEY_DEFAULT_NUM_ASM_INSTRS =
diff --git a/src/confmgr/nmv-gsettings-keys-defs.cc b/src/confmgr/nmv-gsettings-keys-defs.cc
index 1bc7ec2..fbc1416 100644
--- a/src/confmgr/nmv-gsettings-keys-defs.cc
+++ b/src/confmgr/nmv-gsettings-keys-defs.cc
@@ -60,6 +60,8 @@ const char* CONF_KEY_TWO_PANE_LAYOUT_STATUS_HPANE_LOCATION =
 const char* CONF_KEY_DEBUGGER_ENGINE_DYNMOD_NAME = "debugger-engine-dynmod";
 const char* CONF_KEY_EDITOR_STYLE_SCHEME = "editor-style-scheme";
 const char* CONF_KEY_ASM_STYLE_PURE = "asm-style-pure";
+const char* CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP =
+  "update-local-vars-at-each-stop";
 const char* CONF_KEY_DEFAULT_NUM_ASM_INSTRS = "default-num-asm-instrs";
 const char* CONF_KEY_GDB_BINARY = "gdb-binary";
 const char* CONF_KEY_FOLLOW_FORK_MODE = "follow-fork-mode";
diff --git a/src/dbgengine/nmv-gdb-engine.cc b/src/dbgengine/nmv-gdb-engine.cc
index ba4cb15..e462a48 100644
--- a/src/dbgengine/nmv-gdb-engine.cc
+++ b/src/dbgengine/nmv-gdb-engine.cc
@@ -2140,6 +2140,12 @@ struct OnLocalVariablesListedHandler : OutputHandler {
         LOG_FUNCTION_SCOPE_NORMAL_DD;
         THROW_IF_FAIL (m_engine);
 
+        if (a_in.command ().has_slot ()) {
+            typedef sigc::slot<void, const IDebugger::VariableList> SlotType;
+            SlotType slot = a_in.command ().get_slot<SlotType> ();
+            slot (a_in.output ().result_record ().local_variables ());
+        }
+
         m_engine->local_variables_listed_signal ().emit
             (a_in.output ().result_record ().local_variables (),
              a_in.command ().cookie ());
@@ -5211,16 +5217,25 @@ GDBEngine::list_frames_arguments (int a_low_frame,
 }
 
 void
-GDBEngine::list_local_variables (const UString &a_cookie)
+GDBEngine::list_local_variables (const ConstVariableListSlot &a_slot,
+                                 const UString &a_cookie)
 {
     LOG_FUNCTION_SCOPE_NORMAL_DD;
     Command command ("list-local-variables",
                      "-stack-list-locals 2",
                      a_cookie);
+    command.set_slot (a_slot);
     queue_command (command);
 }
 
 void
+GDBEngine::list_local_variables (const UString &a_cookie)
+{
+    LOG_FUNCTION_SCOPE_NORMAL_DD;
+    list_local_variables (&null_const_variable_list_slot, a_cookie);
+}
+
+void
 GDBEngine::list_global_variables (const UString &a_cookie)
 {
     LOG_FUNCTION_SCOPE_NORMAL_DD;
diff --git a/src/dbgengine/nmv-gdb-engine.h b/src/dbgengine/nmv-gdb-engine.h
index 135992f..b348a4c 100644
--- a/src/dbgengine/nmv-gdb-engine.h
+++ b/src/dbgengine/nmv-gdb-engine.h
@@ -480,6 +480,9 @@ public:
                                const FrameArgsSlot &a_slot,
                                const UString &a_cookie);
 
+    void list_local_variables (const ConstVariableListSlot &a_slot,
+                              const UString &a_cookie);
+
     void list_local_variables (const UString &a_cookie);
 
     void list_global_variables ( const UString &a_cookie );
diff --git a/src/dbgengine/nmv-i-debugger.h b/src/dbgengine/nmv-i-debugger.h
index 5356745..26a5d1c 100644
--- a/src/dbgengine/nmv-i-debugger.h
+++ b/src/dbgengine/nmv-i-debugger.h
@@ -1448,6 +1448,9 @@ public:
                                         const FrameArgsSlot &a_slot,
                                         const UString &a_cookie) = 0;
 
+    virtual void list_local_variables (const ConstVariableListSlot &a_slot,
+                                       const UString &a_cookie="") = 0;
+
     virtual void list_local_variables (const UString &a_cookie="") = 0;
 
     virtual void list_global_variables (const UString &a_cookie="") = 0;
diff --git a/src/persp/dbgperspective/nmv-dbg-perspective.cc b/src/persp/dbgperspective/nmv-dbg-perspective.cc
index f61aaf3..22b82c1 100644
--- a/src/persp/dbgperspective/nmv-dbg-perspective.cc
+++ b/src/persp/dbgperspective/nmv-dbg-perspective.cc
@@ -918,6 +918,7 @@ struct DBGPerspective::Priv {
     int current_page_num;
     IDebuggerSafePtr debugger;
     IDebugger::Frame current_frame;
+    int current_thread_id;
     map<int, IDebugger::Breakpoint> breakpoints;
     ISessMgrSafePtr session_manager;
     ISessMgr::Session session;
@@ -976,6 +977,7 @@ struct DBGPerspective::Priv {
         contextual_menu (0),
         workbench (0),
         current_page_num (0),
+        current_thread_id (0),
         show_dbg_errors (false),
         use_system_font (true),
         show_line_numbers (true),
@@ -1761,16 +1763,21 @@ void
 DBGPerspective::on_thread_list_thread_selected_signal (int a_tid)
 {
     LOG_FUNCTION_SCOPE_NORMAL_DD;
-    if (a_tid) {}
 
-    NEMIVER_TRY
+    NEMIVER_TRY;
 
     THROW_IF_FAIL (m_priv);
 
+    LOG_DD ("current tid: " << m_priv->current_thread_id);
+    LOG_DD ("new tid: " << a_tid);
+    if (m_priv->current_thread_id == a_tid)
+        return;
+
+    m_priv->current_thread_id = a_tid;
     get_local_vars_inspector ().show_local_variables_of_current_function
-                                                        (m_priv->current_frame);
+        (m_priv->current_frame);
 
-    NEMIVER_CATCH
+    NEMIVER_CATCH;
 }
 
 
@@ -2381,7 +2388,7 @@ void
 DBGPerspective::on_debugger_stopped_signal (IDebugger::StopReason a_reason,
                                             bool /*a_has_frame*/,
                                             const IDebugger::Frame &a_frame,
-                                            int, int, const UString &)
+                                            int a_thread_id, int, const UString &)
 {
     LOG_FUNCTION_SCOPE_NORMAL_DD;
 
@@ -2396,6 +2403,7 @@ DBGPerspective::on_debugger_stopped_signal (IDebugger::StopReason a_reason,
 
     update_src_dependant_bp_actions_sensitiveness ();
     m_priv->current_frame = a_frame;
+    m_priv->current_thread_id = a_thread_id;
 
     set_where (a_frame, /*do_scroll=*/true, /*try_hard=*/true);
 
diff --git a/src/persp/dbgperspective/nmv-local-vars-inspector.cc 
b/src/persp/dbgperspective/nmv-local-vars-inspector.cc
index a7018d1..d0259fb 100644
--- a/src/persp/dbgperspective/nmv-local-vars-inspector.cc
+++ b/src/persp/dbgperspective/nmv-local-vars-inspector.cc
@@ -37,6 +37,7 @@
 #include "nmv-i-var-walker.h"
 #include "nmv-vars-treeview.h"
 #include "nmv-debugger-utils.h"
+#include "nmv-conf-keys.h"
 
 using namespace nemiver::common;
 namespace vutil = nemiver::variables_utils2;
@@ -212,8 +213,6 @@ public:
         THROW_IF_FAIL (debugger);
         debugger->stopped_signal ().connect
             (sigc::mem_fun (*this, &Priv::on_stopped_signal));
-        debugger->local_variables_listed_signal ().connect
-            (sigc::mem_fun (*this, &Priv::on_local_variables_listed_signal));
     }
 
     void
@@ -388,6 +387,44 @@ public:
         }
     }
 
+    /// Append a new local variable to this widget and then update the
+    /// content of all the local variables contained in the widget.
+    void
+    append_a_local_variable_and_update_all (const IDebugger::VariableSafePtr a_var)
+    {
+        LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+        append_a_local_variable (a_var);
+        update_local_variables ();
+    }
+
+    /// Erases a variable from a list of variables.
+    void
+    erase_variable_from_list (const IDebugger::VariableSafePtr a_var,
+                              IDebugger::VariableList &a_list)
+    {
+        IDebugger::VariableList::iterator v;
+        for (v = a_list.begin (); v != a_list.end (); ++v)
+            if (**v == *a_var)
+                break;
+
+        if (v != a_list.end ())
+            a_list.erase (v);
+    }
+
+    /// Graphically remove a variable a_var from the widget.
+    void
+    remove_a_local_variable (const IDebugger::VariableSafePtr a_var)
+    {
+        Gtk::TreeModel::iterator parent_row_it;
+
+        if (get_local_variables_row_iterator (parent_row_it))
+            vutil::unlink_a_variable_row (a_var, tree_store, parent_row_it);
+
+        erase_variable_from_list (a_var, local_vars);
+        erase_variable_from_list (a_var, local_vars_changed_at_prev_stop);
+    }
+
     void
     append_a_function_argument (const IDebugger::VariableSafePtr a_var)
     {
@@ -494,6 +531,12 @@ public:
         return false;
     }
 
+    /// This function is called after the debugger got stopped and
+    /// this widget is visible.  In this case the function becomes the
+    /// entry point to perform the tasks this local variable inspector
+    /// is supposed to perform: Update the list of local variables and
+    /// then update the content of each local variable and function
+    /// argument.
     void
     finish_handling_debugger_stopped_event
                                     (IDebugger::StopReason /*a_reason*/,
@@ -517,7 +560,9 @@ public:
             LOG_DD ("init tree view");
             re_init_tree_view ();
             LOG_DD ("list local variables");
-            debugger->list_local_variables ();
+            debugger->list_local_variables
+                (sigc::mem_fun
+                 (*this, &Priv::add_new_local_vars_and_update_olders));
             LOG_DD ("list frames arguments");
             debugger->list_frames_arguments (a_frame.level (),
                                              a_frame.level (),
@@ -526,7 +571,7 @@ public:
                                              "");
         } else {
             LOG_DD ("update local variables and function arguments");
-            update_local_variables ();
+            maybe_update_list_of_local_vars_and_then_update_older_ones ();
             update_function_arguments ();
         }
         previous_function_name = a_frame.function_name ();
@@ -554,6 +599,128 @@ public:
         ui_utils::display_info (message);
     }
 
+    /// Add the new local variables @a_vars to the list of local
+    /// variables for the current function.  Then, update the content
+    /// of all the local variables that we already had previous to
+    /// calling this function.
+    void
+    add_new_local_vars_and_update_olders (const IDebugger::VariableList &a_vars)
+    {
+        LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+        if (a_vars.empty ()) {
+            LOG_DD ("got empty list of new variables");
+            // There are no new variables to add.  This functions
+            // amounts to just updating the content of the local
+            // variables we already had.
+            update_local_variables ();
+            return;
+        }
+
+        // For each new local variable name, create a backend variable
+        // object (and add it to the list of local variable managed by
+        // this widget) and then, when all new local variables are
+        // under control, update the older variables we already had in
+        // this widget.
+        bool added_new_vars = false;
+        for (IDebugger::VariableList::const_iterator i = a_vars.begin ();
+             i != a_vars.end ();
+             ++i) {
+            if ((*i)->name ().empty ())
+                continue;
+
+            if (!is_variable_in_list ((*i)->name (),
+                                      local_vars)) {
+                IDebugger::VariableList::const_iterator next_iterator = i;
+                next_iterator++;
+                if (next_iterator == a_vars.end ()) {
+                    // So we are on the last new local variable to
+                    // add.  Do not forget to update the content of
+                    // the list of all the (older) local variables
+                    // after adding this one.
+                    LOG_DD ("Creating a varobj for the last var " << (*i)->name ()
+                            << " and updating the content of all variables");
+                    debugger->create_variable
+                        ((*i)->name (),
+                         sigc::mem_fun
+                         (*this,
+                          &Priv::append_a_local_variable_and_update_all));
+                } else {
+                    LOG_DD ("Creating a varobj for var " << (*i)->name ());
+                    debugger->create_variable
+                        ((*i)->name (),
+                         sigc::mem_fun (*this,
+                                        &Priv::append_a_local_variable));
+                }
+                added_new_vars = true;
+            }
+        }
+
+        // If some old variables we had don't exist anymore, remove
+        // them from the widget.
+        IDebugger::VariableList to_remove;
+        for (IDebugger::VariableList::const_iterator i = local_vars.begin ();
+             i != local_vars.end ();
+             ++i) {
+            if (!is_variable_in_list ((*i)->name (), a_vars))
+                to_remove.push_back (*i);
+        }
+        for (IDebugger::VariableList::const_iterator i = to_remove.begin ();
+             i != to_remove.end ();
+             ++i)
+            remove_a_local_variable (*i);
+
+        // If we didn't add any new variable to the widget, let's not
+        // forget to update the content of the old ones we already
+        // had.
+        if (!added_new_vars) {
+            LOG_DD ("No new local variable was added.  "
+                    "Update existing local variables nonetheless");
+            update_local_variables ();
+        }
+    }
+
+    /// First -- if the user wants the list of local variables to be
+    /// updated at each stop -- update the list of local variables.
+    /// That way, if new variables appeared in the current scope since
+    /// the previous stop, we'll get them.  Second, update the content
+    /// of all the variables that were already present at the previous
+    /// stop.
+    void
+    maybe_update_list_of_local_vars_and_then_update_older_ones ()
+    {
+        LOG_FUNCTION_SCOPE_NORMAL_DD;
+
+        IConfMgrSafePtr conf_mgr = workbench.get_configuration_manager ();
+        bool do_update = false;
+        conf_mgr->get_key_value (CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP,
+                                 do_update);
+        if (do_update) {
+            LOG_DD ("updating the list and content of local variables");
+            debugger->list_local_variables
+                (sigc::mem_fun
+                 (*this,
+                  &Priv::add_new_local_vars_and_update_olders));
+        } else {
+            LOG_DD ("just updating the content of local variables");
+            update_local_variables ();
+        }
+    }
+
+    /// Return true if a variable named @a_name is present among the
+    /// list of local variables of this function, false otherwise.
+    bool
+    is_variable_in_list (const UString &a_name,
+                         const IDebugger::VariableList &a_vars)
+    {
+        for (IDebugger::VariableList::const_iterator i = a_vars.begin ();
+             i != a_vars.end ();
+             ++i)
+            if (a_name == (*i)->name ())
+                return true;
+        return false;
+    }
+
     void
     update_local_variables ()
     {
@@ -760,31 +927,6 @@ public:
     }
 
     void
-    on_local_variables_listed_signal
-                            (const IDebugger::VariableList &a_vars,
-                             const UString & /* a_cookie */)
-    {
-        LOG_FUNCTION_SCOPE_NORMAL_DD;
-
-        NEMIVER_TRY
-
-        UString name;
-        for (IDebugger::VariableList::const_iterator it = a_vars.begin ();
-             it != a_vars.end ();
-             ++it) {
-            name = (*it)->name ();
-            if (name.empty ()) {
-                continue;
-            }
-            LOG_DD ("creating variable '" << name << "'");
-            debugger->create_variable
-                (name, sigc::mem_fun (*this,
-                                      &Priv::on_local_variable_created_signal));
-        }
-        NEMIVER_CATCH
-    }
-
-    void
     on_local_variable_updated_signal (const IDebugger::VariableList &a_vars)
     {
         LOG_FUNCTION_SCOPE_NORMAL_DD;
@@ -1232,7 +1374,9 @@ LocalVarsInspector::show_local_variables_of_current_function
     m_priv->saved_frame = a_frame;
 
     re_init_widget ();
-    m_priv->debugger->list_local_variables ();
+    m_priv->debugger->list_local_variables
+        (sigc::mem_fun (*m_priv, &Priv::add_new_local_vars_and_update_olders));
+
     int frame_level = m_priv->debugger->get_current_frame_level ();
     LOG_DD ("current frame level: " <<  (int)frame_level);
     m_priv->debugger->list_frames_arguments (frame_level, frame_level,
diff --git a/src/persp/dbgperspective/nmv-preferences-dialog.cc 
b/src/persp/dbgperspective/nmv-preferences-dialog.cc
index 1d47c15..d40d1a5 100644
--- a/src/persp/dbgperspective/nmv-preferences-dialog.cc
+++ b/src/persp/dbgperspective/nmv-preferences-dialog.cc
@@ -90,6 +90,7 @@ public:
     Gtk::RadioButton *always_reload_radio_button;
     Gtk::RadioButton *never_reload_radio_button;
     Gtk::RadioButton *confirm_reload_radio_button;
+    Gtk::CheckButton *update_local_vars_check_button;
     Gtk::RadioButton *pure_asm_radio_button;
     Gtk::RadioButton *mixed_asm_radio_button;
     Gtk::RadioButton *follow_parent_radio_button;
@@ -117,6 +118,7 @@ public:
         always_reload_radio_button (0),
         never_reload_radio_button (0),
         confirm_reload_radio_button (0),
+        update_local_vars_check_button (0),
         pure_asm_radio_button (0),
         mixed_asm_radio_button (0),
         follow_parent_radio_button (0),
@@ -232,6 +234,12 @@ public:
     }
 
     void
+    on_local_vars_list_updated_signal ()
+    {
+        update_local_vars_list_keys ();
+    }
+
+    void
     on_asm_style_toggled_signal ()
     {
         update_asm_style_keys ();
@@ -415,10 +423,19 @@ public:
         // Handle the "Debugger" preferences tab
         // *************************************
 
+        update_local_vars_check_button =
+            ui_utils::get_widget_from_gtkbuilder<Gtk::CheckButton>
+            (gtkbuilder, "updatelocalvarslistcheckbutton");
+        THROW_IF_FAIL (update_local_vars_check_button);
+        update_local_vars_check_button->signal_toggled ().connect
+            (sigc::mem_fun
+             (*this, &PreferencesDialog::Priv::on_local_vars_list_updated_signal));
+
         pure_asm_radio_button =
             ui_utils::get_widget_from_gtkbuilder<Gtk::RadioButton>
-                (gtkbuilder, "pureasmradio");
+            (gtkbuilder, "pureasmradio");
         THROW_IF_FAIL (pure_asm_radio_button);
+
         pure_asm_radio_button->signal_toggled ().connect
             (sigc::mem_fun
                  (*this,
@@ -661,6 +678,19 @@ public:
     }
 
     void
+    update_local_vars_list_keys ()
+    {
+        THROW_IF_FAIL (update_local_vars_check_button);
+
+        bool value = false;
+        if (update_local_vars_check_button->get_active ())
+            value = true;
+
+        conf_manager ().set_key_value (CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP,
+                                       value);
+    }
+
+    void
     update_asm_style_keys ()
     {
         THROW_IF_FAIL (pure_asm_radio_button);
@@ -824,6 +854,13 @@ public:
         THROW_IF_FAIL (default_num_asm_instrs_spin_button);
         THROW_IF_FAIL (gdb_binary_path_chooser_button);
 
+        bool update_local_vars_at_each_stop = true;
+        if (!conf_manager ().get_key_value (CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP,
+                                            update_local_vars_at_each_stop)) {
+            LOG_ERROR ("failed to get conf key"
+                       << CONF_KEY_UPDATE_LOCAL_VARS_AT_EACH_STOP);
+        }
+
         bool pure_asm = false;
         if (!conf_manager ().get_key_value (CONF_KEY_ASM_STYLE_PURE,
                                             pure_asm)) {
diff --git a/src/persp/dbgperspective/ui/preferencesdialog.ui 
b/src/persp/dbgperspective/ui/preferencesdialog.ui
index b01f947..fa80a3f 100644
--- a/src/persp/dbgperspective/ui/preferencesdialog.ui
+++ b/src/persp/dbgperspective/ui/preferencesdialog.ui
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <interface>
   <!-- interface-requires gtk+ 2.6 -->
+  <!-- interface-naming-policy toplevel-contextual -->
   <object class="GtkDialog" id="preferencesdialog">
     <property name="visible">True</property>
     <property name="can_focus">False</property>
@@ -10,12 +11,11 @@
     <property name="type_hint">dialog</property>
     <property name="skip_taskbar_hint">True</property>
     <child internal-child="vbox">
-      <object class="GtkBox" id="dialog-vbox1">
+      <object class="GtkVBox" id="dialog-vbox1">
         <property name="visible">True</property>
         <property name="can_focus">False</property>
-        <property name="orientation">vertical</property>
         <child internal-child="action_area">
-          <object class="GtkButtonBox" id="dialog-action_area1">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
             <property name="visible">True</property>
             <property name="can_focus">False</property>
             <property name="layout_style">end</property>
@@ -26,7 +26,6 @@
                 <property name="can_focus">True</property>
                 <property name="can_default">True</property>
                 <property name="receives_default">False</property>
-                <property name="use_action_appearance">False</property>
                 <property name="use_stock">True</property>
               </object>
               <packing>
@@ -77,7 +76,6 @@
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">False</property>
-                                <property name="use_action_appearance">False</property>
                                 <property name="use_underline">True</property>
                                 <property name="active">True</property>
                                 <property name="draw_indicator">True</property>
@@ -111,7 +109,6 @@
                                     <property name="visible">True</property>
                                     <property name="can_focus">True</property>
                                     <property name="receives_default">False</property>
-                                    <property name="use_action_appearance">False</property>
                                   </object>
                                   <packing>
                                     <property name="expand">True</property>
@@ -202,7 +199,6 @@
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="receives_default">False</property>
-                            <property name="use_action_appearance">False</property>
                             <property name="use_underline">True</property>
                             <property name="active">True</property>
                             <property name="draw_indicator">True</property>
@@ -245,7 +241,6 @@
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="receives_default">False</property>
-                            <property name="use_action_appearance">False</property>
                             <property name="use_underline">True</property>
                             <property name="draw_indicator">True</property>
                           </object>
@@ -314,7 +309,6 @@
                                         <property name="visible">True</property>
                                         <property name="can_focus">True</property>
                                         <property name="receives_default">False</property>
-                                        <property name="use_action_appearance">False</property>
                                         <property name="use_underline">True</property>
                                         <property name="draw_indicator">True</property>
                                       </object>
@@ -330,7 +324,6 @@
                                         <property name="visible">True</property>
                                         <property name="can_focus">True</property>
                                         <property name="receives_default">False</property>
-                                        <property name="use_action_appearance">False</property>
                                         <property name="use_underline">True</property>
                                         <property name="draw_indicator">True</property>
                                         <property name="group">reloadradiobutton</property>
@@ -347,7 +340,6 @@
                                         <property name="visible">True</property>
                                         <property name="can_focus">True</property>
                                         <property name="receives_default">False</property>
-                                        <property name="use_action_appearance">False</property>
                                         <property name="use_underline">True</property>
                                         <property name="draw_indicator">True</property>
                                         <property name="group">reloadradiobutton</property>
@@ -406,7 +398,6 @@
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="receives_default">False</property>
-                            <property name="use_action_appearance">False</property>
                             <property name="use_underline">True</property>
                             <property name="active">True</property>
                             <property name="draw_indicator">True</property>
@@ -462,9 +453,6 @@
                           <object class="GtkTreeView" id="dirstreeview">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
-                            <child internal-child="selection">
-                              <object class="GtkTreeSelection" id="treeview-selection1"/>
-                            </child>
                           </object>
                         </child>
                       </object>
@@ -485,7 +473,6 @@
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="receives_default">False</property>
-                            <property name="use_action_appearance">False</property>
                             <property name="use_stock">True</property>
                           </object>
                           <packing>
@@ -500,7 +487,6 @@
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="receives_default">False</property>
-                            <property name="use_action_appearance">False</property>
                             <property name="use_stock">True</property>
                           </object>
                           <packing>
@@ -552,6 +538,44 @@
                     <property name="label_xalign">0</property>
                     <property name="shadow_type">none</property>
                     <child>
+                      <object class="GtkAlignment" id="alignment14">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="left_padding">12</property>
+                        <child>
+                          <object class="GtkCheckButton" id="updatelocalvarslistcheckbutton">
+                            <property name="label" translatable="yes">Update at each stop</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="receives_default">False</property>
+                            <property name="active">True</property>
+                            <property name="draw_indicator">True</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="label">
+                      <object class="GtkLabel" id="label21">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="label" translatable="yes">&lt;b&gt;Local 
variables&lt;/b&gt;</property>
+                        <property name="use_markup">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkFrame" id="frame8">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="label_xalign">0</property>
+                    <property name="shadow_type">none</property>
+                    <child>
                       <object class="GtkAlignment" id="alignment8">
                         <property name="visible">True</property>
                         <property name="can_focus">False</property>
@@ -567,7 +591,6 @@
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">False</property>
-                                <property name="use_action_appearance">False</property>
                                 <property name="use_underline">True</property>
                                 <property name="draw_indicator">True</property>
                               </object>
@@ -583,7 +606,6 @@
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">False</property>
-                                <property name="use_action_appearance">False</property>
                                 <property name="use_underline">True</property>
                                 <property name="draw_indicator">True</property>
                                 <property name="group">pureasmradio</property>
@@ -612,11 +634,11 @@
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
-                    <property name="position">0</property>
+                    <property name="position">1</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkFrame" id="frame8">
+                  <object class="GtkFrame" id="frame9">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="label_xalign">0</property>
@@ -653,11 +675,11 @@
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
-                    <property name="position">1</property>
+                    <property name="position">2</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkFrame" id="frame9">
+                  <object class="GtkFrame" id="frame10">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="label_xalign">0</property>
@@ -696,7 +718,7 @@
                               </object>
                               <packing>
                                 <property name="x_options">GTK_FILL</property>
-                                <property name="y_options"></property>
+                                <property name="y_options"/>
                               </packing>
                             </child>
                           </object>
@@ -717,7 +739,7 @@
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
-                    <property name="position">2</property>
+                    <property name="position">3</property>
                   </packing>
                 </child>
                 <child>
@@ -743,13 +765,17 @@
                               <object class="GtkSpinButton" id="defaultnumasmspin">
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
+                                <property name="primary_icon_activatable">False</property>
+                                <property name="secondary_icon_activatable">False</property>
+                                <property name="primary_icon_sensitive">True</property>
+                                <property name="secondary_icon_sensitive">True</property>
                                 <property name="climb_rate">1</property>
                                 <property name="numeric">True</property>
                               </object>
                               <packing>
                                 <property name="left_attach">1</property>
                                 <property name="right_attach">2</property>
-                                <property name="y_options"></property>
+                                <property name="y_options"/>
                               </packing>
                             </child>
                             <child>
@@ -761,7 +787,7 @@
                               </object>
                               <packing>
                                 <property name="x_options">GTK_FILL</property>
-                                <property name="y_options"></property>
+                                <property name="y_options"/>
                               </packing>
                             </child>
                           </object>
@@ -782,11 +808,11 @@
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
-                    <property name="position">2</property>
+                    <property name="position">3</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkFrame" id="frame11">
+                  <object class="GtkFrame" id="frame13">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="label_xalign">0</property>
@@ -803,7 +829,6 @@
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
                             <property name="receives_default">False</property>
-                            <property name="use_action_appearance">False</property>
                             <property name="active">True</property>
                             <property name="draw_indicator">True</property>
                           </object>
@@ -824,11 +849,11 @@
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
-                    <property name="position">4</property>
+                    <property name="position">5</property>
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkFrame" id="frame10">
+                  <object class="GtkFrame" id="frame11">
                     <property name="visible">True</property>
                     <property name="can_focus">False</property>
                     <property name="label_xalign">0</property>
@@ -849,7 +874,6 @@
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">False</property>
-                                <property name="use_action_appearance">False</property>
                                 <property name="use_underline">True</property>
                                 <property name="draw_indicator">True</property>
                               </object>
@@ -865,7 +889,6 @@
                                 <property name="visible">True</property>
                                 <property name="can_focus">True</property>
                                 <property name="receives_default">False</property>
-                                <property name="use_action_appearance">False</property>
                                 <property name="use_underline">True</property>
                                 <property name="draw_indicator">True</property>
                                 <property name="group">followparentradio</property>
@@ -894,7 +917,7 @@
                   <packing>
                     <property name="expand">False</property>
                     <property name="fill">False</property>
-                    <property name="position">4</property>
+                    <property name="position">5</property>
                   </packing>
                 </child>
               </object>
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 38877bc..1f4de79 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -29,7 +29,7 @@ endif
 noinst_PROGRAMS= \
 $(TESTS) \
 runtestcore  runteststdout  docore inout \
-pointerderef fooprog templatedvar \
+pointerderef fooprog localsinmiddle templatedvar \
 gtkmmtest dostackoverflow bigvar threads \
 forkparent forkchild prettyprint
 
@@ -47,6 +47,9 @@ gtkmmtest_LDADD= @NEMIVERUICOMMON_LIBS@
 fooprog_SOURCES=$(h)/fooprog.cc
 fooprog_LDADD=
 
+localsinmiddle_SOURCES=$(h)/locals-in-middle.cc
+localsinmiddle_LDADD=
+
 forkparent_SOURCES=$(h)/fork-parent.cc
 forkparent_LDADD=
 
diff --git a/tests/locals-in-middle.cc b/tests/locals-in-middle.cc
new file mode 100644
index 0000000..9675fe8
--- /dev/null
+++ b/tests/locals-in-middle.cc
@@ -0,0 +1,17 @@
+int
+main ()
+{
+    int a = 0;
+    a += 1;
+    a *= 2;
+
+    {
+        int b = a;
+        b += 2;
+        a = b;
+    }
+
+    int c = a;
+    c++;
+    return c;
+}
-- 
                Dodji


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]