Replace most calls to help_list and cmd_show_list
[deliverable/binutils-gdb.git] / gdb / tui / tui-hooks.c
index b982941d476b5264bcd7766fc1d5f6cbd47e034c..793ca0e446937f946def56e10e3f318416dd81cb 100644 (file)
@@ -1,12 +1,12 @@
 /* GDB hooks for TUI.
 
-   Copyright 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+   Copyright (C) 2001-2020 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -15,9 +15,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "symtab.h"
 #include "objfiles.h"
 #include "target.h"
 #include "gdbcore.h"
-#include "event-loop.h"
+#include "gdbsupport/event-loop.h"
 #include "event-top.h"
 #include "frame.h"
 #include "breakpoint.h"
-#include "gdb-events.h"
 #include "ui-out.h"
 #include "top.h"
-#include <readline/readline.h>
+#include "observable.h"
+#include "source.h"
 #include <unistd.h>
 #include <fcntl.h>
 
 #include "tui/tui.h"
+#include "tui/tui-hooks.h"
 #include "tui/tui-data.h"
 #include "tui/tui-layout.h"
 #include "tui/tui-io.h"
 #include "tui/tui-regs.h"
 #include "tui/tui-win.h"
 #include "tui/tui-stack.h"
-#include "tui/tui-windata.h"
 #include "tui/tui-winsource.h"
 
-#ifdef HAVE_NCURSES_H
-#include <ncurses.h>
-#else
-#ifdef HAVE_CURSES_H
-#include <curses.h>
-#endif
-#endif
-
-int tui_target_has_run = 0;
-
-static void (* tui_target_new_objfile_chain) (struct objfile*);
+#include "gdb_curses.h"
 
 static void
 tui_new_objfile_hook (struct objfile* objfile)
 {
   if (tui_active)
     tui_display_main ();
-  
-  if (tui_target_new_objfile_chain)
-    tui_target_new_objfile_chain (objfile);
 }
 
-static int
-tui_query_hook (const char * msg, va_list argp)
-{
-  int retval;
-  int ans2;
-  int answer;
+/* Prevent recursion of deprecated_register_changed_hook().  */
+static bool tui_refreshing_registers = false;
 
-  /* Automatically answer "yes" if input is not from a terminal.  */
-  if (!input_from_terminal_p ())
-    return 1;
-
-  echo ();
-  while (1)
-    {
-      wrap_here ("");          /* Flush any buffered output */
-      gdb_flush (gdb_stdout);
+/* Observer for the register_changed notification.  */
 
-      vfprintf_filtered (gdb_stdout, msg, argp);
-      printf_filtered ("(y or n) ");
+static void
+tui_register_changed (struct frame_info *frame, int regno)
+{
+  struct frame_info *fi;
 
-      wrap_here ("");
-      gdb_flush (gdb_stdout);
+  if (!tui_is_window_visible (DATA_WIN))
+    return;
 
-      answer = tui_getc (stdin);
-      clearerr (stdin);                /* in case of C-d */
-      if (answer == EOF)       /* C-d */
-       {
-         retval = 1;
-         break;
-       }
-      /* Eat rest of input line, to EOF or newline */
-      if (answer != '\n')
-       do
-         {
-            ans2 = tui_getc (stdin);
-           clearerr (stdin);
-         }
-       while (ans2 != EOF && ans2 != '\n' && ans2 != '\r');
-
-      if (answer >= 'a')
-       answer -= 040;
-      if (answer == 'Y')
-       {
-         retval = 1;
-         break;
-       }
-      if (answer == 'N')
-       {
-         retval = 0;
-         break;
-       }
-      printf_filtered ("Please answer y or n.\n");
+  /* The frame of the register that was changed may differ from the selected
+     frame, but we only want to show the register values of the selected frame.
+     And even if the frames differ a register change made in one can still show
+     up in the other.  So we always use the selected frame here, and ignore
+     FRAME.  */
+  fi = get_selected_frame (NULL);
+  if (!tui_refreshing_registers)
+    {
+      tui_refreshing_registers = true;
+      TUI_DATA_WIN->check_register_values (fi);
+      tui_refreshing_registers = false;
     }
-  noecho ();
-  return retval;
 }
 
-/* Prevent recursion of registers_changed_hook().  */
-static int tui_refreshing_registers = 0;
+/* Breakpoint creation hook.
+   Update the screen to show the new breakpoint.  */
+static void
+tui_event_create_breakpoint (struct breakpoint *b)
+{
+  tui_update_all_breakpoint_info (nullptr);
+}
 
+/* Breakpoint deletion hook.
+   Refresh the screen to update the breakpoint marks.  */
 static void
-tui_registers_changed_hook (void)
+tui_event_delete_breakpoint (struct breakpoint *b)
 {
-  struct frame_info *fi;
+  tui_update_all_breakpoint_info (b);
+}
 
-  fi = deprecated_selected_frame;
-  if (fi && tui_refreshing_registers == 0)
-    {
-      tui_refreshing_registers = 1;
-#if 0
-      tuiCheckDataValues (fi);
-#endif
-      tui_refreshing_registers = 0;
-    }
+static void
+tui_event_modify_breakpoint (struct breakpoint *b)
+{
+  tui_update_all_breakpoint_info (nullptr);
 }
 
+/* This is set to true if the next window refresh should come from the
+   current stack frame.  */
+
+static bool from_stack;
+
+/* This is set to true if the next window refresh should come from the
+   current source symtab.  */
+
+static bool from_source_symtab;
+
+/* Refresh TUI's frame and register information.  This is a hook intended to be
+   used to update the screen after potential frame and register changes.  */
+
 static void
-tui_register_changed_hook (int regno)
+tui_refresh_frame_and_register_information ()
 {
-  struct frame_info *fi;
+  if (!from_stack && !from_source_symtab)
+    return;
+
+  target_terminal::scoped_restore_terminal_state term_state;
+  target_terminal::ours_for_output ();
 
-  fi = deprecated_selected_frame;
-  if (fi && tui_refreshing_registers == 0)
+  if (from_stack && has_stack_frames ())
     {
-      tui_refreshing_registers = 1;
-      tui_check_data_values (fi);
-      tui_refreshing_registers = 0;
+      struct frame_info *fi = get_selected_frame (NULL);
+
+      /* Display the frame position (even if there is no symbols or
+        the PC is not known).  */
+      bool frame_info_changed_p = tui_show_frame_info (fi);
+
+      /* Refresh the register window if it's visible.  */
+      if (tui_is_window_visible (DATA_WIN)
+         && (frame_info_changed_p || from_stack))
+       {
+         tui_refreshing_registers = true;
+         TUI_DATA_WIN->check_register_values (fi);
+         tui_refreshing_registers = false;
+       }
+    }
+  else if (!from_stack)
+    {
+      /* Make sure that the source window is displayed.  */
+      tui_add_win_to_layout (SRC_WIN);
+
+      struct symtab_and_line sal = get_current_source_symtab_and_line ();
+      tui_update_source_windows_with_line (sal);
     }
 }
 
-/* Breakpoint creation hook.
-   Update the screen to show the new breakpoint.  */
+/* Dummy callback for deprecated_print_frame_info_listing_hook which is called
+   from print_frame_info.  */
+
 static void
-tui_event_create_breakpoint (int number)
+tui_dummy_print_frame_info_listing_hook (struct symtab *s,
+                                        int line,
+                                        int stopline, 
+                                        int noerror)
 {
-  tui_update_all_breakpoint_info ();
 }
 
-/* Breakpoint deletion hook.
-   Refresh the screen to update the breakpoint marks.  */
+/* Perform all necessary cleanups regarding our module's inferior data
+   that is required after the inferior INF just exited.  */
+
 static void
-tui_event_delete_breakpoint (int number)
+tui_inferior_exit (struct inferior *inf)
 {
-  tui_update_all_breakpoint_info ();
+  /* Leave the SingleKey mode to make sure the gdb prompt is visible.  */
+  tui_set_key_mode (TUI_COMMAND_MODE);
+  tui_show_frame_info (0);
+  tui_display_main ();
 }
 
+/* Observer for the before_prompt notification.  */
+
 static void
-tui_event_modify_breakpoint (int number)
+tui_before_prompt (const char *current_gdb_prompt)
 {
-  tui_update_all_breakpoint_info ();
+  tui_refresh_frame_and_register_information ();
+  from_stack = false;
+  from_source_symtab = false;
 }
 
+/* Observer for the normal_stop notification.  */
+
 static void
-tui_event_default (int number)
+tui_normal_stop (struct bpstats *bs, int print_frame)
 {
-  ;
+  from_stack = true;
 }
 
-static struct gdb_events *tui_old_event_hooks;
+/* Observer for user_selected_context_changed.  */
 
-static struct gdb_events tui_event_hooks =
-{
-  tui_event_create_breakpoint,
-  tui_event_delete_breakpoint,
-  tui_event_modify_breakpoint,
-  tui_event_default,
-  tui_event_default,
-  tui_event_default
-};
-
-/* Called when going to wait for the target.
-   Leave curses mode and setup program mode.  */
-static ptid_t
-tui_target_wait_hook (ptid_t pid, struct target_waitstatus *status)
+static void
+tui_context_changed (user_selected_what ignore)
 {
-  ptid_t res;
-
-  /* Leave tui mode (optional).  */
-#if 0
-  if (tui_active)
-    {
-      target_terminal_ours ();
-      endwin ();
-      target_terminal_inferior ();
-    }
-#endif
-  tui_target_has_run = 1;
-  res = target_wait (pid, status);
-
-  if (tui_active)
-    {
-      /* TODO: need to refresh (optional).  */
-    }
-  return res;
+  from_stack = true;
 }
 
-/* The selected frame has changed.  This is happens after a target
-   stop or when the user explicitly changes the frame (up/down/thread/...).  */
+/* Observer for current_source_symtab_and_line_changed.  */
+
 static void
-tui_selected_frame_level_changed_hook (int level)
+tui_symtab_changed ()
 {
-  struct frame_info *fi;
+  from_source_symtab = true;
+}
 
-  fi = deprecated_selected_frame;
-  /* Ensure that symbols for this frame are read in.  Also, determine the
-     source language of this frame, and switch to it if desired.  */
-  if (fi)
-    {
-      struct symtab *s;
-      
-      s = find_pc_symtab (get_frame_pc (fi));
-      /* elz: this if here fixes the problem with the pc not being displayed
-         in the tui asm layout, with no debug symbols. The value of s 
-         would be 0 here, and select_source_symtab would abort the
-         command by calling the 'error' function */
-      if (s)
-        select_source_symtab (s);
-
-      /* Display the frame position (even if there is no symbols).  */
-      tui_show_frame_info (fi);
+/* Token associated with observers registered while TUI hooks are
+   installed.  */
+static const gdb::observers::token tui_observers_token {};
 
-      /* Refresh the register window if it's visible.  */
-      if (tui_is_window_visible (DATA_WIN))
-        {
-          tui_refreshing_registers = 1;
-          tui_check_data_values (fi);
-          tui_refreshing_registers = 0;
-        }
-    }
-}
+/* Attach or detach a single observer, according to ATTACH.  */
 
-/* Called from print_frame_info to list the line we stopped in.  */
+template<typename T>
 static void
-tui_print_frame_info_listing_hook (struct symtab *s, int line,
-                                   int stopline, int noerror)
+attach_or_detach (T &observable, typename T::func_type func, bool attach)
 {
-  select_source_symtab (s);
-  tui_show_frame_info (deprecated_selected_frame);
+  if (attach)
+    observable.attach (func, tui_observers_token);
+  else
+    observable.detach (tui_observers_token);
 }
 
-/* Called when the target process died or is detached.
-   Update the status line.  */
+/* Attach or detach TUI observers, according to ATTACH.  */
+
 static void
-tui_detach_hook (void)
+tui_attach_detach_observers (bool attach)
 {
-  tui_show_frame_info (0);
-  tui_display_main ();
+  attach_or_detach (gdb::observers::breakpoint_created,
+                   tui_event_create_breakpoint, attach);
+  attach_or_detach (gdb::observers::breakpoint_deleted,
+                   tui_event_delete_breakpoint, attach);
+  attach_or_detach (gdb::observers::breakpoint_modified,
+                   tui_event_modify_breakpoint, attach);
+  attach_or_detach (gdb::observers::inferior_exit,
+                   tui_inferior_exit, attach);
+  attach_or_detach (gdb::observers::before_prompt,
+                   tui_before_prompt, attach);
+  attach_or_detach (gdb::observers::normal_stop,
+                   tui_normal_stop, attach);
+  attach_or_detach (gdb::observers::register_changed,
+                   tui_register_changed, attach);
+  attach_or_detach (gdb::observers::user_selected_context_changed,
+                   tui_context_changed, attach);
+  attach_or_detach (gdb::observers::current_source_symtab_and_line_changed,
+                   tui_symtab_changed, attach);
 }
 
 /* Install the TUI specific hooks.  */
 void
 tui_install_hooks (void)
 {
-  target_wait_hook = tui_target_wait_hook;
-  selected_frame_level_changed_hook = tui_selected_frame_level_changed_hook;
-  print_frame_info_listing_hook = tui_print_frame_info_listing_hook;
-
-  query_hook = tui_query_hook;
+  /* If this hook is not set to something then print_frame_info will
+     assume that the CLI, not the TUI, is active, and will print the frame info
+     for us in such a way that we are not prepared to handle.  This hook is
+     otherwise effectively obsolete.  */
+  deprecated_print_frame_info_listing_hook
+    = tui_dummy_print_frame_info_listing_hook;
 
   /* Install the event hooks.  */
-  tui_old_event_hooks = set_gdb_event_hooks (&tui_event_hooks);
-
-  registers_changed_hook = tui_registers_changed_hook;
-  register_changed_hook = tui_register_changed_hook;
-  detach_hook = tui_detach_hook;
+  tui_attach_detach_observers (true);
 }
 
 /* Remove the TUI specific hooks.  */
 void
 tui_remove_hooks (void)
 {
-  target_wait_hook = 0;
-  selected_frame_level_changed_hook = 0;
-  print_frame_info_listing_hook = 0;
-  query_hook = 0;
-  registers_changed_hook = 0;
-  register_changed_hook = 0;
-  detach_hook = 0;
-
-  /* Restore the previous event hooks.  */
-  set_gdb_event_hooks (tui_old_event_hooks);
-}
+  deprecated_print_frame_info_listing_hook = 0;
 
-void _initialize_tui_hooks (void);
+  /* Remove our observers.  */
+  tui_attach_detach_observers (false);
+}
 
+void _initialize_tui_hooks ();
 void
-_initialize_tui_hooks (void)
+_initialize_tui_hooks ()
 {
   /* Install the permanent hooks.  */
-  tui_target_new_objfile_chain = target_new_objfile_hook;
-  target_new_objfile_hook = tui_new_objfile_hook;
+  gdb::observers::new_objfile.attach (tui_new_objfile_hook);
 }
This page took 0.030476 seconds and 4 git commands to generate.