144d93782SGreg Clayton //===-- IOHandler.cpp -------------------------------------------*- C++ -*-===//
244d93782SGreg Clayton //
344d93782SGreg Clayton //                     The LLVM Compiler Infrastructure
444d93782SGreg Clayton //
544d93782SGreg Clayton // This file is distributed under the University of Illinois Open Source
644d93782SGreg Clayton // License. See LICENSE.TXT for details.
744d93782SGreg Clayton //
844d93782SGreg Clayton //===----------------------------------------------------------------------===//
944d93782SGreg Clayton 
1044d93782SGreg Clayton 
1144d93782SGreg Clayton #include "lldb/lldb-python.h"
1244d93782SGreg Clayton 
1344d93782SGreg Clayton #include <stdio.h>	/* ioctl, TIOCGWINSZ */
1444d93782SGreg Clayton #include <sys/ioctl.h>	/* ioctl, TIOCGWINSZ */
1544d93782SGreg Clayton 
1644d93782SGreg Clayton 
1744d93782SGreg Clayton #include <string>
1844d93782SGreg Clayton 
1944d93782SGreg Clayton #include "lldb/Breakpoint/BreakpointLocation.h"
2044d93782SGreg Clayton #include "lldb/Core/IOHandler.h"
2144d93782SGreg Clayton #include "lldb/Core/Debugger.h"
2244d93782SGreg Clayton #include "lldb/Core/State.h"
2344d93782SGreg Clayton #include "lldb/Core/StreamFile.h"
2444d93782SGreg Clayton #include "lldb/Core/ValueObjectRegister.h"
2544d93782SGreg Clayton #include "lldb/Host/Editline.h"
2644d93782SGreg Clayton #include "lldb/Interpreter/CommandCompletions.h"
2744d93782SGreg Clayton #include "lldb/Interpreter/CommandInterpreter.h"
2844d93782SGreg Clayton #include "lldb/Symbol/Block.h"
2944d93782SGreg Clayton #include "lldb/Symbol/Function.h"
3044d93782SGreg Clayton #include "lldb/Symbol/Symbol.h"
3144d93782SGreg Clayton #include "lldb/Target/RegisterContext.h"
3244d93782SGreg Clayton #include "lldb/Target/ThreadPlan.h"
3344d93782SGreg Clayton 
3444d93782SGreg Clayton #include <ncurses.h>
3544d93782SGreg Clayton #include <panel.h>
3644d93782SGreg Clayton 
3744d93782SGreg Clayton using namespace lldb;
3844d93782SGreg Clayton using namespace lldb_private;
3944d93782SGreg Clayton 
4044d93782SGreg Clayton IOHandler::IOHandler (Debugger &debugger) :
4144d93782SGreg Clayton     IOHandler (debugger,
4244d93782SGreg Clayton                StreamFileSP(), // Adopt STDIN from top input reader
4344d93782SGreg Clayton                StreamFileSP(), // Adopt STDOUT from top input reader
4444d93782SGreg Clayton                StreamFileSP()) // Adopt STDERR from top input reader
4544d93782SGreg Clayton {
4644d93782SGreg Clayton }
4744d93782SGreg Clayton 
4844d93782SGreg Clayton 
4944d93782SGreg Clayton IOHandler::IOHandler (Debugger &debugger,
5044d93782SGreg Clayton                       const lldb::StreamFileSP &input_sp,
5144d93782SGreg Clayton                       const lldb::StreamFileSP &output_sp,
5244d93782SGreg Clayton                       const lldb::StreamFileSP &error_sp) :
5344d93782SGreg Clayton     m_debugger (debugger),
5444d93782SGreg Clayton     m_input_sp (input_sp),
5544d93782SGreg Clayton     m_output_sp (output_sp),
5644d93782SGreg Clayton     m_error_sp (error_sp),
5744d93782SGreg Clayton     m_user_data (NULL),
5844d93782SGreg Clayton     m_done (false),
5944d93782SGreg Clayton     m_active (false)
6044d93782SGreg Clayton {
6144d93782SGreg Clayton     // If any files are not specified, then adopt them from the top input reader.
6244d93782SGreg Clayton     if (!m_input_sp || !m_output_sp || !m_error_sp)
6344d93782SGreg Clayton         debugger.AdoptTopIOHandlerFilesIfInvalid (m_input_sp,
6444d93782SGreg Clayton                                                   m_output_sp,
6544d93782SGreg Clayton                                                   m_error_sp);
6644d93782SGreg Clayton }
6744d93782SGreg Clayton 
6844d93782SGreg Clayton IOHandler::~IOHandler()
6944d93782SGreg Clayton {
7044d93782SGreg Clayton }
7144d93782SGreg Clayton 
7244d93782SGreg Clayton 
7344d93782SGreg Clayton int
7444d93782SGreg Clayton IOHandler::GetInputFD()
7544d93782SGreg Clayton {
7644d93782SGreg Clayton     if (m_input_sp)
7744d93782SGreg Clayton         return m_input_sp->GetFile().GetDescriptor();
7844d93782SGreg Clayton     return -1;
7944d93782SGreg Clayton }
8044d93782SGreg Clayton 
8144d93782SGreg Clayton int
8244d93782SGreg Clayton IOHandler::GetOutputFD()
8344d93782SGreg Clayton {
8444d93782SGreg Clayton     if (m_output_sp)
8544d93782SGreg Clayton         return m_output_sp->GetFile().GetDescriptor();
8644d93782SGreg Clayton     return -1;
8744d93782SGreg Clayton }
8844d93782SGreg Clayton 
8944d93782SGreg Clayton int
9044d93782SGreg Clayton IOHandler::GetErrorFD()
9144d93782SGreg Clayton {
9244d93782SGreg Clayton     if (m_error_sp)
9344d93782SGreg Clayton         return m_error_sp->GetFile().GetDescriptor();
9444d93782SGreg Clayton     return -1;
9544d93782SGreg Clayton }
9644d93782SGreg Clayton 
9744d93782SGreg Clayton FILE *
9844d93782SGreg Clayton IOHandler::GetInputFILE()
9944d93782SGreg Clayton {
10044d93782SGreg Clayton     if (m_input_sp)
10144d93782SGreg Clayton         return m_input_sp->GetFile().GetStream();
10244d93782SGreg Clayton     return NULL;
10344d93782SGreg Clayton }
10444d93782SGreg Clayton 
10544d93782SGreg Clayton FILE *
10644d93782SGreg Clayton IOHandler::GetOutputFILE()
10744d93782SGreg Clayton {
10844d93782SGreg Clayton     if (m_output_sp)
10944d93782SGreg Clayton         return m_output_sp->GetFile().GetStream();
11044d93782SGreg Clayton     return NULL;
11144d93782SGreg Clayton }
11244d93782SGreg Clayton 
11344d93782SGreg Clayton FILE *
11444d93782SGreg Clayton IOHandler::GetErrorFILE()
11544d93782SGreg Clayton {
11644d93782SGreg Clayton     if (m_error_sp)
11744d93782SGreg Clayton         return m_error_sp->GetFile().GetStream();
11844d93782SGreg Clayton     return NULL;
11944d93782SGreg Clayton }
12044d93782SGreg Clayton 
12144d93782SGreg Clayton StreamFileSP &
12244d93782SGreg Clayton IOHandler::GetInputStreamFile()
12344d93782SGreg Clayton {
12444d93782SGreg Clayton     return m_input_sp;
12544d93782SGreg Clayton }
12644d93782SGreg Clayton 
12744d93782SGreg Clayton StreamFileSP &
12844d93782SGreg Clayton IOHandler::GetOutputStreamFile()
12944d93782SGreg Clayton {
13044d93782SGreg Clayton     return m_output_sp;
13144d93782SGreg Clayton }
13244d93782SGreg Clayton 
13344d93782SGreg Clayton 
13444d93782SGreg Clayton StreamFileSP &
13544d93782SGreg Clayton IOHandler::GetErrorStreamFile()
13644d93782SGreg Clayton {
13744d93782SGreg Clayton     return m_error_sp;
13844d93782SGreg Clayton }
13944d93782SGreg Clayton 
14044d93782SGreg Clayton 
14144d93782SGreg Clayton IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
14244d93782SGreg Clayton                                     const char *prompt,
14344d93782SGreg Clayton                                     bool default_response) :
14444d93782SGreg Clayton     IOHandlerEditline(debugger,
14544d93782SGreg Clayton                       NULL,     // NULL editline_name means no history loaded/saved
14644d93782SGreg Clayton                       NULL,
14744d93782SGreg Clayton                       false,    // Multi-line
14844d93782SGreg Clayton                       *this),
14944d93782SGreg Clayton     m_default_response (default_response),
15044d93782SGreg Clayton     m_user_response (default_response)
15144d93782SGreg Clayton {
15244d93782SGreg Clayton     StreamString prompt_stream;
15344d93782SGreg Clayton     prompt_stream.PutCString(prompt);
15444d93782SGreg Clayton     if (m_default_response)
15544d93782SGreg Clayton         prompt_stream.Printf(": [Y/n] ");
15644d93782SGreg Clayton     else
15744d93782SGreg Clayton         prompt_stream.Printf(": [y/N] ");
15844d93782SGreg Clayton 
15944d93782SGreg Clayton     SetPrompt (prompt_stream.GetString().c_str());
16044d93782SGreg Clayton 
16144d93782SGreg Clayton }
16244d93782SGreg Clayton 
16344d93782SGreg Clayton 
16444d93782SGreg Clayton IOHandlerConfirm::~IOHandlerConfirm ()
16544d93782SGreg Clayton {
16644d93782SGreg Clayton }
16744d93782SGreg Clayton 
16844d93782SGreg Clayton int
16944d93782SGreg Clayton IOHandlerConfirm::IOHandlerComplete (IOHandler &io_handler,
17044d93782SGreg Clayton                                      const char *current_line,
17144d93782SGreg Clayton                                      const char *cursor,
17244d93782SGreg Clayton                                      const char *last_char,
17344d93782SGreg Clayton                                      int skip_first_n_matches,
17444d93782SGreg Clayton                                      int max_matches,
17544d93782SGreg Clayton                                      StringList &matches)
17644d93782SGreg Clayton {
17744d93782SGreg Clayton     if (current_line == cursor)
17844d93782SGreg Clayton     {
17944d93782SGreg Clayton         if (m_default_response)
18044d93782SGreg Clayton         {
18144d93782SGreg Clayton             matches.AppendString("y");
18244d93782SGreg Clayton         }
18344d93782SGreg Clayton         else
18444d93782SGreg Clayton         {
18544d93782SGreg Clayton             matches.AppendString("n");
18644d93782SGreg Clayton         }
18744d93782SGreg Clayton     }
18844d93782SGreg Clayton     return matches.GetSize();
18944d93782SGreg Clayton }
19044d93782SGreg Clayton 
19144d93782SGreg Clayton void
19244d93782SGreg Clayton IOHandlerConfirm::IOHandlerInputComplete (IOHandler &io_handler, std::string &line)
19344d93782SGreg Clayton {
19444d93782SGreg Clayton     if (line.empty())
19544d93782SGreg Clayton     {
19644d93782SGreg Clayton         // User just hit enter, set the response to the default
19744d93782SGreg Clayton         m_user_response = m_default_response;
19844d93782SGreg Clayton         io_handler.SetIsDone(true);
19944d93782SGreg Clayton         return;
20044d93782SGreg Clayton     }
20144d93782SGreg Clayton 
20244d93782SGreg Clayton     if (line.size() == 1)
20344d93782SGreg Clayton     {
20444d93782SGreg Clayton         switch (line[0])
20544d93782SGreg Clayton         {
20644d93782SGreg Clayton             case 'y':
20744d93782SGreg Clayton             case 'Y':
20844d93782SGreg Clayton                 m_user_response = true;
20944d93782SGreg Clayton                 io_handler.SetIsDone(true);
21044d93782SGreg Clayton                 return;
21144d93782SGreg Clayton             case 'n':
21244d93782SGreg Clayton             case 'N':
21344d93782SGreg Clayton                 m_user_response = false;
21444d93782SGreg Clayton                 io_handler.SetIsDone(true);
21544d93782SGreg Clayton                 return;
21644d93782SGreg Clayton             default:
21744d93782SGreg Clayton                 break;
21844d93782SGreg Clayton         }
21944d93782SGreg Clayton     }
22044d93782SGreg Clayton 
22144d93782SGreg Clayton     if (line == "yes" || line == "YES" || line == "Yes")
22244d93782SGreg Clayton     {
22344d93782SGreg Clayton         m_user_response = true;
22444d93782SGreg Clayton         io_handler.SetIsDone(true);
22544d93782SGreg Clayton     }
22644d93782SGreg Clayton     else if (line == "no" || line == "NO" || line == "No")
22744d93782SGreg Clayton     {
22844d93782SGreg Clayton         m_user_response = false;
22944d93782SGreg Clayton         io_handler.SetIsDone(true);
23044d93782SGreg Clayton     }
23144d93782SGreg Clayton }
23244d93782SGreg Clayton 
23344d93782SGreg Clayton int
23444d93782SGreg Clayton IOHandlerDelegate::IOHandlerComplete (IOHandler &io_handler,
23544d93782SGreg Clayton                                       const char *current_line,
23644d93782SGreg Clayton                                       const char *cursor,
23744d93782SGreg Clayton                                       const char *last_char,
23844d93782SGreg Clayton                                       int skip_first_n_matches,
23944d93782SGreg Clayton                                       int max_matches,
24044d93782SGreg Clayton                                       StringList &matches)
24144d93782SGreg Clayton {
24244d93782SGreg Clayton     switch (m_completion)
24344d93782SGreg Clayton     {
24444d93782SGreg Clayton     case Completion::None:
24544d93782SGreg Clayton         break;
24644d93782SGreg Clayton 
24744d93782SGreg Clayton     case Completion::LLDBCommand:
24844d93782SGreg Clayton         return io_handler.GetDebugger().GetCommandInterpreter().HandleCompletion (current_line,
24944d93782SGreg Clayton                                                                                   cursor,
25044d93782SGreg Clayton                                                                                   last_char,
25144d93782SGreg Clayton                                                                                   skip_first_n_matches,
25244d93782SGreg Clayton                                                                                   max_matches,
25344d93782SGreg Clayton                                                                                   matches);
25444d93782SGreg Clayton 
25544d93782SGreg Clayton     case Completion::Expression:
25644d93782SGreg Clayton         {
25744d93782SGreg Clayton             bool word_complete = false;
25844d93782SGreg Clayton             const char *word_start = cursor;
25944d93782SGreg Clayton             if (cursor > current_line)
26044d93782SGreg Clayton                 --word_start;
26144d93782SGreg Clayton             while (word_start > current_line && !isspace(*word_start))
26244d93782SGreg Clayton                 --word_start;
26344d93782SGreg Clayton             CommandCompletions::InvokeCommonCompletionCallbacks (io_handler.GetDebugger().GetCommandInterpreter(),
26444d93782SGreg Clayton                                                                  CommandCompletions::eVariablePathCompletion,
26544d93782SGreg Clayton                                                                  word_start,
26644d93782SGreg Clayton                                                                  skip_first_n_matches,
26744d93782SGreg Clayton                                                                  max_matches,
26844d93782SGreg Clayton                                                                  NULL,
26944d93782SGreg Clayton                                                                  word_complete,
27044d93782SGreg Clayton                                                                  matches);
27144d93782SGreg Clayton 
27244d93782SGreg Clayton             size_t num_matches = matches.GetSize();
27344d93782SGreg Clayton             if (num_matches > 0)
27444d93782SGreg Clayton             {
27544d93782SGreg Clayton                 std::string common_prefix;
27644d93782SGreg Clayton                 matches.LongestCommonPrefix (common_prefix);
27744d93782SGreg Clayton                 const size_t partial_name_len = strlen(word_start);
27844d93782SGreg Clayton 
27944d93782SGreg Clayton                 // If we matched a unique single command, add a space...
28044d93782SGreg Clayton                 // Only do this if the completer told us this was a complete word, however...
28144d93782SGreg Clayton                 if (num_matches == 1 && word_complete)
28244d93782SGreg Clayton                 {
28344d93782SGreg Clayton                     common_prefix.push_back(' ');
28444d93782SGreg Clayton                 }
28544d93782SGreg Clayton                 common_prefix.erase (0, partial_name_len);
28644d93782SGreg Clayton                 matches.InsertStringAtIndex(0, std::move(common_prefix));
28744d93782SGreg Clayton             }
28844d93782SGreg Clayton             return num_matches;
28944d93782SGreg Clayton         }
29044d93782SGreg Clayton         break;
29144d93782SGreg Clayton     }
29244d93782SGreg Clayton 
29344d93782SGreg Clayton 
29444d93782SGreg Clayton     return 0;
29544d93782SGreg Clayton }
29644d93782SGreg Clayton 
29744d93782SGreg Clayton 
29844d93782SGreg Clayton IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
29944d93782SGreg Clayton                                       const char *editline_name, // Used for saving history files
30044d93782SGreg Clayton                                       const char *prompt,
30144d93782SGreg Clayton                                       bool multi_line,
30244d93782SGreg Clayton                                       IOHandlerDelegate &delegate) :
30344d93782SGreg Clayton     IOHandlerEditline(debugger,
30444d93782SGreg Clayton                       StreamFileSP(), // Inherit input from top input reader
30544d93782SGreg Clayton                       StreamFileSP(), // Inherit output from top input reader
30644d93782SGreg Clayton                       StreamFileSP(), // Inherit error from top input reader
30744d93782SGreg Clayton                       editline_name,  // Used for saving history files
30844d93782SGreg Clayton                       prompt,
30944d93782SGreg Clayton                       multi_line,
31044d93782SGreg Clayton                       delegate)
31144d93782SGreg Clayton {
31244d93782SGreg Clayton }
31344d93782SGreg Clayton 
31444d93782SGreg Clayton IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
31544d93782SGreg Clayton                                       const lldb::StreamFileSP &input_sp,
31644d93782SGreg Clayton                                       const lldb::StreamFileSP &output_sp,
31744d93782SGreg Clayton                                       const lldb::StreamFileSP &error_sp,
31844d93782SGreg Clayton                                       const char *editline_name, // Used for saving history files
31944d93782SGreg Clayton                                       const char *prompt,
32044d93782SGreg Clayton                                       bool multi_line,
32144d93782SGreg Clayton                                       IOHandlerDelegate &delegate) :
32244d93782SGreg Clayton     IOHandler (debugger, input_sp, output_sp, error_sp),
32344d93782SGreg Clayton     m_editline_ap (),
32444d93782SGreg Clayton     m_delegate (delegate),
32544d93782SGreg Clayton     m_prompt (),
32644d93782SGreg Clayton     m_multi_line (multi_line),
32744d93782SGreg Clayton     m_interactive (false)
32844d93782SGreg Clayton {
32944d93782SGreg Clayton     SetPrompt(prompt);
33044d93782SGreg Clayton 
33144d93782SGreg Clayton     const int in_fd = GetInputFD();
33244d93782SGreg Clayton     struct winsize window_size;
33344d93782SGreg Clayton     bool use_editline = false;
33444d93782SGreg Clayton     if (isatty (in_fd))
33544d93782SGreg Clayton     {
33644d93782SGreg Clayton         m_interactive = true;
33744d93782SGreg Clayton         if (::ioctl (in_fd, TIOCGWINSZ, &window_size) == 0)
33844d93782SGreg Clayton         {
33944d93782SGreg Clayton             if (window_size.ws_col > 0)
34044d93782SGreg Clayton                 use_editline = true;
34144d93782SGreg Clayton         }
34244d93782SGreg Clayton     }
34344d93782SGreg Clayton 
34444d93782SGreg Clayton     if (use_editline)
34544d93782SGreg Clayton     {
34644d93782SGreg Clayton         m_editline_ap.reset(new Editline (editline_name,
34744d93782SGreg Clayton                                           prompt ? prompt : "",
34844d93782SGreg Clayton                                           GetInputFILE (),
34944d93782SGreg Clayton                                           GetOutputFILE (),
35044d93782SGreg Clayton                                           GetErrorFILE ()));
35144d93782SGreg Clayton         m_editline_ap->SetLineCompleteCallback (LineCompletedCallback, this);
35244d93782SGreg Clayton         m_editline_ap->SetAutoCompleteCallback (AutoCompleteCallback, this);
35344d93782SGreg Clayton     }
35444d93782SGreg Clayton 
35544d93782SGreg Clayton }
35644d93782SGreg Clayton 
35744d93782SGreg Clayton IOHandlerEditline::~IOHandlerEditline ()
35844d93782SGreg Clayton {
35944d93782SGreg Clayton     m_editline_ap.reset();
36044d93782SGreg Clayton }
36144d93782SGreg Clayton 
36244d93782SGreg Clayton 
36344d93782SGreg Clayton bool
36444d93782SGreg Clayton IOHandlerEditline::GetLine (std::string &line)
36544d93782SGreg Clayton {
36644d93782SGreg Clayton     if (m_editline_ap)
36744d93782SGreg Clayton     {
36844d93782SGreg Clayton         return m_editline_ap->GetLine(line).Success();
36944d93782SGreg Clayton     }
37044d93782SGreg Clayton     else
37144d93782SGreg Clayton     {
37244d93782SGreg Clayton         line.clear();
37344d93782SGreg Clayton 
37444d93782SGreg Clayton         FILE *in = GetInputFILE();
37544d93782SGreg Clayton         if (in)
37644d93782SGreg Clayton         {
37744d93782SGreg Clayton             if (m_interactive)
37844d93782SGreg Clayton             {
37944d93782SGreg Clayton                 const char *prompt = GetPrompt();
38044d93782SGreg Clayton                 if (prompt && prompt[0])
38144d93782SGreg Clayton                 {
38244d93782SGreg Clayton                     FILE *out = GetOutputFILE();
38344d93782SGreg Clayton                     if (out)
38444d93782SGreg Clayton                     {
38544d93782SGreg Clayton                         ::fprintf(out, "%s", prompt);
38644d93782SGreg Clayton                         ::fflush(out);
38744d93782SGreg Clayton                     }
38844d93782SGreg Clayton                 }
38944d93782SGreg Clayton             }
39044d93782SGreg Clayton             char buffer[256];
39144d93782SGreg Clayton             bool done = false;
39244d93782SGreg Clayton             while (!done)
39344d93782SGreg Clayton             {
39444d93782SGreg Clayton                 if (fgets(buffer, sizeof(buffer), in) == NULL)
39544d93782SGreg Clayton                     done = true;
39644d93782SGreg Clayton                 else
39744d93782SGreg Clayton                 {
39844d93782SGreg Clayton                     size_t buffer_len = strlen(buffer);
39944d93782SGreg Clayton                     assert (buffer[buffer_len] == '\0');
40044d93782SGreg Clayton                     char last_char = buffer[buffer_len-1];
40144d93782SGreg Clayton                     if (last_char == '\r' || last_char == '\n')
40244d93782SGreg Clayton                     {
40344d93782SGreg Clayton                         done = true;
40444d93782SGreg Clayton                         // Strip trailing newlines
40544d93782SGreg Clayton                         while (last_char == '\r' || last_char == '\n')
40644d93782SGreg Clayton                         {
40744d93782SGreg Clayton                             --buffer_len;
40844d93782SGreg Clayton                             if (buffer_len == 0)
40944d93782SGreg Clayton                                 break;
41044d93782SGreg Clayton                             last_char = buffer[buffer_len-1];
41144d93782SGreg Clayton                         }
41244d93782SGreg Clayton                     }
41344d93782SGreg Clayton                     line.append(buffer, buffer_len);
41444d93782SGreg Clayton                 }
41544d93782SGreg Clayton             }
41644d93782SGreg Clayton         }
41744d93782SGreg Clayton         else
41844d93782SGreg Clayton         {
41944d93782SGreg Clayton             // No more input file, we are done...
42044d93782SGreg Clayton             SetIsDone(true);
42144d93782SGreg Clayton         }
42244d93782SGreg Clayton         return !line.empty();
42344d93782SGreg Clayton     }
42444d93782SGreg Clayton }
42544d93782SGreg Clayton 
42644d93782SGreg Clayton 
42744d93782SGreg Clayton LineStatus
42844d93782SGreg Clayton IOHandlerEditline::LineCompletedCallback (Editline *editline,
42944d93782SGreg Clayton                                           StringList &lines,
43044d93782SGreg Clayton                                           uint32_t line_idx,
43144d93782SGreg Clayton                                           Error &error,
43244d93782SGreg Clayton                                           void *baton)
43344d93782SGreg Clayton {
43444d93782SGreg Clayton     IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
43544d93782SGreg Clayton     return editline_reader->m_delegate.IOHandlerLinesUpdated(*editline_reader, lines, line_idx, error);
43644d93782SGreg Clayton }
43744d93782SGreg Clayton 
43844d93782SGreg Clayton int
43944d93782SGreg Clayton IOHandlerEditline::AutoCompleteCallback (const char *current_line,
44044d93782SGreg Clayton                                          const char *cursor,
44144d93782SGreg Clayton                                          const char *last_char,
44244d93782SGreg Clayton                                          int skip_first_n_matches,
44344d93782SGreg Clayton                                          int max_matches,
44444d93782SGreg Clayton                                          StringList &matches,
44544d93782SGreg Clayton                                          void *baton)
44644d93782SGreg Clayton {
44744d93782SGreg Clayton     IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
44844d93782SGreg Clayton     if (editline_reader)
44944d93782SGreg Clayton         return editline_reader->m_delegate.IOHandlerComplete (*editline_reader,
45044d93782SGreg Clayton                                                               current_line,
45144d93782SGreg Clayton                                                               cursor,
45244d93782SGreg Clayton                                                               last_char,
45344d93782SGreg Clayton                                                               skip_first_n_matches,
45444d93782SGreg Clayton                                                               max_matches,
45544d93782SGreg Clayton                                                               matches);
45644d93782SGreg Clayton     return 0;
45744d93782SGreg Clayton }
45844d93782SGreg Clayton 
45944d93782SGreg Clayton const char *
46044d93782SGreg Clayton IOHandlerEditline::GetPrompt ()
46144d93782SGreg Clayton {
46244d93782SGreg Clayton     if (m_editline_ap)
46344d93782SGreg Clayton         return m_editline_ap->GetPrompt ();
46444d93782SGreg Clayton     else if (m_prompt.empty())
46544d93782SGreg Clayton         return NULL;
46644d93782SGreg Clayton     return m_prompt.c_str();
46744d93782SGreg Clayton }
46844d93782SGreg Clayton 
46944d93782SGreg Clayton bool
47044d93782SGreg Clayton IOHandlerEditline::SetPrompt (const char *p)
47144d93782SGreg Clayton {
47244d93782SGreg Clayton     if (p && p[0])
47344d93782SGreg Clayton         m_prompt = p;
47444d93782SGreg Clayton     else
47544d93782SGreg Clayton         m_prompt.clear();
47644d93782SGreg Clayton     if (m_editline_ap)
47744d93782SGreg Clayton         m_editline_ap->SetPrompt (m_prompt.empty() ? NULL : m_prompt.c_str());
47844d93782SGreg Clayton     return true;
47944d93782SGreg Clayton }
48044d93782SGreg Clayton 
48144d93782SGreg Clayton bool
48244d93782SGreg Clayton IOHandlerEditline::GetLines (StringList &lines)
48344d93782SGreg Clayton {
48444d93782SGreg Clayton     bool success = false;
48544d93782SGreg Clayton     if (m_editline_ap)
48644d93782SGreg Clayton     {
48744d93782SGreg Clayton         std::string end_token;
48844d93782SGreg Clayton         success = m_editline_ap->GetLines(end_token, lines).Success();
48944d93782SGreg Clayton     }
49044d93782SGreg Clayton     else
49144d93782SGreg Clayton     {
49244d93782SGreg Clayton         LineStatus lines_status = LineStatus::Success;
49344d93782SGreg Clayton 
49444d93782SGreg Clayton         while (lines_status == LineStatus::Success)
49544d93782SGreg Clayton         {
49644d93782SGreg Clayton             std::string line;
49744d93782SGreg Clayton             if (GetLine(line))
49844d93782SGreg Clayton             {
49944d93782SGreg Clayton                 lines.AppendString(line);
50044d93782SGreg Clayton                 Error error;
50144d93782SGreg Clayton                 lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error);
50244d93782SGreg Clayton             }
50344d93782SGreg Clayton             else
50444d93782SGreg Clayton             {
50544d93782SGreg Clayton                 lines_status = LineStatus::Done;
50644d93782SGreg Clayton             }
50744d93782SGreg Clayton         }
50844d93782SGreg Clayton         success = lines.GetSize() > 0;
50944d93782SGreg Clayton     }
51044d93782SGreg Clayton     return success;
51144d93782SGreg Clayton }
51244d93782SGreg Clayton 
51344d93782SGreg Clayton // Each IOHandler gets to run until it is done. It should read data
51444d93782SGreg Clayton // from the "in" and place output into "out" and "err and return
51544d93782SGreg Clayton // when done.
51644d93782SGreg Clayton void
51744d93782SGreg Clayton IOHandlerEditline::Run ()
51844d93782SGreg Clayton {
51944d93782SGreg Clayton     std::string line;
52044d93782SGreg Clayton     while (IsActive())
52144d93782SGreg Clayton     {
52244d93782SGreg Clayton         if (m_multi_line)
52344d93782SGreg Clayton         {
52444d93782SGreg Clayton             StringList lines;
52544d93782SGreg Clayton             if (GetLines (lines))
52644d93782SGreg Clayton             {
52744d93782SGreg Clayton                 line = lines.CopyList();
52844d93782SGreg Clayton                 m_delegate.IOHandlerInputComplete(*this, line);
52944d93782SGreg Clayton             }
53044d93782SGreg Clayton             else
53144d93782SGreg Clayton             {
53244d93782SGreg Clayton                 m_done = true;
53344d93782SGreg Clayton             }
53444d93782SGreg Clayton         }
53544d93782SGreg Clayton         else
53644d93782SGreg Clayton         {
53744d93782SGreg Clayton             if (GetLine(line))
53844d93782SGreg Clayton             {
53944d93782SGreg Clayton                 m_delegate.IOHandlerInputComplete(*this, line);
54044d93782SGreg Clayton             }
54144d93782SGreg Clayton             else
54244d93782SGreg Clayton             {
54344d93782SGreg Clayton                 m_done = true;
54444d93782SGreg Clayton             }
54544d93782SGreg Clayton         }
54644d93782SGreg Clayton     }
54744d93782SGreg Clayton }
54844d93782SGreg Clayton 
54944d93782SGreg Clayton void
55044d93782SGreg Clayton IOHandlerEditline::Hide ()
55144d93782SGreg Clayton {
55244d93782SGreg Clayton     if (m_editline_ap && m_editline_ap->GettingLine())
55344d93782SGreg Clayton         m_editline_ap->Hide();
55444d93782SGreg Clayton }
55544d93782SGreg Clayton 
55644d93782SGreg Clayton 
55744d93782SGreg Clayton void
55844d93782SGreg Clayton IOHandlerEditline::Refresh ()
55944d93782SGreg Clayton {
56044d93782SGreg Clayton     if (m_editline_ap && m_editline_ap->GettingLine())
56144d93782SGreg Clayton         m_editline_ap->Refresh();
56244d93782SGreg Clayton     else
56344d93782SGreg Clayton     {
56444d93782SGreg Clayton         const char *prompt = GetPrompt();
56544d93782SGreg Clayton         if (prompt && prompt[0])
56644d93782SGreg Clayton         {
56744d93782SGreg Clayton             FILE *out = GetOutputFILE();
56844d93782SGreg Clayton             if (out)
56944d93782SGreg Clayton             {
57044d93782SGreg Clayton                 ::fprintf(out, "%s", prompt);
57144d93782SGreg Clayton                 ::fflush(out);
57244d93782SGreg Clayton             }
57344d93782SGreg Clayton         }
57444d93782SGreg Clayton     }
57544d93782SGreg Clayton }
57644d93782SGreg Clayton 
57744d93782SGreg Clayton void
57844d93782SGreg Clayton IOHandlerEditline::Interrupt ()
57944d93782SGreg Clayton {
58044d93782SGreg Clayton     if (m_editline_ap)
58144d93782SGreg Clayton         m_editline_ap->Interrupt();
58244d93782SGreg Clayton }
58344d93782SGreg Clayton 
58444d93782SGreg Clayton void
58544d93782SGreg Clayton IOHandlerEditline::GotEOF()
58644d93782SGreg Clayton {
58744d93782SGreg Clayton     if (m_editline_ap)
58844d93782SGreg Clayton         m_editline_ap->Interrupt();
58944d93782SGreg Clayton }
59044d93782SGreg Clayton 
59144d93782SGreg Clayton #include "lldb/Core/ValueObject.h"
59244d93782SGreg Clayton #include "lldb/Symbol/VariableList.h"
59344d93782SGreg Clayton #include "lldb/Target/Target.h"
59444d93782SGreg Clayton #include "lldb/Target/Process.h"
59544d93782SGreg Clayton #include "lldb/Target/Thread.h"
59644d93782SGreg Clayton #include "lldb/Target/StackFrame.h"
59744d93782SGreg Clayton 
59844d93782SGreg Clayton #define KEY_RETURN   10
59944d93782SGreg Clayton #define KEY_ESCAPE  27
60044d93782SGreg Clayton 
60144d93782SGreg Clayton namespace curses
60244d93782SGreg Clayton {
60344d93782SGreg Clayton     class Menu;
60444d93782SGreg Clayton     class MenuDelegate;
60544d93782SGreg Clayton     class Window;
60644d93782SGreg Clayton     class WindowDelegate;
60744d93782SGreg Clayton     typedef std::shared_ptr<Menu> MenuSP;
60844d93782SGreg Clayton     typedef std::shared_ptr<MenuDelegate> MenuDelegateSP;
60944d93782SGreg Clayton     typedef std::shared_ptr<Window> WindowSP;
61044d93782SGreg Clayton     typedef std::shared_ptr<WindowDelegate> WindowDelegateSP;
61144d93782SGreg Clayton     typedef std::vector<MenuSP> Menus;
61244d93782SGreg Clayton     typedef std::vector<WindowSP> Windows;
61344d93782SGreg Clayton     typedef std::vector<WindowDelegateSP> WindowDelegates;
61444d93782SGreg Clayton 
61544d93782SGreg Clayton #if 0
61644d93782SGreg Clayton type summary add -s "x=${var.x}, y=${var.y}" curses::Point
61744d93782SGreg Clayton type summary add -s "w=${var.width}, h=${var.height}" curses::Size
61844d93782SGreg Clayton type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
61944d93782SGreg Clayton #endif
62044d93782SGreg Clayton     struct Point
62144d93782SGreg Clayton     {
62244d93782SGreg Clayton         int x;
62344d93782SGreg Clayton         int y;
62444d93782SGreg Clayton 
62544d93782SGreg Clayton         Point (int _x = 0, int _y = 0) :
62644d93782SGreg Clayton             x(_x),
62744d93782SGreg Clayton             y(_y)
62844d93782SGreg Clayton         {
62944d93782SGreg Clayton         }
63044d93782SGreg Clayton 
63144d93782SGreg Clayton         void
63244d93782SGreg Clayton         Clear ()
63344d93782SGreg Clayton         {
63444d93782SGreg Clayton             x = 0;
63544d93782SGreg Clayton             y = 0;
63644d93782SGreg Clayton         }
63744d93782SGreg Clayton 
63844d93782SGreg Clayton         Point &
63944d93782SGreg Clayton         operator += (const Point &rhs)
64044d93782SGreg Clayton         {
64144d93782SGreg Clayton             x += rhs.x;
64244d93782SGreg Clayton             y += rhs.y;
64344d93782SGreg Clayton             return *this;
64444d93782SGreg Clayton         }
64544d93782SGreg Clayton 
64644d93782SGreg Clayton         void
64744d93782SGreg Clayton         Dump ()
64844d93782SGreg Clayton         {
64944d93782SGreg Clayton             printf ("(x=%i, y=%i)\n", x, y);
65044d93782SGreg Clayton         }
65144d93782SGreg Clayton 
65244d93782SGreg Clayton     };
65344d93782SGreg Clayton 
65444d93782SGreg Clayton     bool operator == (const Point &lhs, const Point &rhs)
65544d93782SGreg Clayton     {
65644d93782SGreg Clayton         return lhs.x == rhs.x && lhs.y == rhs.y;
65744d93782SGreg Clayton     }
65844d93782SGreg Clayton     bool operator != (const Point &lhs, const Point &rhs)
65944d93782SGreg Clayton     {
66044d93782SGreg Clayton         return lhs.x != rhs.x || lhs.y != rhs.y;
66144d93782SGreg Clayton     }
66244d93782SGreg Clayton 
66344d93782SGreg Clayton     struct Size
66444d93782SGreg Clayton     {
66544d93782SGreg Clayton         int width;
66644d93782SGreg Clayton         int height;
66744d93782SGreg Clayton         Size (int w = 0, int h = 0) :
66844d93782SGreg Clayton             width (w),
66944d93782SGreg Clayton             height (h)
67044d93782SGreg Clayton         {
67144d93782SGreg Clayton         }
67244d93782SGreg Clayton 
67344d93782SGreg Clayton         void
67444d93782SGreg Clayton         Clear ()
67544d93782SGreg Clayton         {
67644d93782SGreg Clayton             width = 0;
67744d93782SGreg Clayton             height = 0;
67844d93782SGreg Clayton         }
67944d93782SGreg Clayton 
68044d93782SGreg Clayton         void
68144d93782SGreg Clayton         Dump ()
68244d93782SGreg Clayton         {
68344d93782SGreg Clayton             printf ("(w=%i, h=%i)\n", width, height);
68444d93782SGreg Clayton         }
68544d93782SGreg Clayton 
68644d93782SGreg Clayton     };
68744d93782SGreg Clayton 
68844d93782SGreg Clayton     bool operator == (const Size &lhs, const Size &rhs)
68944d93782SGreg Clayton     {
69044d93782SGreg Clayton         return lhs.width == rhs.width && lhs.height == rhs.height;
69144d93782SGreg Clayton     }
69244d93782SGreg Clayton     bool operator != (const Size &lhs, const Size &rhs)
69344d93782SGreg Clayton     {
69444d93782SGreg Clayton         return lhs.width != rhs.width || lhs.height != rhs.height;
69544d93782SGreg Clayton     }
69644d93782SGreg Clayton 
69744d93782SGreg Clayton     struct Rect
69844d93782SGreg Clayton     {
69944d93782SGreg Clayton         Point origin;
70044d93782SGreg Clayton         Size size;
70144d93782SGreg Clayton 
70244d93782SGreg Clayton         Rect () :
70344d93782SGreg Clayton             origin(),
70444d93782SGreg Clayton             size()
70544d93782SGreg Clayton         {
70644d93782SGreg Clayton         }
70744d93782SGreg Clayton 
70844d93782SGreg Clayton         Rect (const Point &p, const Size &s) :
70944d93782SGreg Clayton             origin (p),
71044d93782SGreg Clayton             size (s)
71144d93782SGreg Clayton         {
71244d93782SGreg Clayton         }
71344d93782SGreg Clayton 
71444d93782SGreg Clayton         void
71544d93782SGreg Clayton         Clear ()
71644d93782SGreg Clayton         {
71744d93782SGreg Clayton             origin.Clear();
71844d93782SGreg Clayton             size.Clear();
71944d93782SGreg Clayton         }
72044d93782SGreg Clayton 
72144d93782SGreg Clayton         void
72244d93782SGreg Clayton         Dump ()
72344d93782SGreg Clayton         {
72444d93782SGreg Clayton             printf ("(x=%i, y=%i), w=%i, h=%i)\n", origin.x, origin.y, size.width, size.height);
72544d93782SGreg Clayton         }
72644d93782SGreg Clayton 
72744d93782SGreg Clayton         void
72844d93782SGreg Clayton         Inset (int w, int h)
72944d93782SGreg Clayton         {
73044d93782SGreg Clayton             if (size.width > w*2)
73144d93782SGreg Clayton                 size.width -= w*2;
73244d93782SGreg Clayton             origin.x += w;
73344d93782SGreg Clayton 
73444d93782SGreg Clayton             if (size.height > h*2)
73544d93782SGreg Clayton                 size.height -= h*2;
73644d93782SGreg Clayton             origin.y += h;
73744d93782SGreg Clayton         }
73844d93782SGreg Clayton         // Return a status bar rectangle which is the last line of
73944d93782SGreg Clayton         // this rectangle. This rectangle will be modified to not
74044d93782SGreg Clayton         // include the status bar area.
74144d93782SGreg Clayton         Rect
74244d93782SGreg Clayton         MakeStatusBar ()
74344d93782SGreg Clayton         {
74444d93782SGreg Clayton             Rect status_bar;
74544d93782SGreg Clayton             if (size.height > 1)
74644d93782SGreg Clayton             {
74744d93782SGreg Clayton                 status_bar.origin.x = origin.x;
74844d93782SGreg Clayton                 status_bar.origin.y = size.height;
74944d93782SGreg Clayton                 status_bar.size.width = size.width;
75044d93782SGreg Clayton                 status_bar.size.height = 1;
75144d93782SGreg Clayton                 --size.height;
75244d93782SGreg Clayton             }
75344d93782SGreg Clayton             return status_bar;
75444d93782SGreg Clayton         }
75544d93782SGreg Clayton 
75644d93782SGreg Clayton         // Return a menubar rectangle which is the first line of
75744d93782SGreg Clayton         // this rectangle. This rectangle will be modified to not
75844d93782SGreg Clayton         // include the menubar area.
75944d93782SGreg Clayton         Rect
76044d93782SGreg Clayton         MakeMenuBar ()
76144d93782SGreg Clayton         {
76244d93782SGreg Clayton             Rect menubar;
76344d93782SGreg Clayton             if (size.height > 1)
76444d93782SGreg Clayton             {
76544d93782SGreg Clayton                 menubar.origin.x = origin.x;
76644d93782SGreg Clayton                 menubar.origin.y = origin.y;
76744d93782SGreg Clayton                 menubar.size.width = size.width;
76844d93782SGreg Clayton                 menubar.size.height = 1;
76944d93782SGreg Clayton                 ++origin.y;
77044d93782SGreg Clayton                 --size.height;
77144d93782SGreg Clayton             }
77244d93782SGreg Clayton             return menubar;
77344d93782SGreg Clayton         }
77444d93782SGreg Clayton 
77544d93782SGreg Clayton         void
77644d93782SGreg Clayton         HorizontalSplitPercentage (float top_percentage, Rect &top, Rect &bottom) const
77744d93782SGreg Clayton         {
77844d93782SGreg Clayton             float top_height = top_percentage * size.height;
77944d93782SGreg Clayton             HorizontalSplit (top_height, top, bottom);
78044d93782SGreg Clayton         }
78144d93782SGreg Clayton 
78244d93782SGreg Clayton         void
78344d93782SGreg Clayton         HorizontalSplit (int top_height, Rect &top, Rect &bottom) const
78444d93782SGreg Clayton         {
78544d93782SGreg Clayton             top = *this;
78644d93782SGreg Clayton             if (top_height < size.height)
78744d93782SGreg Clayton             {
78844d93782SGreg Clayton                 top.size.height = top_height;
78944d93782SGreg Clayton                 bottom.origin.x = origin.x;
79044d93782SGreg Clayton                 bottom.origin.y = origin.y + top.size.height;
79144d93782SGreg Clayton                 bottom.size.width = size.width;
79244d93782SGreg Clayton                 bottom.size.height = size.height - top.size.height;
79344d93782SGreg Clayton             }
79444d93782SGreg Clayton             else
79544d93782SGreg Clayton             {
79644d93782SGreg Clayton                 bottom.Clear();
79744d93782SGreg Clayton             }
79844d93782SGreg Clayton         }
79944d93782SGreg Clayton 
80044d93782SGreg Clayton         void
80144d93782SGreg Clayton         VerticalSplitPercentage (float left_percentage, Rect &left, Rect &right) const
80244d93782SGreg Clayton         {
80344d93782SGreg Clayton             float left_width = left_percentage * size.width;
80444d93782SGreg Clayton             VerticalSplit (left_width, left, right);
80544d93782SGreg Clayton         }
80644d93782SGreg Clayton 
80744d93782SGreg Clayton 
80844d93782SGreg Clayton         void
80944d93782SGreg Clayton         VerticalSplit (int left_width, Rect &left, Rect &right) const
81044d93782SGreg Clayton         {
81144d93782SGreg Clayton             left = *this;
81244d93782SGreg Clayton             if (left_width < size.width)
81344d93782SGreg Clayton             {
81444d93782SGreg Clayton                 left.size.width = left_width;
81544d93782SGreg Clayton                 right.origin.x = origin.x + left.size.width;
81644d93782SGreg Clayton                 right.origin.y = origin.y;
81744d93782SGreg Clayton                 right.size.width = size.width - left.size.width;
81844d93782SGreg Clayton                 right.size.height = size.height;
81944d93782SGreg Clayton             }
82044d93782SGreg Clayton             else
82144d93782SGreg Clayton             {
82244d93782SGreg Clayton                 right.Clear();
82344d93782SGreg Clayton             }
82444d93782SGreg Clayton         }
82544d93782SGreg Clayton     };
82644d93782SGreg Clayton 
82744d93782SGreg Clayton     bool operator == (const Rect &lhs, const Rect &rhs)
82844d93782SGreg Clayton     {
82944d93782SGreg Clayton         return lhs.origin == rhs.origin && lhs.size == rhs.size;
83044d93782SGreg Clayton     }
83144d93782SGreg Clayton     bool operator != (const Rect &lhs, const Rect &rhs)
83244d93782SGreg Clayton     {
83344d93782SGreg Clayton         return lhs.origin != rhs.origin || lhs.size != rhs.size;
83444d93782SGreg Clayton     }
83544d93782SGreg Clayton 
83644d93782SGreg Clayton     enum HandleCharResult
83744d93782SGreg Clayton     {
83844d93782SGreg Clayton         eKeyNotHandled      = 0,
83944d93782SGreg Clayton         eKeyHandled         = 1,
84044d93782SGreg Clayton         eQuitApplication    = 2
84144d93782SGreg Clayton     };
84244d93782SGreg Clayton 
84344d93782SGreg Clayton     enum class MenuActionResult
84444d93782SGreg Clayton     {
84544d93782SGreg Clayton         Handled,
84644d93782SGreg Clayton         NotHandled,
84744d93782SGreg Clayton         Quit    // Exit all menus and quit
84844d93782SGreg Clayton     };
84944d93782SGreg Clayton 
85044d93782SGreg Clayton     struct KeyHelp
85144d93782SGreg Clayton     {
85244d93782SGreg Clayton         int ch;
85344d93782SGreg Clayton         const char *description;
85444d93782SGreg Clayton     };
85544d93782SGreg Clayton 
85644d93782SGreg Clayton     class WindowDelegate
85744d93782SGreg Clayton     {
85844d93782SGreg Clayton     public:
85944d93782SGreg Clayton         virtual
86044d93782SGreg Clayton         ~WindowDelegate()
86144d93782SGreg Clayton         {
86244d93782SGreg Clayton         }
86344d93782SGreg Clayton 
86444d93782SGreg Clayton         virtual bool
86544d93782SGreg Clayton         WindowDelegateDraw (Window &window, bool force)
86644d93782SGreg Clayton         {
86744d93782SGreg Clayton             return false; // Drawing not handled
86844d93782SGreg Clayton         }
86944d93782SGreg Clayton 
87044d93782SGreg Clayton         virtual HandleCharResult
87144d93782SGreg Clayton         WindowDelegateHandleChar (Window &window, int key)
87244d93782SGreg Clayton         {
87344d93782SGreg Clayton             return eKeyNotHandled;
87444d93782SGreg Clayton         }
87544d93782SGreg Clayton 
87644d93782SGreg Clayton         virtual const char *
87744d93782SGreg Clayton         WindowDelegateGetHelpText ()
87844d93782SGreg Clayton         {
87944d93782SGreg Clayton             return NULL;
88044d93782SGreg Clayton         }
88144d93782SGreg Clayton 
88244d93782SGreg Clayton         virtual KeyHelp *
88344d93782SGreg Clayton         WindowDelegateGetKeyHelp ()
88444d93782SGreg Clayton         {
88544d93782SGreg Clayton             return NULL;
88644d93782SGreg Clayton         }
88744d93782SGreg Clayton     };
88844d93782SGreg Clayton 
88944d93782SGreg Clayton     class HelpDialogDelegate :
89044d93782SGreg Clayton         public WindowDelegate
89144d93782SGreg Clayton     {
89244d93782SGreg Clayton     public:
89344d93782SGreg Clayton         HelpDialogDelegate (const char *text, KeyHelp *key_help_array);
89444d93782SGreg Clayton 
89544d93782SGreg Clayton         virtual
89644d93782SGreg Clayton         ~HelpDialogDelegate();
89744d93782SGreg Clayton 
89844d93782SGreg Clayton         virtual bool
89944d93782SGreg Clayton         WindowDelegateDraw (Window &window, bool force);
90044d93782SGreg Clayton 
90144d93782SGreg Clayton         virtual HandleCharResult
90244d93782SGreg Clayton         WindowDelegateHandleChar (Window &window, int key);
90344d93782SGreg Clayton 
90444d93782SGreg Clayton         size_t
90544d93782SGreg Clayton         GetNumLines() const
90644d93782SGreg Clayton         {
90744d93782SGreg Clayton             return m_text.GetSize();
90844d93782SGreg Clayton         }
90944d93782SGreg Clayton 
91044d93782SGreg Clayton         size_t
91144d93782SGreg Clayton         GetMaxLineLength () const
91244d93782SGreg Clayton         {
91344d93782SGreg Clayton             return m_text.GetMaxStringLength();
91444d93782SGreg Clayton         }
91544d93782SGreg Clayton 
91644d93782SGreg Clayton     protected:
91744d93782SGreg Clayton         StringList m_text;
91844d93782SGreg Clayton         int m_first_visible_line;
91944d93782SGreg Clayton     };
92044d93782SGreg Clayton 
92144d93782SGreg Clayton 
92244d93782SGreg Clayton     class Window
92344d93782SGreg Clayton     {
92444d93782SGreg Clayton     public:
92544d93782SGreg Clayton 
92644d93782SGreg Clayton         Window (const char *name) :
92744d93782SGreg Clayton             m_name (name),
92844d93782SGreg Clayton             m_window (NULL),
92944d93782SGreg Clayton             m_panel (NULL),
93044d93782SGreg Clayton             m_parent (NULL),
93144d93782SGreg Clayton             m_subwindows (),
93244d93782SGreg Clayton             m_delegate_sp (),
93344d93782SGreg Clayton             m_curr_active_window_idx (UINT32_MAX),
93444d93782SGreg Clayton             m_prev_active_window_idx (UINT32_MAX),
93544d93782SGreg Clayton             m_delete (false),
93644d93782SGreg Clayton             m_needs_update (true),
93744d93782SGreg Clayton             m_can_activate (true),
93844d93782SGreg Clayton             m_is_subwin (false)
93944d93782SGreg Clayton         {
94044d93782SGreg Clayton         }
94144d93782SGreg Clayton 
94244d93782SGreg Clayton         Window (const char *name, WINDOW *w, bool del = true) :
94344d93782SGreg Clayton             m_name (name),
94444d93782SGreg Clayton             m_window (NULL),
94544d93782SGreg Clayton             m_panel (NULL),
94644d93782SGreg Clayton             m_parent (NULL),
94744d93782SGreg Clayton             m_subwindows (),
94844d93782SGreg Clayton             m_delegate_sp (),
94944d93782SGreg Clayton             m_curr_active_window_idx (UINT32_MAX),
95044d93782SGreg Clayton             m_prev_active_window_idx (UINT32_MAX),
95144d93782SGreg Clayton             m_delete (del),
95244d93782SGreg Clayton             m_needs_update (true),
95344d93782SGreg Clayton             m_can_activate (true),
95444d93782SGreg Clayton             m_is_subwin (false)
95544d93782SGreg Clayton         {
95644d93782SGreg Clayton             if (w)
95744d93782SGreg Clayton                 Reset(w);
95844d93782SGreg Clayton         }
95944d93782SGreg Clayton 
96044d93782SGreg Clayton         Window (const char *name, const Rect &bounds) :
96144d93782SGreg Clayton             m_name (name),
96244d93782SGreg Clayton             m_window (NULL),
96344d93782SGreg Clayton             m_parent (NULL),
96444d93782SGreg Clayton             m_subwindows (),
96544d93782SGreg Clayton             m_delegate_sp (),
96644d93782SGreg Clayton             m_curr_active_window_idx (UINT32_MAX),
96744d93782SGreg Clayton             m_prev_active_window_idx (UINT32_MAX),
96844d93782SGreg Clayton             m_delete (true),
96944d93782SGreg Clayton             m_needs_update (true),
97044d93782SGreg Clayton             m_can_activate (true),
97144d93782SGreg Clayton             m_is_subwin (false)
97244d93782SGreg Clayton         {
97344d93782SGreg Clayton             Reset (::newwin (bounds.size.height, bounds.size.width, bounds.origin.y, bounds.origin.y));
97444d93782SGreg Clayton         }
97544d93782SGreg Clayton 
97644d93782SGreg Clayton         virtual
97744d93782SGreg Clayton         ~Window ()
97844d93782SGreg Clayton         {
97944d93782SGreg Clayton             RemoveSubWindows ();
98044d93782SGreg Clayton             Reset ();
98144d93782SGreg Clayton         }
98244d93782SGreg Clayton 
98344d93782SGreg Clayton         void
98444d93782SGreg Clayton         Reset (WINDOW *w = NULL, bool del = true)
98544d93782SGreg Clayton         {
98644d93782SGreg Clayton             if (m_window == w)
98744d93782SGreg Clayton                 return;
98844d93782SGreg Clayton 
98944d93782SGreg Clayton             if (m_panel)
99044d93782SGreg Clayton             {
99144d93782SGreg Clayton                 ::del_panel (m_panel);
99244d93782SGreg Clayton                 m_panel = NULL;
99344d93782SGreg Clayton             }
99444d93782SGreg Clayton             if (m_window && m_delete)
99544d93782SGreg Clayton             {
99644d93782SGreg Clayton                 ::delwin (m_window);
99744d93782SGreg Clayton                 m_window = NULL;
99844d93782SGreg Clayton                 m_delete = false;
99944d93782SGreg Clayton             }
100044d93782SGreg Clayton             if (w)
100144d93782SGreg Clayton             {
100244d93782SGreg Clayton                 m_window = w;
100344d93782SGreg Clayton                 m_panel = ::new_panel (m_window);
100444d93782SGreg Clayton                 m_delete = del;
100544d93782SGreg Clayton             }
100644d93782SGreg Clayton         }
100744d93782SGreg Clayton 
100844d93782SGreg Clayton         void    AttributeOn (attr_t attr)   { ::wattron (m_window, attr); }
100944d93782SGreg Clayton         void    AttributeOff (attr_t attr)  { ::wattroff (m_window, attr); }
101044d93782SGreg Clayton         void    Box (chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) { ::box(m_window, v_char, h_char); }
101144d93782SGreg Clayton         void    Clear ()    { ::wclear (m_window); }
101244d93782SGreg Clayton         void    Erase ()    { ::werase (m_window); }
101344d93782SGreg Clayton         Rect    GetBounds () { return Rect (GetParentOrigin(), GetSize()); } // Get the rectangle in our parent window
101444d93782SGreg Clayton         int     GetChar ()  { return ::wgetch (m_window); }
101544d93782SGreg Clayton         int     GetCursorX ()     { return getcurx (m_window); }
101644d93782SGreg Clayton         int     GetCursorY ()     { return getcury (m_window); }
101744d93782SGreg Clayton         Rect    GetFrame ()    { return Rect (Point(), GetSize()); } // Get our rectangle in our own coordinate system
101844d93782SGreg Clayton         Point   GetParentOrigin() { return Point (GetParentX(), GetParentY()); }
101944d93782SGreg Clayton         Size    GetSize()         { return Size (GetWidth(), GetHeight()); }
102044d93782SGreg Clayton         int     GetParentX ()     { return getparx (m_window); }
102144d93782SGreg Clayton         int     GetParentY ()     { return getpary (m_window); }
102244d93782SGreg Clayton         int     GetMaxX()   { return getmaxx (m_window); }
102344d93782SGreg Clayton         int     GetMaxY()   { return getmaxy (m_window); }
102444d93782SGreg Clayton         int     GetWidth()  { return GetMaxX(); }
102544d93782SGreg Clayton         int     GetHeight() { return GetMaxY(); }
102644d93782SGreg Clayton         void    MoveCursor (int x, int y) {  ::wmove (m_window, y, x); }
102744d93782SGreg Clayton         void    MoveWindow (int x, int y) {  MoveWindow(Point(x,y)); }
102844d93782SGreg Clayton         void    Resize (int w, int h) { ::wresize(m_window, h, w); }
102944d93782SGreg Clayton         void    Resize (const Size &size) { ::wresize(m_window, size.height, size.width); }
103044d93782SGreg Clayton         void    PutChar (int ch)    { ::waddch (m_window, ch); }
103144d93782SGreg Clayton         void    PutCString (const char *s, int len = -1) { ::waddnstr (m_window, s, len); }
103244d93782SGreg Clayton         void    Refresh ()  { ::wrefresh (m_window); }
103344d93782SGreg Clayton         void    DeferredRefresh ()
103444d93782SGreg Clayton         {
103544d93782SGreg Clayton             // We are using panels, so we don't need to call this...
103644d93782SGreg Clayton             //::wnoutrefresh(m_window);
103744d93782SGreg Clayton         }
103844d93782SGreg Clayton         void    SetBackground (int color_pair_idx) { ::wbkgd (m_window,COLOR_PAIR(color_pair_idx)); }
103944d93782SGreg Clayton         void    UnderlineOn ()  { AttributeOn(A_UNDERLINE); }
104044d93782SGreg Clayton         void    UnderlineOff () { AttributeOff(A_UNDERLINE); }
104144d93782SGreg Clayton 
104244d93782SGreg Clayton         void    PutCStringTruncated (const char *s, int right_pad)
104344d93782SGreg Clayton         {
104444d93782SGreg Clayton             int bytes_left = GetWidth() - GetCursorX();
104544d93782SGreg Clayton             if (bytes_left > right_pad)
104644d93782SGreg Clayton             {
104744d93782SGreg Clayton                 bytes_left -= right_pad;
104844d93782SGreg Clayton                 ::waddnstr (m_window, s, bytes_left);
104944d93782SGreg Clayton             }
105044d93782SGreg Clayton         }
105144d93782SGreg Clayton 
105244d93782SGreg Clayton         void
105344d93782SGreg Clayton         MoveWindow (const Point &origin)
105444d93782SGreg Clayton         {
105544d93782SGreg Clayton             const bool moving_window = origin != GetParentOrigin();
105644d93782SGreg Clayton             if (m_is_subwin && moving_window)
105744d93782SGreg Clayton             {
105844d93782SGreg Clayton                 // Can't move subwindows, must delete and re-create
105944d93782SGreg Clayton                 Size size = GetSize();
106044d93782SGreg Clayton                 Reset (::subwin (m_parent->m_window,
106144d93782SGreg Clayton                                  size.height,
106244d93782SGreg Clayton                                  size.width,
106344d93782SGreg Clayton                                  origin.y,
106444d93782SGreg Clayton                                  origin.x), true);
106544d93782SGreg Clayton             }
106644d93782SGreg Clayton             else
106744d93782SGreg Clayton             {
106844d93782SGreg Clayton                 ::mvwin (m_window, origin.y, origin.x);
106944d93782SGreg Clayton             }
107044d93782SGreg Clayton         }
107144d93782SGreg Clayton 
107244d93782SGreg Clayton         void
107344d93782SGreg Clayton         SetBounds (const Rect &bounds)
107444d93782SGreg Clayton         {
107544d93782SGreg Clayton             const bool moving_window = bounds.origin != GetParentOrigin();
107644d93782SGreg Clayton             if (m_is_subwin && moving_window)
107744d93782SGreg Clayton             {
107844d93782SGreg Clayton                 // Can't move subwindows, must delete and re-create
107944d93782SGreg Clayton                 Reset (::subwin (m_parent->m_window,
108044d93782SGreg Clayton                                  bounds.size.height,
108144d93782SGreg Clayton                                  bounds.size.width,
108244d93782SGreg Clayton                                  bounds.origin.y,
108344d93782SGreg Clayton                                  bounds.origin.x), true);
108444d93782SGreg Clayton             }
108544d93782SGreg Clayton             else
108644d93782SGreg Clayton             {
108744d93782SGreg Clayton                 if (moving_window)
108844d93782SGreg Clayton                     MoveWindow(bounds.origin);
108944d93782SGreg Clayton                 Resize (bounds.size);
109044d93782SGreg Clayton             }
109144d93782SGreg Clayton         }
109244d93782SGreg Clayton 
109344d93782SGreg Clayton         void
109444d93782SGreg Clayton         Printf (const char *format, ...)  __attribute__ ((format (printf, 2, 3)))
109544d93782SGreg Clayton         {
109644d93782SGreg Clayton             va_list args;
109744d93782SGreg Clayton             va_start (args, format);
109844d93782SGreg Clayton             vwprintw(m_window, format, args);
109944d93782SGreg Clayton             va_end (args);
110044d93782SGreg Clayton         }
110144d93782SGreg Clayton 
110244d93782SGreg Clayton         void
110344d93782SGreg Clayton         Touch ()
110444d93782SGreg Clayton         {
110544d93782SGreg Clayton             ::touchwin (m_window);
110644d93782SGreg Clayton             if (m_parent)
110744d93782SGreg Clayton                 m_parent->Touch();
110844d93782SGreg Clayton         }
110944d93782SGreg Clayton 
111044d93782SGreg Clayton         WindowSP
111144d93782SGreg Clayton         CreateSubWindow (const char *name, const Rect &bounds, bool make_active)
111244d93782SGreg Clayton         {
111344d93782SGreg Clayton             WindowSP subwindow_sp;
111444d93782SGreg Clayton             if (m_window)
111544d93782SGreg Clayton             {
111644d93782SGreg Clayton                 subwindow_sp.reset(new Window(name, ::subwin (m_window,
111744d93782SGreg Clayton                                                               bounds.size.height,
111844d93782SGreg Clayton                                                               bounds.size.width,
111944d93782SGreg Clayton                                                               bounds.origin.y,
112044d93782SGreg Clayton                                                               bounds.origin.x), true));
112144d93782SGreg Clayton                 subwindow_sp->m_is_subwin = true;
112244d93782SGreg Clayton             }
112344d93782SGreg Clayton             else
112444d93782SGreg Clayton             {
112544d93782SGreg Clayton                 subwindow_sp.reset(new Window(name, ::newwin (bounds.size.height,
112644d93782SGreg Clayton                                                               bounds.size.width,
112744d93782SGreg Clayton                                                               bounds.origin.y,
112844d93782SGreg Clayton                                                               bounds.origin.x), true));
112944d93782SGreg Clayton                 subwindow_sp->m_is_subwin = false;
113044d93782SGreg Clayton             }
113144d93782SGreg Clayton             subwindow_sp->m_parent = this;
113244d93782SGreg Clayton             if (make_active)
113344d93782SGreg Clayton             {
113444d93782SGreg Clayton                 m_prev_active_window_idx = m_curr_active_window_idx;
113544d93782SGreg Clayton                 m_curr_active_window_idx = m_subwindows.size();
113644d93782SGreg Clayton             }
113744d93782SGreg Clayton             m_subwindows.push_back(subwindow_sp);
113844d93782SGreg Clayton             ::top_panel (subwindow_sp->m_panel);
113944d93782SGreg Clayton             m_needs_update = true;
114044d93782SGreg Clayton             return subwindow_sp;
114144d93782SGreg Clayton         }
114244d93782SGreg Clayton 
114344d93782SGreg Clayton         bool
114444d93782SGreg Clayton         RemoveSubWindow (Window *window)
114544d93782SGreg Clayton         {
114644d93782SGreg Clayton             Windows::iterator pos, end = m_subwindows.end();
114744d93782SGreg Clayton             size_t i = 0;
114844d93782SGreg Clayton             for (pos = m_subwindows.begin(); pos != end; ++pos, ++i)
114944d93782SGreg Clayton             {
115044d93782SGreg Clayton                 if ((*pos).get() == window)
115144d93782SGreg Clayton                 {
115244d93782SGreg Clayton                     if (m_prev_active_window_idx == i)
115344d93782SGreg Clayton                         m_prev_active_window_idx = UINT32_MAX;
115444d93782SGreg Clayton                     else if (m_prev_active_window_idx != UINT32_MAX && m_prev_active_window_idx > i)
115544d93782SGreg Clayton                         --m_prev_active_window_idx;
115644d93782SGreg Clayton 
115744d93782SGreg Clayton                     if (m_curr_active_window_idx == i)
115844d93782SGreg Clayton                         m_curr_active_window_idx = UINT32_MAX;
115944d93782SGreg Clayton                     else if (m_curr_active_window_idx != UINT32_MAX && m_curr_active_window_idx > i)
116044d93782SGreg Clayton                         --m_curr_active_window_idx;
116144d93782SGreg Clayton                     window->Erase();
116244d93782SGreg Clayton                     m_subwindows.erase(pos);
116344d93782SGreg Clayton                     m_needs_update = true;
116444d93782SGreg Clayton                     if (m_parent)
116544d93782SGreg Clayton                         m_parent->Touch();
116644d93782SGreg Clayton                     else
116744d93782SGreg Clayton                         ::touchwin (stdscr);
116844d93782SGreg Clayton                     return true;
116944d93782SGreg Clayton                 }
117044d93782SGreg Clayton             }
117144d93782SGreg Clayton             return false;
117244d93782SGreg Clayton         }
117344d93782SGreg Clayton 
117444d93782SGreg Clayton         WindowSP
117544d93782SGreg Clayton         FindSubWindow (const char *name)
117644d93782SGreg Clayton         {
117744d93782SGreg Clayton             Windows::iterator pos, end = m_subwindows.end();
117844d93782SGreg Clayton             size_t i = 0;
117944d93782SGreg Clayton             for (pos = m_subwindows.begin(); pos != end; ++pos, ++i)
118044d93782SGreg Clayton             {
118144d93782SGreg Clayton                 if ((*pos)->m_name.compare(name) == 0)
118244d93782SGreg Clayton                     return *pos;
118344d93782SGreg Clayton             }
118444d93782SGreg Clayton             return WindowSP();
118544d93782SGreg Clayton         }
118644d93782SGreg Clayton 
118744d93782SGreg Clayton         void
118844d93782SGreg Clayton         RemoveSubWindows ()
118944d93782SGreg Clayton         {
119044d93782SGreg Clayton             m_curr_active_window_idx = UINT32_MAX;
119144d93782SGreg Clayton             m_prev_active_window_idx = UINT32_MAX;
119244d93782SGreg Clayton             for (Windows::iterator pos = m_subwindows.begin();
119344d93782SGreg Clayton                  pos != m_subwindows.end();
119444d93782SGreg Clayton                  pos = m_subwindows.erase(pos))
119544d93782SGreg Clayton             {
119644d93782SGreg Clayton                 (*pos)->Erase();
119744d93782SGreg Clayton             }
119844d93782SGreg Clayton             if (m_parent)
119944d93782SGreg Clayton                 m_parent->Touch();
120044d93782SGreg Clayton             else
120144d93782SGreg Clayton                 ::touchwin (stdscr);
120244d93782SGreg Clayton         }
120344d93782SGreg Clayton 
120444d93782SGreg Clayton         WINDOW *
120544d93782SGreg Clayton         get()
120644d93782SGreg Clayton         {
120744d93782SGreg Clayton             return m_window;
120844d93782SGreg Clayton         }
120944d93782SGreg Clayton 
121044d93782SGreg Clayton         operator WINDOW *()
121144d93782SGreg Clayton         {
121244d93782SGreg Clayton             return m_window;
121344d93782SGreg Clayton         }
121444d93782SGreg Clayton 
121544d93782SGreg Clayton         //----------------------------------------------------------------------
121644d93782SGreg Clayton         // Window drawing utilities
121744d93782SGreg Clayton         //----------------------------------------------------------------------
121844d93782SGreg Clayton         void
121944d93782SGreg Clayton         DrawTitleBox (const char *title, const char *bottom_message = NULL)
122044d93782SGreg Clayton         {
122144d93782SGreg Clayton             attr_t attr = 0;
122244d93782SGreg Clayton             if (IsActive())
122344d93782SGreg Clayton                 attr = A_BOLD | COLOR_PAIR(2);
122444d93782SGreg Clayton             else
122544d93782SGreg Clayton                 attr = 0;
122644d93782SGreg Clayton             if (attr)
122744d93782SGreg Clayton                 AttributeOn(attr);
122844d93782SGreg Clayton 
122944d93782SGreg Clayton             Box();
123044d93782SGreg Clayton             MoveCursor(3, 0);
123144d93782SGreg Clayton 
123244d93782SGreg Clayton             if (title && title[0])
123344d93782SGreg Clayton             {
123444d93782SGreg Clayton                 PutChar ('<');
123544d93782SGreg Clayton                 PutCString (title);
123644d93782SGreg Clayton                 PutChar ('>');
123744d93782SGreg Clayton             }
123844d93782SGreg Clayton 
123944d93782SGreg Clayton             if (bottom_message && bottom_message[0])
124044d93782SGreg Clayton             {
124144d93782SGreg Clayton                 int bottom_message_length = strlen(bottom_message);
124244d93782SGreg Clayton                 int x = GetWidth() - 3 - (bottom_message_length + 2);
124344d93782SGreg Clayton 
124444d93782SGreg Clayton                 if (x > 0)
124544d93782SGreg Clayton                 {
124644d93782SGreg Clayton                     MoveCursor (x, GetHeight() - 1);
124744d93782SGreg Clayton                     PutChar ('[');
124844d93782SGreg Clayton                     PutCString(bottom_message);
124944d93782SGreg Clayton                     PutChar (']');
125044d93782SGreg Clayton                 }
125144d93782SGreg Clayton                 else
125244d93782SGreg Clayton                 {
125344d93782SGreg Clayton                     MoveCursor (1, GetHeight() - 1);
125444d93782SGreg Clayton                     PutChar ('[');
125544d93782SGreg Clayton                     PutCStringTruncated (bottom_message, 1);
125644d93782SGreg Clayton                 }
125744d93782SGreg Clayton             }
125844d93782SGreg Clayton             if (attr)
125944d93782SGreg Clayton                 AttributeOff(attr);
126044d93782SGreg Clayton 
126144d93782SGreg Clayton         }
126244d93782SGreg Clayton 
126344d93782SGreg Clayton         virtual void
126444d93782SGreg Clayton         Draw (bool force)
126544d93782SGreg Clayton         {
126644d93782SGreg Clayton             if (m_delegate_sp && m_delegate_sp->WindowDelegateDraw (*this, force))
126744d93782SGreg Clayton                 return;
126844d93782SGreg Clayton 
126944d93782SGreg Clayton             for (auto &subwindow_sp : m_subwindows)
127044d93782SGreg Clayton                 subwindow_sp->Draw(force);
127144d93782SGreg Clayton         }
127244d93782SGreg Clayton 
127344d93782SGreg Clayton         bool
127444d93782SGreg Clayton         CreateHelpSubwindow ()
127544d93782SGreg Clayton         {
127644d93782SGreg Clayton             if (m_delegate_sp)
127744d93782SGreg Clayton             {
127844d93782SGreg Clayton                 const char *text = m_delegate_sp->WindowDelegateGetHelpText ();
127944d93782SGreg Clayton                 KeyHelp *key_help = m_delegate_sp->WindowDelegateGetKeyHelp ();
128044d93782SGreg Clayton                 if ((text && text[0]) || key_help)
128144d93782SGreg Clayton                 {
128244d93782SGreg Clayton                     std::auto_ptr<HelpDialogDelegate> help_delegate_ap(new HelpDialogDelegate(text, key_help));
128344d93782SGreg Clayton                     const size_t num_lines = help_delegate_ap->GetNumLines();
128444d93782SGreg Clayton                     const size_t max_length = help_delegate_ap->GetMaxLineLength();
128544d93782SGreg Clayton                     Rect bounds = GetBounds();
128644d93782SGreg Clayton                     bounds.Inset(1, 1);
128744d93782SGreg Clayton                     if (max_length + 4 < bounds.size.width)
128844d93782SGreg Clayton                     {
128944d93782SGreg Clayton                         bounds.origin.x += (bounds.size.width - max_length + 4)/2;
129044d93782SGreg Clayton                         bounds.size.width = max_length + 4;
129144d93782SGreg Clayton                     }
129244d93782SGreg Clayton                     else
129344d93782SGreg Clayton                     {
129444d93782SGreg Clayton                         if (bounds.size.width > 100)
129544d93782SGreg Clayton                         {
129644d93782SGreg Clayton                             const int inset_w = bounds.size.width / 4;
129744d93782SGreg Clayton                             bounds.origin.x += inset_w;
129844d93782SGreg Clayton                             bounds.size.width -= 2*inset_w;
129944d93782SGreg Clayton                         }
130044d93782SGreg Clayton                     }
130144d93782SGreg Clayton 
130244d93782SGreg Clayton                     if (num_lines + 2 < bounds.size.height)
130344d93782SGreg Clayton                     {
130444d93782SGreg Clayton                         bounds.origin.y += (bounds.size.height - num_lines + 2)/2;
130544d93782SGreg Clayton                         bounds.size.height = num_lines + 2;
130644d93782SGreg Clayton                     }
130744d93782SGreg Clayton                     else
130844d93782SGreg Clayton                     {
130944d93782SGreg Clayton                         if (bounds.size.height > 100)
131044d93782SGreg Clayton                         {
131144d93782SGreg Clayton                             const int inset_h = bounds.size.height / 4;
131244d93782SGreg Clayton                             bounds.origin.y += inset_h;
131344d93782SGreg Clayton                             bounds.size.height -= 2*inset_h;
131444d93782SGreg Clayton                         }
131544d93782SGreg Clayton                     }
1316*5fdb09bbSGreg Clayton                     WindowSP help_window_sp;
1317*5fdb09bbSGreg Clayton                     Window *parent_window = GetParent();
1318*5fdb09bbSGreg Clayton                     if (parent_window)
1319*5fdb09bbSGreg Clayton                         help_window_sp = parent_window->CreateSubWindow("Help", bounds, true);
1320*5fdb09bbSGreg Clayton                     else
1321*5fdb09bbSGreg Clayton                         help_window_sp = CreateSubWindow("Help", bounds, true);
132244d93782SGreg Clayton                     help_window_sp->SetDelegate(WindowDelegateSP(help_delegate_ap.release()));
132344d93782SGreg Clayton                     return true;
132444d93782SGreg Clayton                 }
132544d93782SGreg Clayton             }
132644d93782SGreg Clayton             return false;
132744d93782SGreg Clayton         }
132844d93782SGreg Clayton 
132944d93782SGreg Clayton         virtual HandleCharResult
133044d93782SGreg Clayton         HandleChar (int key)
133144d93782SGreg Clayton         {
133244d93782SGreg Clayton             // Always check the active window first
133344d93782SGreg Clayton             HandleCharResult result = eKeyNotHandled;
133444d93782SGreg Clayton             WindowSP active_window_sp = GetActiveWindow ();
133544d93782SGreg Clayton             if (active_window_sp)
133644d93782SGreg Clayton             {
133744d93782SGreg Clayton                 result = active_window_sp->HandleChar (key);
133844d93782SGreg Clayton                 if (result != eKeyNotHandled)
133944d93782SGreg Clayton                     return result;
134044d93782SGreg Clayton             }
134144d93782SGreg Clayton 
134244d93782SGreg Clayton             if (m_delegate_sp)
134344d93782SGreg Clayton             {
134444d93782SGreg Clayton                 result = m_delegate_sp->WindowDelegateHandleChar (*this, key);
134544d93782SGreg Clayton                 if (result != eKeyNotHandled)
134644d93782SGreg Clayton                     return result;
134744d93782SGreg Clayton             }
134844d93782SGreg Clayton 
134944d93782SGreg Clayton             // Then check for any windows that want any keys
135044d93782SGreg Clayton             // that weren't handled. This is typically only
135144d93782SGreg Clayton             // for a menubar.
135244d93782SGreg Clayton             // Make a copy of the subwindows in case any HandleChar()
135344d93782SGreg Clayton             // functions muck with the subwindows. If we don't do this,
135444d93782SGreg Clayton             // we can crash when iterating over the subwindows.
135544d93782SGreg Clayton             Windows subwindows (m_subwindows);
135644d93782SGreg Clayton             for (auto subwindow_sp : subwindows)
135744d93782SGreg Clayton             {
135844d93782SGreg Clayton                 if (subwindow_sp->m_can_activate == false)
135944d93782SGreg Clayton                 {
136044d93782SGreg Clayton                     HandleCharResult result = subwindow_sp->HandleChar(key);
136144d93782SGreg Clayton                     if (result != eKeyNotHandled)
136244d93782SGreg Clayton                         return result;
136344d93782SGreg Clayton                 }
136444d93782SGreg Clayton             }
136544d93782SGreg Clayton 
136644d93782SGreg Clayton             return eKeyNotHandled;
136744d93782SGreg Clayton         }
136844d93782SGreg Clayton 
136944d93782SGreg Clayton         bool
137044d93782SGreg Clayton         SetActiveWindow (Window *window)
137144d93782SGreg Clayton         {
137244d93782SGreg Clayton             const size_t num_subwindows = m_subwindows.size();
137344d93782SGreg Clayton             for (size_t i=0; i<num_subwindows; ++i)
137444d93782SGreg Clayton             {
137544d93782SGreg Clayton                 if (m_subwindows[i].get() == window)
137644d93782SGreg Clayton                 {
137744d93782SGreg Clayton                     m_prev_active_window_idx = m_curr_active_window_idx;
137844d93782SGreg Clayton                     ::top_panel (window->m_panel);
137944d93782SGreg Clayton                     m_curr_active_window_idx = i;
138044d93782SGreg Clayton                     return true;
138144d93782SGreg Clayton                 }
138244d93782SGreg Clayton             }
138344d93782SGreg Clayton             return false;
138444d93782SGreg Clayton         }
138544d93782SGreg Clayton 
138644d93782SGreg Clayton         WindowSP
138744d93782SGreg Clayton         GetActiveWindow ()
138844d93782SGreg Clayton         {
138944d93782SGreg Clayton             if (!m_subwindows.empty())
139044d93782SGreg Clayton             {
139144d93782SGreg Clayton                 if (m_curr_active_window_idx >= m_subwindows.size())
139244d93782SGreg Clayton                 {
139344d93782SGreg Clayton                     if (m_prev_active_window_idx < m_subwindows.size())
139444d93782SGreg Clayton                     {
139544d93782SGreg Clayton                         m_curr_active_window_idx = m_prev_active_window_idx;
139644d93782SGreg Clayton                         m_prev_active_window_idx = UINT32_MAX;
139744d93782SGreg Clayton                     }
139844d93782SGreg Clayton                     else if (IsActive())
139944d93782SGreg Clayton                     {
140044d93782SGreg Clayton                         m_prev_active_window_idx = UINT32_MAX;
140144d93782SGreg Clayton                         m_curr_active_window_idx = UINT32_MAX;
140244d93782SGreg Clayton 
140344d93782SGreg Clayton                         // Find first window that wants to be active if this window is active
140444d93782SGreg Clayton                         const size_t num_subwindows = m_subwindows.size();
140544d93782SGreg Clayton                         for (size_t i=0; i<num_subwindows; ++i)
140644d93782SGreg Clayton                         {
140744d93782SGreg Clayton                             if (m_subwindows[i]->GetCanBeActive())
140844d93782SGreg Clayton                             {
140944d93782SGreg Clayton                                 m_curr_active_window_idx = i;
141044d93782SGreg Clayton                                 break;
141144d93782SGreg Clayton                             }
141244d93782SGreg Clayton                         }
141344d93782SGreg Clayton                     }
141444d93782SGreg Clayton                 }
141544d93782SGreg Clayton 
141644d93782SGreg Clayton                 if (m_curr_active_window_idx < m_subwindows.size())
141744d93782SGreg Clayton                     return m_subwindows[m_curr_active_window_idx];
141844d93782SGreg Clayton             }
141944d93782SGreg Clayton             return WindowSP();
142044d93782SGreg Clayton         }
142144d93782SGreg Clayton 
142244d93782SGreg Clayton         bool
142344d93782SGreg Clayton         GetCanBeActive () const
142444d93782SGreg Clayton         {
142544d93782SGreg Clayton             return m_can_activate;
142644d93782SGreg Clayton         }
142744d93782SGreg Clayton 
142844d93782SGreg Clayton         void
142944d93782SGreg Clayton         SetCanBeActive (bool b)
143044d93782SGreg Clayton         {
143144d93782SGreg Clayton             m_can_activate = b;
143244d93782SGreg Clayton         }
143344d93782SGreg Clayton 
143444d93782SGreg Clayton         const WindowDelegateSP &
143544d93782SGreg Clayton         GetDelegate () const
143644d93782SGreg Clayton         {
143744d93782SGreg Clayton             return m_delegate_sp;
143844d93782SGreg Clayton         }
143944d93782SGreg Clayton 
144044d93782SGreg Clayton         void
144144d93782SGreg Clayton         SetDelegate (const WindowDelegateSP &delegate_sp)
144244d93782SGreg Clayton         {
144344d93782SGreg Clayton             m_delegate_sp = delegate_sp;
144444d93782SGreg Clayton         }
144544d93782SGreg Clayton 
144644d93782SGreg Clayton         Window *
144744d93782SGreg Clayton         GetParent () const
144844d93782SGreg Clayton         {
144944d93782SGreg Clayton             return m_parent;
145044d93782SGreg Clayton         }
145144d93782SGreg Clayton 
145244d93782SGreg Clayton         bool
145344d93782SGreg Clayton         IsActive () const
145444d93782SGreg Clayton         {
145544d93782SGreg Clayton             if (m_parent)
145644d93782SGreg Clayton                 return m_parent->GetActiveWindow().get() == this;
145744d93782SGreg Clayton             else
145844d93782SGreg Clayton                 return true; // Top level window is always active
145944d93782SGreg Clayton         }
146044d93782SGreg Clayton 
146144d93782SGreg Clayton         void
146244d93782SGreg Clayton         SelectNextWindowAsActive ()
146344d93782SGreg Clayton         {
146444d93782SGreg Clayton             // Move active focus to next window
146544d93782SGreg Clayton             const size_t num_subwindows = m_subwindows.size();
146644d93782SGreg Clayton             if (m_curr_active_window_idx == UINT32_MAX)
146744d93782SGreg Clayton             {
146844d93782SGreg Clayton                 uint32_t idx = 0;
146944d93782SGreg Clayton                 for (auto subwindow_sp : m_subwindows)
147044d93782SGreg Clayton                 {
147144d93782SGreg Clayton                     if (subwindow_sp->GetCanBeActive())
147244d93782SGreg Clayton                     {
147344d93782SGreg Clayton                         m_curr_active_window_idx = idx;
147444d93782SGreg Clayton                         break;
147544d93782SGreg Clayton                     }
147644d93782SGreg Clayton                     ++idx;
147744d93782SGreg Clayton                 }
147844d93782SGreg Clayton             }
147944d93782SGreg Clayton             else if (m_curr_active_window_idx + 1 < num_subwindows)
148044d93782SGreg Clayton             {
148144d93782SGreg Clayton                 bool handled = false;
148244d93782SGreg Clayton                 m_prev_active_window_idx = m_curr_active_window_idx;
148344d93782SGreg Clayton                 for (size_t idx=m_curr_active_window_idx + 1; idx<num_subwindows; ++idx)
148444d93782SGreg Clayton                 {
148544d93782SGreg Clayton                     if (m_subwindows[idx]->GetCanBeActive())
148644d93782SGreg Clayton                     {
148744d93782SGreg Clayton                         m_curr_active_window_idx = idx;
148844d93782SGreg Clayton                         handled = true;
148944d93782SGreg Clayton                         break;
149044d93782SGreg Clayton                     }
149144d93782SGreg Clayton                 }
149244d93782SGreg Clayton                 if (!handled)
149344d93782SGreg Clayton                 {
149444d93782SGreg Clayton                     for (size_t idx=0; idx<=m_prev_active_window_idx; ++idx)
149544d93782SGreg Clayton                     {
149644d93782SGreg Clayton                         if (m_subwindows[idx]->GetCanBeActive())
149744d93782SGreg Clayton                         {
149844d93782SGreg Clayton                             m_curr_active_window_idx = idx;
149944d93782SGreg Clayton                             break;
150044d93782SGreg Clayton                         }
150144d93782SGreg Clayton                     }
150244d93782SGreg Clayton                 }
150344d93782SGreg Clayton             }
150444d93782SGreg Clayton             else
150544d93782SGreg Clayton             {
150644d93782SGreg Clayton                 m_prev_active_window_idx = m_curr_active_window_idx;
150744d93782SGreg Clayton                 for (size_t idx=0; idx<num_subwindows; ++idx)
150844d93782SGreg Clayton                 {
150944d93782SGreg Clayton                     if (m_subwindows[idx]->GetCanBeActive())
151044d93782SGreg Clayton                     {
151144d93782SGreg Clayton                         m_curr_active_window_idx = idx;
151244d93782SGreg Clayton                         break;
151344d93782SGreg Clayton                     }
151444d93782SGreg Clayton                 }
151544d93782SGreg Clayton             }
151644d93782SGreg Clayton         }
151744d93782SGreg Clayton 
151844d93782SGreg Clayton         const char *
151944d93782SGreg Clayton         GetName () const
152044d93782SGreg Clayton         {
152144d93782SGreg Clayton             return m_name.c_str();
152244d93782SGreg Clayton         }
152344d93782SGreg Clayton     protected:
152444d93782SGreg Clayton         std::string m_name;
152544d93782SGreg Clayton         WINDOW *m_window;
152644d93782SGreg Clayton         PANEL *m_panel;
152744d93782SGreg Clayton         Window *m_parent;
152844d93782SGreg Clayton         Windows m_subwindows;
152944d93782SGreg Clayton         WindowDelegateSP m_delegate_sp;
153044d93782SGreg Clayton         uint32_t m_curr_active_window_idx;
153144d93782SGreg Clayton         uint32_t m_prev_active_window_idx;
153244d93782SGreg Clayton         bool m_delete;
153344d93782SGreg Clayton         bool m_needs_update;
153444d93782SGreg Clayton         bool m_can_activate;
153544d93782SGreg Clayton         bool m_is_subwin;
153644d93782SGreg Clayton 
153744d93782SGreg Clayton     private:
153844d93782SGreg Clayton         DISALLOW_COPY_AND_ASSIGN(Window);
153944d93782SGreg Clayton     };
154044d93782SGreg Clayton 
154144d93782SGreg Clayton     class MenuDelegate
154244d93782SGreg Clayton     {
154344d93782SGreg Clayton     public:
154444d93782SGreg Clayton         virtual ~MenuDelegate() {}
154544d93782SGreg Clayton 
154644d93782SGreg Clayton         virtual MenuActionResult
154744d93782SGreg Clayton         MenuDelegateAction (Menu &menu) = 0;
154844d93782SGreg Clayton     };
154944d93782SGreg Clayton 
155044d93782SGreg Clayton     class Menu : public WindowDelegate
155144d93782SGreg Clayton     {
155244d93782SGreg Clayton     public:
155344d93782SGreg Clayton         enum class Type
155444d93782SGreg Clayton         {
155544d93782SGreg Clayton             Invalid,
155644d93782SGreg Clayton             Bar,
155744d93782SGreg Clayton             Item,
155844d93782SGreg Clayton             Separator
155944d93782SGreg Clayton         };
156044d93782SGreg Clayton 
156144d93782SGreg Clayton         // Menubar or separator constructor
156244d93782SGreg Clayton         Menu (Type type);
156344d93782SGreg Clayton 
156444d93782SGreg Clayton         // Menuitem constructor
156544d93782SGreg Clayton         Menu (const char *name,
156644d93782SGreg Clayton               const char *key_name,
156744d93782SGreg Clayton               int key_value,
156844d93782SGreg Clayton               uint64_t identifier);
156944d93782SGreg Clayton 
157044d93782SGreg Clayton         virtual ~
157144d93782SGreg Clayton         Menu ()
157244d93782SGreg Clayton         {
157344d93782SGreg Clayton         }
157444d93782SGreg Clayton 
157544d93782SGreg Clayton         const MenuDelegateSP &
157644d93782SGreg Clayton         GetDelegate () const
157744d93782SGreg Clayton         {
157844d93782SGreg Clayton             return m_delegate_sp;
157944d93782SGreg Clayton         }
158044d93782SGreg Clayton 
158144d93782SGreg Clayton         void
158244d93782SGreg Clayton         SetDelegate (const MenuDelegateSP &delegate_sp)
158344d93782SGreg Clayton         {
158444d93782SGreg Clayton             m_delegate_sp = delegate_sp;
158544d93782SGreg Clayton         }
158644d93782SGreg Clayton 
158744d93782SGreg Clayton         void
158844d93782SGreg Clayton         RecalculateNameLengths();
158944d93782SGreg Clayton 
159044d93782SGreg Clayton         void
159144d93782SGreg Clayton         AddSubmenu (const MenuSP &menu_sp);
159244d93782SGreg Clayton 
159344d93782SGreg Clayton         int
159444d93782SGreg Clayton         DrawAndRunMenu (Window &window);
159544d93782SGreg Clayton 
159644d93782SGreg Clayton         void
159744d93782SGreg Clayton         DrawMenuTitle (Window &window, bool highlight);
159844d93782SGreg Clayton 
159944d93782SGreg Clayton         virtual bool
160044d93782SGreg Clayton         WindowDelegateDraw (Window &window, bool force);
160144d93782SGreg Clayton 
160244d93782SGreg Clayton         virtual HandleCharResult
160344d93782SGreg Clayton         WindowDelegateHandleChar (Window &window, int key);
160444d93782SGreg Clayton 
160544d93782SGreg Clayton         MenuActionResult
160644d93782SGreg Clayton         ActionPrivate (Menu &menu)
160744d93782SGreg Clayton         {
160844d93782SGreg Clayton             MenuActionResult result = MenuActionResult::NotHandled;
160944d93782SGreg Clayton             if (m_delegate_sp)
161044d93782SGreg Clayton             {
161144d93782SGreg Clayton                 result = m_delegate_sp->MenuDelegateAction (menu);
161244d93782SGreg Clayton                 if (result != MenuActionResult::NotHandled)
161344d93782SGreg Clayton                     return result;
161444d93782SGreg Clayton             }
161544d93782SGreg Clayton             else if (m_parent)
161644d93782SGreg Clayton             {
161744d93782SGreg Clayton                 result = m_parent->ActionPrivate(menu);
161844d93782SGreg Clayton                 if (result != MenuActionResult::NotHandled)
161944d93782SGreg Clayton                     return result;
162044d93782SGreg Clayton             }
162144d93782SGreg Clayton             return m_canned_result;
162244d93782SGreg Clayton         }
162344d93782SGreg Clayton 
162444d93782SGreg Clayton         MenuActionResult
162544d93782SGreg Clayton         Action ()
162644d93782SGreg Clayton         {
162744d93782SGreg Clayton             // Call the recursive action so it can try to handle it
162844d93782SGreg Clayton             // with the menu delegate, and if not, try our parent menu
162944d93782SGreg Clayton             return ActionPrivate (*this);
163044d93782SGreg Clayton         }
163144d93782SGreg Clayton 
163244d93782SGreg Clayton         void
163344d93782SGreg Clayton         SetCannedResult (MenuActionResult result)
163444d93782SGreg Clayton         {
163544d93782SGreg Clayton             m_canned_result = result;
163644d93782SGreg Clayton         }
163744d93782SGreg Clayton 
163844d93782SGreg Clayton         Menus &
163944d93782SGreg Clayton         GetSubmenus()
164044d93782SGreg Clayton         {
164144d93782SGreg Clayton             return m_submenus;
164244d93782SGreg Clayton         }
164344d93782SGreg Clayton 
164444d93782SGreg Clayton         const Menus &
164544d93782SGreg Clayton         GetSubmenus() const
164644d93782SGreg Clayton         {
164744d93782SGreg Clayton             return m_submenus;
164844d93782SGreg Clayton         }
164944d93782SGreg Clayton 
165044d93782SGreg Clayton         int
165144d93782SGreg Clayton         GetSelectedSubmenuIndex () const
165244d93782SGreg Clayton         {
165344d93782SGreg Clayton             return m_selected;
165444d93782SGreg Clayton         }
165544d93782SGreg Clayton 
165644d93782SGreg Clayton         void
165744d93782SGreg Clayton         SetSelectedSubmenuIndex (int idx)
165844d93782SGreg Clayton         {
165944d93782SGreg Clayton             m_selected = idx;
166044d93782SGreg Clayton         }
166144d93782SGreg Clayton 
166244d93782SGreg Clayton         Type
166344d93782SGreg Clayton         GetType () const
166444d93782SGreg Clayton         {
166544d93782SGreg Clayton             return m_type;
166644d93782SGreg Clayton         }
166744d93782SGreg Clayton 
166844d93782SGreg Clayton         int
166944d93782SGreg Clayton         GetStartingColumn() const
167044d93782SGreg Clayton         {
167144d93782SGreg Clayton             return m_start_col;
167244d93782SGreg Clayton         }
167344d93782SGreg Clayton 
167444d93782SGreg Clayton         void
167544d93782SGreg Clayton         SetStartingColumn(int col)
167644d93782SGreg Clayton         {
167744d93782SGreg Clayton             m_start_col = col;
167844d93782SGreg Clayton         }
167944d93782SGreg Clayton 
168044d93782SGreg Clayton         int
168144d93782SGreg Clayton         GetKeyValue() const
168244d93782SGreg Clayton         {
168344d93782SGreg Clayton             return m_key_value;
168444d93782SGreg Clayton         }
168544d93782SGreg Clayton 
168644d93782SGreg Clayton         void
168744d93782SGreg Clayton         SetKeyValue(int key_value)
168844d93782SGreg Clayton         {
168944d93782SGreg Clayton             m_key_value = key_value;
169044d93782SGreg Clayton         }
169144d93782SGreg Clayton 
169244d93782SGreg Clayton         std::string &
169344d93782SGreg Clayton         GetName()
169444d93782SGreg Clayton         {
169544d93782SGreg Clayton             return m_name;
169644d93782SGreg Clayton         }
169744d93782SGreg Clayton 
169844d93782SGreg Clayton         std::string &
169944d93782SGreg Clayton         GetKeyName()
170044d93782SGreg Clayton         {
170144d93782SGreg Clayton             return m_key_name;
170244d93782SGreg Clayton         }
170344d93782SGreg Clayton 
170444d93782SGreg Clayton         int
170544d93782SGreg Clayton         GetDrawWidth () const
170644d93782SGreg Clayton         {
170744d93782SGreg Clayton             return m_max_submenu_name_length + m_max_submenu_key_name_length + 8;
170844d93782SGreg Clayton         }
170944d93782SGreg Clayton 
171044d93782SGreg Clayton 
171144d93782SGreg Clayton         uint64_t
171244d93782SGreg Clayton         GetIdentifier() const
171344d93782SGreg Clayton         {
171444d93782SGreg Clayton             return m_identifier;
171544d93782SGreg Clayton         }
171644d93782SGreg Clayton 
171744d93782SGreg Clayton         void
171844d93782SGreg Clayton         SetIdentifier (uint64_t identifier)
171944d93782SGreg Clayton         {
172044d93782SGreg Clayton             m_identifier = identifier;
172144d93782SGreg Clayton         }
172244d93782SGreg Clayton 
172344d93782SGreg Clayton     protected:
172444d93782SGreg Clayton         std::string m_name;
172544d93782SGreg Clayton         std::string m_key_name;
172644d93782SGreg Clayton         uint64_t m_identifier;
172744d93782SGreg Clayton         Type m_type;
172844d93782SGreg Clayton         int m_key_value;
172944d93782SGreg Clayton         int m_start_col;
173044d93782SGreg Clayton         int m_max_submenu_name_length;
173144d93782SGreg Clayton         int m_max_submenu_key_name_length;
173244d93782SGreg Clayton         int m_selected;
173344d93782SGreg Clayton         Menu *m_parent;
173444d93782SGreg Clayton         Menus m_submenus;
173544d93782SGreg Clayton         WindowSP m_menu_window_sp;
173644d93782SGreg Clayton         MenuActionResult m_canned_result;
173744d93782SGreg Clayton         MenuDelegateSP m_delegate_sp;
173844d93782SGreg Clayton     };
173944d93782SGreg Clayton 
174044d93782SGreg Clayton     // Menubar or separator constructor
174144d93782SGreg Clayton     Menu::Menu (Type type) :
174244d93782SGreg Clayton         m_name (),
174344d93782SGreg Clayton         m_key_name (),
174444d93782SGreg Clayton         m_identifier (0),
174544d93782SGreg Clayton         m_type (type),
174644d93782SGreg Clayton         m_key_value (0),
174744d93782SGreg Clayton         m_start_col (0),
174844d93782SGreg Clayton         m_max_submenu_name_length (0),
174944d93782SGreg Clayton         m_max_submenu_key_name_length (0),
175044d93782SGreg Clayton         m_selected (0),
175144d93782SGreg Clayton         m_parent (NULL),
175244d93782SGreg Clayton         m_submenus (),
175344d93782SGreg Clayton         m_canned_result (MenuActionResult::NotHandled),
175444d93782SGreg Clayton         m_delegate_sp()
175544d93782SGreg Clayton     {
175644d93782SGreg Clayton     }
175744d93782SGreg Clayton 
175844d93782SGreg Clayton     // Menuitem constructor
175944d93782SGreg Clayton     Menu::Menu (const char *name,
176044d93782SGreg Clayton                 const char *key_name,
176144d93782SGreg Clayton                 int key_value,
176244d93782SGreg Clayton                 uint64_t identifier) :
176344d93782SGreg Clayton         m_name (),
176444d93782SGreg Clayton         m_key_name (),
176544d93782SGreg Clayton         m_identifier (identifier),
176644d93782SGreg Clayton         m_type (Type::Invalid),
176744d93782SGreg Clayton         m_key_value (key_value),
176844d93782SGreg Clayton         m_start_col (0),
176944d93782SGreg Clayton         m_max_submenu_name_length (0),
177044d93782SGreg Clayton         m_max_submenu_key_name_length (0),
177144d93782SGreg Clayton         m_selected (0),
177244d93782SGreg Clayton         m_parent (NULL),
177344d93782SGreg Clayton         m_submenus (),
177444d93782SGreg Clayton         m_canned_result (MenuActionResult::NotHandled),
177544d93782SGreg Clayton         m_delegate_sp()
177644d93782SGreg Clayton     {
177744d93782SGreg Clayton         if (name && name[0])
177844d93782SGreg Clayton         {
177944d93782SGreg Clayton             m_name = name;
178044d93782SGreg Clayton             m_type = Type::Item;
178144d93782SGreg Clayton             if (key_name && key_name[0])
178244d93782SGreg Clayton                 m_key_name = key_name;
178344d93782SGreg Clayton         }
178444d93782SGreg Clayton         else
178544d93782SGreg Clayton         {
178644d93782SGreg Clayton             m_type = Type::Separator;
178744d93782SGreg Clayton         }
178844d93782SGreg Clayton     }
178944d93782SGreg Clayton 
179044d93782SGreg Clayton     void
179144d93782SGreg Clayton     Menu::RecalculateNameLengths()
179244d93782SGreg Clayton     {
179344d93782SGreg Clayton         m_max_submenu_name_length = 0;
179444d93782SGreg Clayton         m_max_submenu_key_name_length = 0;
179544d93782SGreg Clayton         Menus &submenus = GetSubmenus();
179644d93782SGreg Clayton         const size_t num_submenus = submenus.size();
179744d93782SGreg Clayton         for (size_t i=0; i<num_submenus; ++i)
179844d93782SGreg Clayton         {
179944d93782SGreg Clayton             Menu *submenu = submenus[i].get();
180044d93782SGreg Clayton             if (m_max_submenu_name_length < submenu->m_name.size())
180144d93782SGreg Clayton                 m_max_submenu_name_length = submenu->m_name.size();
180244d93782SGreg Clayton             if (m_max_submenu_key_name_length < submenu->m_key_name.size())
180344d93782SGreg Clayton                 m_max_submenu_key_name_length = submenu->m_key_name.size();
180444d93782SGreg Clayton         }
180544d93782SGreg Clayton     }
180644d93782SGreg Clayton 
180744d93782SGreg Clayton     void
180844d93782SGreg Clayton     Menu::AddSubmenu (const MenuSP &menu_sp)
180944d93782SGreg Clayton     {
181044d93782SGreg Clayton         menu_sp->m_parent = this;
181144d93782SGreg Clayton         if (m_max_submenu_name_length < menu_sp->m_name.size())
181244d93782SGreg Clayton             m_max_submenu_name_length = menu_sp->m_name.size();
181344d93782SGreg Clayton         if (m_max_submenu_key_name_length < menu_sp->m_key_name.size())
181444d93782SGreg Clayton             m_max_submenu_key_name_length = menu_sp->m_key_name.size();
181544d93782SGreg Clayton         m_submenus.push_back(menu_sp);
181644d93782SGreg Clayton     }
181744d93782SGreg Clayton 
181844d93782SGreg Clayton     void
181944d93782SGreg Clayton     Menu::DrawMenuTitle (Window &window, bool highlight)
182044d93782SGreg Clayton     {
182144d93782SGreg Clayton         if (m_type == Type::Separator)
182244d93782SGreg Clayton         {
182344d93782SGreg Clayton             window.MoveCursor(0, window.GetCursorY());
182444d93782SGreg Clayton             window.PutChar(ACS_LTEE);
182544d93782SGreg Clayton             int width = window.GetWidth();
182644d93782SGreg Clayton             if (width > 2)
182744d93782SGreg Clayton             {
182844d93782SGreg Clayton                 width -= 2;
182944d93782SGreg Clayton                 for (size_t i=0; i< width; ++i)
183044d93782SGreg Clayton                     window.PutChar(ACS_HLINE);
183144d93782SGreg Clayton             }
183244d93782SGreg Clayton             window.PutChar(ACS_RTEE);
183344d93782SGreg Clayton         }
183444d93782SGreg Clayton         else
183544d93782SGreg Clayton         {
183644d93782SGreg Clayton             const int shortcut_key = m_key_value;
183744d93782SGreg Clayton             bool underlined_shortcut = false;
183844d93782SGreg Clayton             const attr_t hilgight_attr = A_REVERSE;
183944d93782SGreg Clayton             if (highlight)
184044d93782SGreg Clayton                 window.AttributeOn(hilgight_attr);
184144d93782SGreg Clayton             if (isprint(shortcut_key))
184244d93782SGreg Clayton             {
184344d93782SGreg Clayton                 size_t lower_pos = m_name.find(tolower(shortcut_key));
184444d93782SGreg Clayton                 size_t upper_pos = m_name.find(toupper(shortcut_key));
184544d93782SGreg Clayton                 const char *name = m_name.c_str();
184644d93782SGreg Clayton                 size_t pos = std::min<size_t>(lower_pos, upper_pos);
184744d93782SGreg Clayton                 if (pos != std::string::npos)
184844d93782SGreg Clayton                 {
184944d93782SGreg Clayton                     underlined_shortcut = true;
185044d93782SGreg Clayton                     if (pos > 0)
185144d93782SGreg Clayton                     {
185244d93782SGreg Clayton                         window.PutCString(name, pos);
185344d93782SGreg Clayton                         name += pos;
185444d93782SGreg Clayton                     }
185544d93782SGreg Clayton                     const attr_t shortcut_attr = A_UNDERLINE|A_BOLD;
185644d93782SGreg Clayton                     window.AttributeOn (shortcut_attr);
185744d93782SGreg Clayton                     window.PutChar(name[0]);
185844d93782SGreg Clayton                     window.AttributeOff(shortcut_attr);
185944d93782SGreg Clayton                     name++;
186044d93782SGreg Clayton                     if (name[0])
186144d93782SGreg Clayton                         window.PutCString(name);
186244d93782SGreg Clayton                 }
186344d93782SGreg Clayton             }
186444d93782SGreg Clayton 
186544d93782SGreg Clayton             if (!underlined_shortcut)
186644d93782SGreg Clayton             {
186744d93782SGreg Clayton                 window.PutCString(m_name.c_str());
186844d93782SGreg Clayton             }
186944d93782SGreg Clayton 
187044d93782SGreg Clayton             if (highlight)
187144d93782SGreg Clayton                 window.AttributeOff(hilgight_attr);
187244d93782SGreg Clayton 
187344d93782SGreg Clayton             if (m_key_name.empty())
187444d93782SGreg Clayton             {
187544d93782SGreg Clayton                 if (!underlined_shortcut && isprint(m_key_value))
187644d93782SGreg Clayton                 {
187744d93782SGreg Clayton                     window.AttributeOn (COLOR_PAIR(3));
187844d93782SGreg Clayton                     window.Printf (" (%c)", m_key_value);
187944d93782SGreg Clayton                     window.AttributeOff (COLOR_PAIR(3));
188044d93782SGreg Clayton                 }
188144d93782SGreg Clayton             }
188244d93782SGreg Clayton             else
188344d93782SGreg Clayton             {
188444d93782SGreg Clayton                 window.AttributeOn (COLOR_PAIR(3));
188544d93782SGreg Clayton                 window.Printf (" (%s)", m_key_name.c_str());
188644d93782SGreg Clayton                 window.AttributeOff (COLOR_PAIR(3));
188744d93782SGreg Clayton             }
188844d93782SGreg Clayton         }
188944d93782SGreg Clayton     }
189044d93782SGreg Clayton 
189144d93782SGreg Clayton     bool
189244d93782SGreg Clayton     Menu::WindowDelegateDraw (Window &window, bool force)
189344d93782SGreg Clayton     {
189444d93782SGreg Clayton         Menus &submenus = GetSubmenus();
189544d93782SGreg Clayton         const size_t num_submenus = submenus.size();
189644d93782SGreg Clayton         const int selected_idx = GetSelectedSubmenuIndex();
189744d93782SGreg Clayton         Menu::Type menu_type = GetType ();
189844d93782SGreg Clayton         switch (menu_type)
189944d93782SGreg Clayton         {
190044d93782SGreg Clayton         case  Menu::Type::Bar:
190144d93782SGreg Clayton             {
190244d93782SGreg Clayton                 window.SetBackground(2);
190344d93782SGreg Clayton                 window.MoveCursor(0, 0);
190444d93782SGreg Clayton                 for (size_t i=0; i<num_submenus; ++i)
190544d93782SGreg Clayton                 {
190644d93782SGreg Clayton                     Menu *menu = submenus[i].get();
190744d93782SGreg Clayton                     if (i > 0)
190844d93782SGreg Clayton                         window.PutChar(' ');
190944d93782SGreg Clayton                     menu->SetStartingColumn (window.GetCursorX());
191044d93782SGreg Clayton                     window.PutCString("| ");
191144d93782SGreg Clayton                     menu->DrawMenuTitle (window, false);
191244d93782SGreg Clayton                 }
191344d93782SGreg Clayton                 window.PutCString(" |");
191444d93782SGreg Clayton                 window.DeferredRefresh();
191544d93782SGreg Clayton             }
191644d93782SGreg Clayton             break;
191744d93782SGreg Clayton 
191844d93782SGreg Clayton         case Menu::Type::Item:
191944d93782SGreg Clayton             {
192044d93782SGreg Clayton                 int y = 1;
192144d93782SGreg Clayton                 int x = 3;
192244d93782SGreg Clayton                 // Draw the menu
192344d93782SGreg Clayton                 int cursor_x = 0;
192444d93782SGreg Clayton                 int cursor_y = 0;
192544d93782SGreg Clayton                 window.Erase();
192644d93782SGreg Clayton                 window.SetBackground(2);
192744d93782SGreg Clayton                 window.Box();
192844d93782SGreg Clayton                 for (size_t i=0; i<num_submenus; ++i)
192944d93782SGreg Clayton                 {
193044d93782SGreg Clayton                     const bool is_selected = i == selected_idx;
193144d93782SGreg Clayton                     window.MoveCursor(x, y + i);
193244d93782SGreg Clayton                     if (is_selected)
193344d93782SGreg Clayton                     {
193444d93782SGreg Clayton                         // Remember where we want the cursor to be
193544d93782SGreg Clayton                         cursor_x = x-1;
193644d93782SGreg Clayton                         cursor_y = y+i;
193744d93782SGreg Clayton                     }
193844d93782SGreg Clayton                     submenus[i]->DrawMenuTitle (window, is_selected);
193944d93782SGreg Clayton                 }
194044d93782SGreg Clayton                 window.MoveCursor(cursor_x, cursor_y);
194144d93782SGreg Clayton                 window.DeferredRefresh();
194244d93782SGreg Clayton             }
194344d93782SGreg Clayton             break;
194444d93782SGreg Clayton 
194544d93782SGreg Clayton         default:
194644d93782SGreg Clayton         case Menu::Type::Separator:
194744d93782SGreg Clayton             break;
194844d93782SGreg Clayton         }
194944d93782SGreg Clayton         return true; // Drawing handled...
195044d93782SGreg Clayton     }
195144d93782SGreg Clayton 
195244d93782SGreg Clayton     HandleCharResult
195344d93782SGreg Clayton     Menu::WindowDelegateHandleChar (Window &window, int key)
195444d93782SGreg Clayton     {
195544d93782SGreg Clayton         HandleCharResult result = eKeyNotHandled;
195644d93782SGreg Clayton 
195744d93782SGreg Clayton         Menus &submenus = GetSubmenus();
195844d93782SGreg Clayton         const size_t num_submenus = submenus.size();
195944d93782SGreg Clayton         const int selected_idx = GetSelectedSubmenuIndex();
196044d93782SGreg Clayton         Menu::Type menu_type = GetType ();
196144d93782SGreg Clayton         if (menu_type == Menu::Type::Bar)
196244d93782SGreg Clayton         {
196344d93782SGreg Clayton             MenuSP run_menu_sp;
196444d93782SGreg Clayton             switch (key)
196544d93782SGreg Clayton             {
196644d93782SGreg Clayton                 case KEY_DOWN:
196744d93782SGreg Clayton                 case KEY_UP:
196844d93782SGreg Clayton                     // Show last menu or first menu
196944d93782SGreg Clayton                     if (selected_idx < num_submenus)
197044d93782SGreg Clayton                         run_menu_sp = submenus[selected_idx];
197144d93782SGreg Clayton                     else if (!submenus.empty())
197244d93782SGreg Clayton                         run_menu_sp = submenus.front();
197344d93782SGreg Clayton                     result = eKeyHandled;
197444d93782SGreg Clayton                     break;
197544d93782SGreg Clayton 
197644d93782SGreg Clayton                 case KEY_RIGHT:
197744d93782SGreg Clayton                 {
197844d93782SGreg Clayton                     ++m_selected;
197944d93782SGreg Clayton                     if (m_selected >= num_submenus)
198044d93782SGreg Clayton                         m_selected = 0;
198144d93782SGreg Clayton                     if (m_selected < num_submenus)
198244d93782SGreg Clayton                         run_menu_sp = submenus[m_selected];
198344d93782SGreg Clayton                     else if (!submenus.empty())
198444d93782SGreg Clayton                         run_menu_sp = submenus.front();
198544d93782SGreg Clayton                     result = eKeyHandled;
198644d93782SGreg Clayton                 }
198744d93782SGreg Clayton                     break;
198844d93782SGreg Clayton 
198944d93782SGreg Clayton                 case KEY_LEFT:
199044d93782SGreg Clayton                 {
199144d93782SGreg Clayton                     --m_selected;
199244d93782SGreg Clayton                     if (m_selected < 0)
199344d93782SGreg Clayton                         m_selected = num_submenus - 1;
199444d93782SGreg Clayton                     if (m_selected < num_submenus)
199544d93782SGreg Clayton                         run_menu_sp = submenus[m_selected];
199644d93782SGreg Clayton                     else if (!submenus.empty())
199744d93782SGreg Clayton                         run_menu_sp = submenus.front();
199844d93782SGreg Clayton                     result = eKeyHandled;
199944d93782SGreg Clayton                 }
200044d93782SGreg Clayton                     break;
200144d93782SGreg Clayton 
200244d93782SGreg Clayton                 default:
200344d93782SGreg Clayton                     for (size_t i=0; i<num_submenus; ++i)
200444d93782SGreg Clayton                     {
200544d93782SGreg Clayton                         if (submenus[i]->GetKeyValue() == key)
200644d93782SGreg Clayton                         {
200744d93782SGreg Clayton                             SetSelectedSubmenuIndex(i);
200844d93782SGreg Clayton                             run_menu_sp = submenus[i];
200944d93782SGreg Clayton                             result = eKeyHandled;
201044d93782SGreg Clayton                             break;
201144d93782SGreg Clayton                         }
201244d93782SGreg Clayton                     }
201344d93782SGreg Clayton                     break;
201444d93782SGreg Clayton             }
201544d93782SGreg Clayton 
201644d93782SGreg Clayton             if (run_menu_sp)
201744d93782SGreg Clayton             {
201844d93782SGreg Clayton                 // Run the action on this menu in case we need to populate the
201944d93782SGreg Clayton                 // menu with dynamic content and also in case check marks, and
202044d93782SGreg Clayton                 // any other menu decorations need to be caclulated
202144d93782SGreg Clayton                 if (run_menu_sp->Action() == MenuActionResult::Quit)
202244d93782SGreg Clayton                     return eQuitApplication;
202344d93782SGreg Clayton 
202444d93782SGreg Clayton                 Rect menu_bounds;
202544d93782SGreg Clayton                 menu_bounds.origin.x = run_menu_sp->GetStartingColumn();
202644d93782SGreg Clayton                 menu_bounds.origin.y = 1;
202744d93782SGreg Clayton                 menu_bounds.size.width = run_menu_sp->GetDrawWidth();
202844d93782SGreg Clayton                 menu_bounds.size.height = run_menu_sp->GetSubmenus().size() + 2;
202944d93782SGreg Clayton                 if (m_menu_window_sp)
203044d93782SGreg Clayton                     window.GetParent()->RemoveSubWindow(m_menu_window_sp.get());
203144d93782SGreg Clayton 
203244d93782SGreg Clayton                 m_menu_window_sp = window.GetParent()->CreateSubWindow (run_menu_sp->GetName().c_str(),
203344d93782SGreg Clayton                                                                         menu_bounds,
203444d93782SGreg Clayton                                                                         true);
203544d93782SGreg Clayton                 m_menu_window_sp->SetDelegate (run_menu_sp);
203644d93782SGreg Clayton             }
203744d93782SGreg Clayton         }
203844d93782SGreg Clayton         else if (menu_type == Menu::Type::Item)
203944d93782SGreg Clayton         {
204044d93782SGreg Clayton             switch (key)
204144d93782SGreg Clayton             {
204244d93782SGreg Clayton                 case KEY_DOWN:
204344d93782SGreg Clayton                     if (m_submenus.size() > 1)
204444d93782SGreg Clayton                     {
204544d93782SGreg Clayton                         const int start_select = m_selected;
204644d93782SGreg Clayton                         while (++m_selected != start_select)
204744d93782SGreg Clayton                         {
204844d93782SGreg Clayton                             if (m_selected >= num_submenus)
204944d93782SGreg Clayton                                 m_selected = 0;
205044d93782SGreg Clayton                             if (m_submenus[m_selected]->GetType() == Type::Separator)
205144d93782SGreg Clayton                                 continue;
205244d93782SGreg Clayton                             else
205344d93782SGreg Clayton                                 break;
205444d93782SGreg Clayton                         }
205544d93782SGreg Clayton                         return eKeyHandled;
205644d93782SGreg Clayton                     }
205744d93782SGreg Clayton                     break;
205844d93782SGreg Clayton 
205944d93782SGreg Clayton                 case KEY_UP:
206044d93782SGreg Clayton                     if (m_submenus.size() > 1)
206144d93782SGreg Clayton                     {
206244d93782SGreg Clayton                         const int start_select = m_selected;
206344d93782SGreg Clayton                         while (--m_selected != start_select)
206444d93782SGreg Clayton                         {
206544d93782SGreg Clayton                             if (m_selected < 0)
206644d93782SGreg Clayton                                 m_selected = num_submenus - 1;
206744d93782SGreg Clayton                             if (m_submenus[m_selected]->GetType() == Type::Separator)
206844d93782SGreg Clayton                                 continue;
206944d93782SGreg Clayton                             else
207044d93782SGreg Clayton                                 break;
207144d93782SGreg Clayton                         }
207244d93782SGreg Clayton                         return eKeyHandled;
207344d93782SGreg Clayton                     }
207444d93782SGreg Clayton                     break;
207544d93782SGreg Clayton 
207644d93782SGreg Clayton                 case KEY_RETURN:
207744d93782SGreg Clayton                     if (selected_idx < num_submenus)
207844d93782SGreg Clayton                     {
207944d93782SGreg Clayton                         if (submenus[selected_idx]->Action() == MenuActionResult::Quit)
208044d93782SGreg Clayton                             return eQuitApplication;
208144d93782SGreg Clayton                         window.GetParent()->RemoveSubWindow(&window);
208244d93782SGreg Clayton                         return eKeyHandled;
208344d93782SGreg Clayton                     }
208444d93782SGreg Clayton                     break;
208544d93782SGreg Clayton 
208644d93782SGreg Clayton                 case KEY_ESCAPE: // Beware: pressing escape key has 1 to 2 second delay in case other chars are entered for escaped sequences
208744d93782SGreg Clayton                     window.GetParent()->RemoveSubWindow(&window);
208844d93782SGreg Clayton                     return eKeyHandled;
208944d93782SGreg Clayton 
209044d93782SGreg Clayton                 default:
209144d93782SGreg Clayton                 {
209244d93782SGreg Clayton                     bool handled = false;
209344d93782SGreg Clayton                     for (size_t i=0; i<num_submenus; ++i)
209444d93782SGreg Clayton                     {
209544d93782SGreg Clayton                         Menu *menu = submenus[i].get();
209644d93782SGreg Clayton                         if (menu->GetKeyValue() == key)
209744d93782SGreg Clayton                         {
209844d93782SGreg Clayton                             handled = true;
209944d93782SGreg Clayton                             SetSelectedSubmenuIndex(i);
210044d93782SGreg Clayton                             window.GetParent()->RemoveSubWindow(&window);
210144d93782SGreg Clayton                             if (menu->Action() == MenuActionResult::Quit)
210244d93782SGreg Clayton                                 return eQuitApplication;
210344d93782SGreg Clayton                             return eKeyHandled;
210444d93782SGreg Clayton                         }
210544d93782SGreg Clayton                     }
210644d93782SGreg Clayton                 }
210744d93782SGreg Clayton                     break;
210844d93782SGreg Clayton 
210944d93782SGreg Clayton             }
211044d93782SGreg Clayton         }
211144d93782SGreg Clayton         else if (menu_type == Menu::Type::Separator)
211244d93782SGreg Clayton         {
211344d93782SGreg Clayton 
211444d93782SGreg Clayton         }
211544d93782SGreg Clayton         return result;
211644d93782SGreg Clayton     }
211744d93782SGreg Clayton 
211844d93782SGreg Clayton 
211944d93782SGreg Clayton     class Application
212044d93782SGreg Clayton     {
212144d93782SGreg Clayton     public:
212244d93782SGreg Clayton         Application (FILE *in, FILE *out) :
212344d93782SGreg Clayton             m_window_sp(),
212444d93782SGreg Clayton             m_screen (NULL),
212544d93782SGreg Clayton             m_in (in),
212644d93782SGreg Clayton             m_out (out)
212744d93782SGreg Clayton         {
212844d93782SGreg Clayton 
212944d93782SGreg Clayton         }
213044d93782SGreg Clayton 
213144d93782SGreg Clayton         ~Application ()
213244d93782SGreg Clayton         {
213344d93782SGreg Clayton             m_window_delegates.clear();
213444d93782SGreg Clayton             m_window_sp.reset();
213544d93782SGreg Clayton             if (m_screen)
213644d93782SGreg Clayton             {
213744d93782SGreg Clayton                 ::delscreen(m_screen);
213844d93782SGreg Clayton                 m_screen = NULL;
213944d93782SGreg Clayton             }
214044d93782SGreg Clayton         }
214144d93782SGreg Clayton 
214244d93782SGreg Clayton         void
214344d93782SGreg Clayton         Initialize ()
214444d93782SGreg Clayton         {
214544d93782SGreg Clayton             ::setlocale(LC_ALL, "");
214644d93782SGreg Clayton             ::setlocale(LC_CTYPE, "");
214744d93782SGreg Clayton #if 0
214844d93782SGreg Clayton             ::initscr();
214944d93782SGreg Clayton #else
215044d93782SGreg Clayton             m_screen = ::newterm(NULL, m_out, m_in);
215144d93782SGreg Clayton #endif
215244d93782SGreg Clayton             ::start_color();
215344d93782SGreg Clayton             ::curs_set(0);
215444d93782SGreg Clayton             ::noecho();
215544d93782SGreg Clayton             ::keypad(stdscr,TRUE);
215644d93782SGreg Clayton         }
215744d93782SGreg Clayton 
215844d93782SGreg Clayton         void
215944d93782SGreg Clayton         Terminate ()
216044d93782SGreg Clayton         {
216144d93782SGreg Clayton             ::endwin();
216244d93782SGreg Clayton         }
216344d93782SGreg Clayton 
216444d93782SGreg Clayton         void
216544d93782SGreg Clayton         Run (Debugger &debugger)
216644d93782SGreg Clayton         {
216744d93782SGreg Clayton             bool done = false;
216844d93782SGreg Clayton             int delay_in_tenths_of_a_second = 1;
216944d93782SGreg Clayton 
217044d93782SGreg Clayton             // Alas the threading model in curses is a bit lame so we need to
217144d93782SGreg Clayton             // resort to polling every 0.5 seconds. We could poll for stdin
217244d93782SGreg Clayton             // ourselves and then pass the keys down but then we need to
217344d93782SGreg Clayton             // translate all of the escape sequences ourselves. So we resort to
217444d93782SGreg Clayton             // polling for input because we need to receive async process events
217544d93782SGreg Clayton             // while in this loop.
217644d93782SGreg Clayton 
217744d93782SGreg Clayton             halfdelay(delay_in_tenths_of_a_second); // Poll using some number of tenths of seconds seconds when calling Window::GetChar()
217844d93782SGreg Clayton 
217944d93782SGreg Clayton             ListenerSP listener_sp (new Listener ("lldb.IOHandler.curses.Application"));
218044d93782SGreg Clayton             ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass());
218144d93782SGreg Clayton             ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass());
218244d93782SGreg Clayton             ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass());
218344d93782SGreg Clayton             debugger.EnableForwardEvents (listener_sp);
218444d93782SGreg Clayton 
218544d93782SGreg Clayton             bool update = true;
218644d93782SGreg Clayton #if defined(__APPLE__)
218744d93782SGreg Clayton             std::deque<int> escape_chars;
218844d93782SGreg Clayton #endif
218944d93782SGreg Clayton 
219044d93782SGreg Clayton             while (!done)
219144d93782SGreg Clayton             {
219244d93782SGreg Clayton                 if (update)
219344d93782SGreg Clayton                 {
219444d93782SGreg Clayton                     m_window_sp->Draw(false);
219544d93782SGreg Clayton                     // All windows should be calling Window::DeferredRefresh() instead
219644d93782SGreg Clayton                     // of Window::Refresh() so we can do a single update and avoid
219744d93782SGreg Clayton                     // any screen blinking
219844d93782SGreg Clayton                     update_panels();
219944d93782SGreg Clayton 
220044d93782SGreg Clayton                     // Cursor hiding isn't working on MacOSX, so hide it in the top left corner
220144d93782SGreg Clayton                     m_window_sp->MoveCursor(0, 0);
220244d93782SGreg Clayton 
220344d93782SGreg Clayton                     doupdate();
220444d93782SGreg Clayton                     update = false;
220544d93782SGreg Clayton                 }
220644d93782SGreg Clayton 
220744d93782SGreg Clayton #if defined(__APPLE__)
220844d93782SGreg Clayton                 // Terminal.app doesn't map its function keys correctly, F1-F4 default to:
220944d93782SGreg Clayton                 // \033OP, \033OQ, \033OR, \033OS, so lets take care of this here if possible
221044d93782SGreg Clayton                 int ch;
221144d93782SGreg Clayton                 if (escape_chars.empty())
221244d93782SGreg Clayton                     ch = m_window_sp->GetChar();
221344d93782SGreg Clayton                 else
221444d93782SGreg Clayton                 {
221544d93782SGreg Clayton                     ch = escape_chars.front();
221644d93782SGreg Clayton                     escape_chars.pop_front();
221744d93782SGreg Clayton                 }
221844d93782SGreg Clayton                 if (ch == KEY_ESCAPE)
221944d93782SGreg Clayton                 {
222044d93782SGreg Clayton                     int ch2 = m_window_sp->GetChar();
222144d93782SGreg Clayton                     if (ch2 == 'O')
222244d93782SGreg Clayton                     {
222344d93782SGreg Clayton                         int ch3 = m_window_sp->GetChar();
222444d93782SGreg Clayton                         switch (ch3)
222544d93782SGreg Clayton                         {
222644d93782SGreg Clayton                             case 'P': ch = KEY_F(1); break;
222744d93782SGreg Clayton                             case 'Q': ch = KEY_F(2); break;
222844d93782SGreg Clayton                             case 'R': ch = KEY_F(3); break;
222944d93782SGreg Clayton                             case 'S': ch = KEY_F(4); break;
223044d93782SGreg Clayton                             default:
223144d93782SGreg Clayton                                 escape_chars.push_back(ch2);
223244d93782SGreg Clayton                                 if (ch3 != -1)
223344d93782SGreg Clayton                                     escape_chars.push_back(ch3);
223444d93782SGreg Clayton                                 break;
223544d93782SGreg Clayton                         }
223644d93782SGreg Clayton                     }
223744d93782SGreg Clayton                     else if (ch2 != -1)
223844d93782SGreg Clayton                         escape_chars.push_back(ch2);
223944d93782SGreg Clayton                 }
224044d93782SGreg Clayton #else
224144d93782SGreg Clayton                 int ch = m_window_sp->GetChar();
224244d93782SGreg Clayton 
224344d93782SGreg Clayton #endif
224444d93782SGreg Clayton                 if (ch == -1)
224544d93782SGreg Clayton                 {
224644d93782SGreg Clayton                     if (feof(m_in) || ferror(m_in))
224744d93782SGreg Clayton                     {
224844d93782SGreg Clayton                         done = true;
224944d93782SGreg Clayton                     }
225044d93782SGreg Clayton                     else
225144d93782SGreg Clayton                     {
225244d93782SGreg Clayton                         // Just a timeout from using halfdelay(), check for events
225344d93782SGreg Clayton                         EventSP event_sp;
225444d93782SGreg Clayton                         while (listener_sp->PeekAtNextEvent())
225544d93782SGreg Clayton                         {
225644d93782SGreg Clayton                             listener_sp->GetNextEvent(event_sp);
225744d93782SGreg Clayton 
225844d93782SGreg Clayton                             if (event_sp)
225944d93782SGreg Clayton                             {
226044d93782SGreg Clayton                                 Broadcaster *broadcaster = event_sp->GetBroadcaster();
226144d93782SGreg Clayton                                 if (broadcaster)
226244d93782SGreg Clayton                                 {
226344d93782SGreg Clayton                                     //uint32_t event_type = event_sp->GetType();
226444d93782SGreg Clayton                                     ConstString broadcaster_class (broadcaster->GetBroadcasterClass());
226544d93782SGreg Clayton                                     if (broadcaster_class == broadcaster_class_process)
226644d93782SGreg Clayton                                     {
226744d93782SGreg Clayton                                         update = true;
226844d93782SGreg Clayton                                         continue; // Don't get any key, just update our view
226944d93782SGreg Clayton                                     }
227044d93782SGreg Clayton                                 }
227144d93782SGreg Clayton                             }
227244d93782SGreg Clayton                         }
227344d93782SGreg Clayton                     }
227444d93782SGreg Clayton                 }
227544d93782SGreg Clayton                 else
227644d93782SGreg Clayton                 {
227744d93782SGreg Clayton                     HandleCharResult key_result = m_window_sp->HandleChar(ch);
227844d93782SGreg Clayton                     switch (key_result)
227944d93782SGreg Clayton                     {
228044d93782SGreg Clayton                         case eKeyHandled:
228144d93782SGreg Clayton                             update = true;
228244d93782SGreg Clayton                             break;
228344d93782SGreg Clayton                         case eKeyNotHandled:
228444d93782SGreg Clayton                             break;
228544d93782SGreg Clayton                         case eQuitApplication:
228644d93782SGreg Clayton                             done = true;
228744d93782SGreg Clayton                             break;
228844d93782SGreg Clayton                     }
228944d93782SGreg Clayton                 }
229044d93782SGreg Clayton             }
229144d93782SGreg Clayton 
229244d93782SGreg Clayton             debugger.CancelForwardEvents (listener_sp);
229344d93782SGreg Clayton 
229444d93782SGreg Clayton         }
229544d93782SGreg Clayton 
229644d93782SGreg Clayton         WindowSP &
229744d93782SGreg Clayton         GetMainWindow ()
229844d93782SGreg Clayton         {
229944d93782SGreg Clayton             if (!m_window_sp)
230044d93782SGreg Clayton                 m_window_sp.reset (new Window ("main", stdscr, false));
230144d93782SGreg Clayton             return m_window_sp;
230244d93782SGreg Clayton         }
230344d93782SGreg Clayton 
230444d93782SGreg Clayton         WindowDelegates &
230544d93782SGreg Clayton         GetWindowDelegates ()
230644d93782SGreg Clayton         {
230744d93782SGreg Clayton             return m_window_delegates;
230844d93782SGreg Clayton         }
230944d93782SGreg Clayton 
231044d93782SGreg Clayton     protected:
231144d93782SGreg Clayton         WindowSP m_window_sp;
231244d93782SGreg Clayton         WindowDelegates m_window_delegates;
231344d93782SGreg Clayton         SCREEN *m_screen;
231444d93782SGreg Clayton         FILE *m_in;
231544d93782SGreg Clayton         FILE *m_out;
231644d93782SGreg Clayton     };
231744d93782SGreg Clayton 
231844d93782SGreg Clayton 
231944d93782SGreg Clayton } // namespace curses
232044d93782SGreg Clayton 
232144d93782SGreg Clayton 
232244d93782SGreg Clayton using namespace curses;
232344d93782SGreg Clayton 
232444d93782SGreg Clayton struct Row
232544d93782SGreg Clayton {
232644d93782SGreg Clayton     ValueObjectSP valobj;
232744d93782SGreg Clayton     Row *parent;
232844d93782SGreg Clayton     int row_idx;
232944d93782SGreg Clayton     int x;
233044d93782SGreg Clayton     int y;
233144d93782SGreg Clayton     bool might_have_children;
233244d93782SGreg Clayton     bool expanded;
233344d93782SGreg Clayton     bool calculated_children;
233444d93782SGreg Clayton     std::vector<Row> children;
233544d93782SGreg Clayton 
233644d93782SGreg Clayton     Row (const ValueObjectSP &v, Row *p) :
233744d93782SGreg Clayton     valobj (v),
233844d93782SGreg Clayton     parent (p),
233944d93782SGreg Clayton     row_idx(0),
234044d93782SGreg Clayton     x(1),
234144d93782SGreg Clayton     y(1),
234244d93782SGreg Clayton     might_have_children (v ? v->MightHaveChildren() : false),
234344d93782SGreg Clayton     expanded (false),
234444d93782SGreg Clayton     calculated_children (false),
234544d93782SGreg Clayton     children()
234644d93782SGreg Clayton     {
234744d93782SGreg Clayton     }
234844d93782SGreg Clayton 
234944d93782SGreg Clayton     size_t
235044d93782SGreg Clayton     GetDepth () const
235144d93782SGreg Clayton     {
235244d93782SGreg Clayton         if (parent)
235344d93782SGreg Clayton             return 1 + parent->GetDepth();
235444d93782SGreg Clayton         return 0;
235544d93782SGreg Clayton     }
235644d93782SGreg Clayton 
235744d93782SGreg Clayton     void
235844d93782SGreg Clayton     Expand()
235944d93782SGreg Clayton     {
236044d93782SGreg Clayton         expanded = true;
236144d93782SGreg Clayton         if (!calculated_children)
236244d93782SGreg Clayton         {
236344d93782SGreg Clayton             calculated_children = true;
236444d93782SGreg Clayton             if (valobj)
236544d93782SGreg Clayton             {
236644d93782SGreg Clayton                 const size_t num_children = valobj->GetNumChildren();
236744d93782SGreg Clayton                 for (size_t i=0; i<num_children; ++i)
236844d93782SGreg Clayton                 {
236944d93782SGreg Clayton                     children.push_back(Row (valobj->GetChildAtIndex(i, true), this));
237044d93782SGreg Clayton                 }
237144d93782SGreg Clayton             }
237244d93782SGreg Clayton         }
237344d93782SGreg Clayton     }
237444d93782SGreg Clayton 
237544d93782SGreg Clayton     void
237644d93782SGreg Clayton     Unexpand ()
237744d93782SGreg Clayton     {
237844d93782SGreg Clayton         expanded = false;
237944d93782SGreg Clayton     }
238044d93782SGreg Clayton 
238144d93782SGreg Clayton     void
238244d93782SGreg Clayton     DrawTree (Window &window)
238344d93782SGreg Clayton     {
238444d93782SGreg Clayton         if (parent)
238544d93782SGreg Clayton             parent->DrawTreeForChild (window, this, 0);
238644d93782SGreg Clayton 
238744d93782SGreg Clayton         if (might_have_children)
238844d93782SGreg Clayton         {
238944d93782SGreg Clayton             // It we can get UTF8 characters to work we should try to use the "symbol"
239044d93782SGreg Clayton             // UTF8 string below
239144d93782SGreg Clayton //            const char *symbol = "";
239244d93782SGreg Clayton //            if (row.expanded)
239344d93782SGreg Clayton //                symbol = "\xe2\x96\xbd ";
239444d93782SGreg Clayton //            else
239544d93782SGreg Clayton //                symbol = "\xe2\x96\xb7 ";
239644d93782SGreg Clayton //            window.PutCString (symbol);
239744d93782SGreg Clayton 
239844d93782SGreg Clayton             // The ACS_DARROW and ACS_RARROW don't look very nice they are just a
239944d93782SGreg Clayton             // 'v' or '>' character...
240044d93782SGreg Clayton //            if (expanded)
240144d93782SGreg Clayton //                window.PutChar (ACS_DARROW);
240244d93782SGreg Clayton //            else
240344d93782SGreg Clayton //                window.PutChar (ACS_RARROW);
240444d93782SGreg Clayton             // Since we can't find any good looking right arrow/down arrow
240544d93782SGreg Clayton             // symbols, just use a diamond...
240644d93782SGreg Clayton             window.PutChar (ACS_DIAMOND);
240744d93782SGreg Clayton             window.PutChar (ACS_HLINE);
240844d93782SGreg Clayton         }
240944d93782SGreg Clayton     }
241044d93782SGreg Clayton 
241144d93782SGreg Clayton     void
241244d93782SGreg Clayton     DrawTreeForChild (Window &window, Row *child, uint32_t reverse_depth)
241344d93782SGreg Clayton     {
241444d93782SGreg Clayton         if (parent)
241544d93782SGreg Clayton             parent->DrawTreeForChild (window, this, reverse_depth + 1);
241644d93782SGreg Clayton 
241744d93782SGreg Clayton         if (&children.back() == child)
241844d93782SGreg Clayton         {
241944d93782SGreg Clayton             // Last child
242044d93782SGreg Clayton             if (reverse_depth == 0)
242144d93782SGreg Clayton             {
242244d93782SGreg Clayton                 window.PutChar (ACS_LLCORNER);
242344d93782SGreg Clayton                 window.PutChar (ACS_HLINE);
242444d93782SGreg Clayton             }
242544d93782SGreg Clayton             else
242644d93782SGreg Clayton             {
242744d93782SGreg Clayton                 window.PutChar (' ');
242844d93782SGreg Clayton                 window.PutChar (' ');
242944d93782SGreg Clayton             }
243044d93782SGreg Clayton         }
243144d93782SGreg Clayton         else
243244d93782SGreg Clayton         {
243344d93782SGreg Clayton             if (reverse_depth == 0)
243444d93782SGreg Clayton             {
243544d93782SGreg Clayton                 window.PutChar (ACS_LTEE);
243644d93782SGreg Clayton                 window.PutChar (ACS_HLINE);
243744d93782SGreg Clayton             }
243844d93782SGreg Clayton             else
243944d93782SGreg Clayton             {
244044d93782SGreg Clayton                 window.PutChar (ACS_VLINE);
244144d93782SGreg Clayton                 window.PutChar (' ');
244244d93782SGreg Clayton             }
244344d93782SGreg Clayton         }
244444d93782SGreg Clayton     }
244544d93782SGreg Clayton };
244644d93782SGreg Clayton 
244744d93782SGreg Clayton struct DisplayOptions
244844d93782SGreg Clayton {
244944d93782SGreg Clayton     bool show_types;
245044d93782SGreg Clayton };
245144d93782SGreg Clayton 
245244d93782SGreg Clayton class TreeItem;
245344d93782SGreg Clayton 
245444d93782SGreg Clayton class TreeDelegate
245544d93782SGreg Clayton {
245644d93782SGreg Clayton public:
245744d93782SGreg Clayton     TreeDelegate() {}
245844d93782SGreg Clayton     virtual ~TreeDelegate() {}
245944d93782SGreg Clayton     virtual void TreeDelegateDrawTreeItem (TreeItem &item, Window &window) = 0;
246044d93782SGreg Clayton     virtual void TreeDelegateGenerateChildren (TreeItem &item) = 0;
246144d93782SGreg Clayton     virtual bool TreeDelegateItemSelected (TreeItem &item) = 0; // Return true if we need to update views
246244d93782SGreg Clayton };
246344d93782SGreg Clayton typedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
246444d93782SGreg Clayton 
246544d93782SGreg Clayton class TreeItem
246644d93782SGreg Clayton {
246744d93782SGreg Clayton public:
246844d93782SGreg Clayton 
246944d93782SGreg Clayton     TreeItem (TreeItem *parent, TreeDelegate &delegate, bool might_have_children) :
247044d93782SGreg Clayton         m_parent (parent),
247144d93782SGreg Clayton         m_delegate (delegate),
247244d93782SGreg Clayton         m_identifier (0),
247344d93782SGreg Clayton         m_row_idx (-1),
247444d93782SGreg Clayton         m_children (),
247544d93782SGreg Clayton         m_might_have_children (might_have_children),
247644d93782SGreg Clayton         m_is_expanded (false)
247744d93782SGreg Clayton     {
247844d93782SGreg Clayton     }
247944d93782SGreg Clayton 
248044d93782SGreg Clayton     TreeItem &
248144d93782SGreg Clayton     operator=(const TreeItem &rhs)
248244d93782SGreg Clayton     {
248344d93782SGreg Clayton         if (this != &rhs)
248444d93782SGreg Clayton         {
248544d93782SGreg Clayton             m_parent = rhs.m_parent;
248644d93782SGreg Clayton             m_delegate = rhs.m_delegate;
248744d93782SGreg Clayton             m_identifier = rhs.m_identifier;
248844d93782SGreg Clayton             m_row_idx = rhs.m_row_idx;
248944d93782SGreg Clayton             m_children = rhs.m_children;
249044d93782SGreg Clayton             m_might_have_children = rhs.m_might_have_children;
249144d93782SGreg Clayton             m_is_expanded = rhs.m_is_expanded;
249244d93782SGreg Clayton         }
249344d93782SGreg Clayton         return *this;
249444d93782SGreg Clayton     }
249544d93782SGreg Clayton 
249644d93782SGreg Clayton     size_t
249744d93782SGreg Clayton     GetDepth () const
249844d93782SGreg Clayton     {
249944d93782SGreg Clayton         if (m_parent)
250044d93782SGreg Clayton             return 1 + m_parent->GetDepth();
250144d93782SGreg Clayton         return 0;
250244d93782SGreg Clayton     }
250344d93782SGreg Clayton 
250444d93782SGreg Clayton     int
250544d93782SGreg Clayton     GetRowIndex () const
250644d93782SGreg Clayton     {
250744d93782SGreg Clayton         return m_row_idx;
250844d93782SGreg Clayton     }
250944d93782SGreg Clayton 
251044d93782SGreg Clayton     void
251144d93782SGreg Clayton     ClearChildren ()
251244d93782SGreg Clayton     {
251344d93782SGreg Clayton         m_children.clear();
251444d93782SGreg Clayton     }
251544d93782SGreg Clayton 
251644d93782SGreg Clayton     void
251744d93782SGreg Clayton     Resize (size_t n, const TreeItem &t)
251844d93782SGreg Clayton     {
251944d93782SGreg Clayton         m_children.resize(n, t);
252044d93782SGreg Clayton     }
252144d93782SGreg Clayton 
252244d93782SGreg Clayton     TreeItem &
252344d93782SGreg Clayton     operator [](size_t i)
252444d93782SGreg Clayton     {
252544d93782SGreg Clayton         return m_children[i];
252644d93782SGreg Clayton     }
252744d93782SGreg Clayton 
252844d93782SGreg Clayton     void
252944d93782SGreg Clayton     SetRowIndex (int row_idx)
253044d93782SGreg Clayton     {
253144d93782SGreg Clayton         m_row_idx = row_idx;
253244d93782SGreg Clayton     }
253344d93782SGreg Clayton 
253444d93782SGreg Clayton     size_t
253544d93782SGreg Clayton     GetNumChildren ()
253644d93782SGreg Clayton     {
253744d93782SGreg Clayton         m_delegate.TreeDelegateGenerateChildren (*this);
253844d93782SGreg Clayton         return m_children.size();
253944d93782SGreg Clayton     }
254044d93782SGreg Clayton 
254144d93782SGreg Clayton     void
254244d93782SGreg Clayton     ItemWasSelected ()
254344d93782SGreg Clayton     {
254444d93782SGreg Clayton         m_delegate.TreeDelegateItemSelected(*this);
254544d93782SGreg Clayton     }
254644d93782SGreg Clayton     void
254744d93782SGreg Clayton     CalculateRowIndexes (int &row_idx)
254844d93782SGreg Clayton     {
254944d93782SGreg Clayton         SetRowIndex(row_idx);
255044d93782SGreg Clayton         ++row_idx;
255144d93782SGreg Clayton 
255244d93782SGreg Clayton         // The root item must calculate its children
255344d93782SGreg Clayton         if (m_parent == NULL)
255444d93782SGreg Clayton             GetNumChildren();
255544d93782SGreg Clayton 
255644d93782SGreg Clayton         const bool expanded = IsExpanded();
255744d93782SGreg Clayton         for (auto &item : m_children)
255844d93782SGreg Clayton         {
255944d93782SGreg Clayton             if (expanded)
256044d93782SGreg Clayton                 item.CalculateRowIndexes(row_idx);
256144d93782SGreg Clayton             else
256244d93782SGreg Clayton                 item.SetRowIndex(-1);
256344d93782SGreg Clayton         }
256444d93782SGreg Clayton     }
256544d93782SGreg Clayton 
256644d93782SGreg Clayton     TreeItem *
256744d93782SGreg Clayton     GetParent ()
256844d93782SGreg Clayton     {
256944d93782SGreg Clayton         return m_parent;
257044d93782SGreg Clayton     }
257144d93782SGreg Clayton 
257244d93782SGreg Clayton     bool
257344d93782SGreg Clayton     IsExpanded () const
257444d93782SGreg Clayton     {
257544d93782SGreg Clayton         return m_is_expanded;
257644d93782SGreg Clayton     }
257744d93782SGreg Clayton 
257844d93782SGreg Clayton     void
257944d93782SGreg Clayton     Expand()
258044d93782SGreg Clayton     {
258144d93782SGreg Clayton         m_is_expanded = true;
258244d93782SGreg Clayton     }
258344d93782SGreg Clayton 
258444d93782SGreg Clayton     void
258544d93782SGreg Clayton     Unexpand ()
258644d93782SGreg Clayton     {
258744d93782SGreg Clayton         m_is_expanded = false;
258844d93782SGreg Clayton     }
258944d93782SGreg Clayton 
259044d93782SGreg Clayton     bool
259144d93782SGreg Clayton     Draw (Window &window,
259244d93782SGreg Clayton           const int first_visible_row,
259344d93782SGreg Clayton           const uint32_t selected_row_idx,
259444d93782SGreg Clayton           int &row_idx,
259544d93782SGreg Clayton           int &num_rows_left)
259644d93782SGreg Clayton     {
259744d93782SGreg Clayton         if (num_rows_left <= 0)
259844d93782SGreg Clayton             return false;
259944d93782SGreg Clayton 
260044d93782SGreg Clayton         if (m_row_idx >= first_visible_row)
260144d93782SGreg Clayton         {
260244d93782SGreg Clayton             window.MoveCursor(2, row_idx + 1);
260344d93782SGreg Clayton 
260444d93782SGreg Clayton             if (m_parent)
260544d93782SGreg Clayton                 m_parent->DrawTreeForChild (window, this, 0);
260644d93782SGreg Clayton 
260744d93782SGreg Clayton             if (m_might_have_children)
260844d93782SGreg Clayton             {
260944d93782SGreg Clayton                 // It we can get UTF8 characters to work we should try to use the "symbol"
261044d93782SGreg Clayton                 // UTF8 string below
261144d93782SGreg Clayton                 //            const char *symbol = "";
261244d93782SGreg Clayton                 //            if (row.expanded)
261344d93782SGreg Clayton                 //                symbol = "\xe2\x96\xbd ";
261444d93782SGreg Clayton                 //            else
261544d93782SGreg Clayton                 //                symbol = "\xe2\x96\xb7 ";
261644d93782SGreg Clayton                 //            window.PutCString (symbol);
261744d93782SGreg Clayton 
261844d93782SGreg Clayton                 // The ACS_DARROW and ACS_RARROW don't look very nice they are just a
261944d93782SGreg Clayton                 // 'v' or '>' character...
262044d93782SGreg Clayton                 //            if (expanded)
262144d93782SGreg Clayton                 //                window.PutChar (ACS_DARROW);
262244d93782SGreg Clayton                 //            else
262344d93782SGreg Clayton                 //                window.PutChar (ACS_RARROW);
262444d93782SGreg Clayton                 // Since we can't find any good looking right arrow/down arrow
262544d93782SGreg Clayton                 // symbols, just use a diamond...
262644d93782SGreg Clayton                 window.PutChar (ACS_DIAMOND);
262744d93782SGreg Clayton                 window.PutChar (ACS_HLINE);
262844d93782SGreg Clayton             }
262944d93782SGreg Clayton             bool highlight = (selected_row_idx == m_row_idx) && window.IsActive();
263044d93782SGreg Clayton 
263144d93782SGreg Clayton             if (highlight)
263244d93782SGreg Clayton                 window.AttributeOn(A_REVERSE);
263344d93782SGreg Clayton 
263444d93782SGreg Clayton             m_delegate.TreeDelegateDrawTreeItem(*this, window);
263544d93782SGreg Clayton 
263644d93782SGreg Clayton             if (highlight)
263744d93782SGreg Clayton                 window.AttributeOff(A_REVERSE);
263844d93782SGreg Clayton             ++row_idx;
263944d93782SGreg Clayton             --num_rows_left;
264044d93782SGreg Clayton         }
264144d93782SGreg Clayton 
264244d93782SGreg Clayton         if (num_rows_left <= 0)
264344d93782SGreg Clayton             return false; // We are done drawing...
264444d93782SGreg Clayton 
264544d93782SGreg Clayton         if (IsExpanded())
264644d93782SGreg Clayton         {
264744d93782SGreg Clayton             for (auto &item : m_children)
264844d93782SGreg Clayton             {
264944d93782SGreg Clayton                 // If we displayed all the rows and item.Draw() returns
265044d93782SGreg Clayton                 // false we are done drawing and can exit this for loop
265144d93782SGreg Clayton                 if (item.Draw(window, first_visible_row, selected_row_idx, row_idx, num_rows_left) == false)
265244d93782SGreg Clayton                     break;
265344d93782SGreg Clayton             }
265444d93782SGreg Clayton         }
265544d93782SGreg Clayton         return num_rows_left >= 0; // Return true if not done drawing yet
265644d93782SGreg Clayton     }
265744d93782SGreg Clayton 
265844d93782SGreg Clayton     void
265944d93782SGreg Clayton     DrawTreeForChild (Window &window, TreeItem *child, uint32_t reverse_depth)
266044d93782SGreg Clayton     {
266144d93782SGreg Clayton         if (m_parent)
266244d93782SGreg Clayton             m_parent->DrawTreeForChild (window, this, reverse_depth + 1);
266344d93782SGreg Clayton 
266444d93782SGreg Clayton         if (&m_children.back() == child)
266544d93782SGreg Clayton         {
266644d93782SGreg Clayton             // Last child
266744d93782SGreg Clayton             if (reverse_depth == 0)
266844d93782SGreg Clayton             {
266944d93782SGreg Clayton                 window.PutChar (ACS_LLCORNER);
267044d93782SGreg Clayton                 window.PutChar (ACS_HLINE);
267144d93782SGreg Clayton             }
267244d93782SGreg Clayton             else
267344d93782SGreg Clayton             {
267444d93782SGreg Clayton                 window.PutChar (' ');
267544d93782SGreg Clayton                 window.PutChar (' ');
267644d93782SGreg Clayton             }
267744d93782SGreg Clayton         }
267844d93782SGreg Clayton         else
267944d93782SGreg Clayton         {
268044d93782SGreg Clayton             if (reverse_depth == 0)
268144d93782SGreg Clayton             {
268244d93782SGreg Clayton                 window.PutChar (ACS_LTEE);
268344d93782SGreg Clayton                 window.PutChar (ACS_HLINE);
268444d93782SGreg Clayton             }
268544d93782SGreg Clayton             else
268644d93782SGreg Clayton             {
268744d93782SGreg Clayton                 window.PutChar (ACS_VLINE);
268844d93782SGreg Clayton                 window.PutChar (' ');
268944d93782SGreg Clayton             }
269044d93782SGreg Clayton         }
269144d93782SGreg Clayton     }
269244d93782SGreg Clayton 
269344d93782SGreg Clayton     TreeItem *
269444d93782SGreg Clayton     GetItemForRowIndex (uint32_t row_idx)
269544d93782SGreg Clayton     {
269644d93782SGreg Clayton         if (m_row_idx == row_idx)
269744d93782SGreg Clayton             return this;
269844d93782SGreg Clayton         if (m_children.empty())
269944d93782SGreg Clayton             return NULL;
270044d93782SGreg Clayton         if (m_children.back().m_row_idx < row_idx)
270144d93782SGreg Clayton             return NULL;
270244d93782SGreg Clayton         if (IsExpanded())
270344d93782SGreg Clayton         {
270444d93782SGreg Clayton             for (auto &item : m_children)
270544d93782SGreg Clayton             {
270644d93782SGreg Clayton                 TreeItem *selected_item_ptr = item.GetItemForRowIndex(row_idx);
270744d93782SGreg Clayton                 if (selected_item_ptr)
270844d93782SGreg Clayton                     return selected_item_ptr;
270944d93782SGreg Clayton             }
271044d93782SGreg Clayton         }
271144d93782SGreg Clayton         return NULL;
271244d93782SGreg Clayton     }
271344d93782SGreg Clayton 
271444d93782SGreg Clayton //    void *
271544d93782SGreg Clayton //    GetUserData() const
271644d93782SGreg Clayton //    {
271744d93782SGreg Clayton //        return m_user_data;
271844d93782SGreg Clayton //    }
271944d93782SGreg Clayton //
272044d93782SGreg Clayton //    void
272144d93782SGreg Clayton //    SetUserData (void *user_data)
272244d93782SGreg Clayton //    {
272344d93782SGreg Clayton //        m_user_data = user_data;
272444d93782SGreg Clayton //    }
272544d93782SGreg Clayton     uint64_t
272644d93782SGreg Clayton     GetIdentifier() const
272744d93782SGreg Clayton     {
272844d93782SGreg Clayton         return m_identifier;
272944d93782SGreg Clayton     }
273044d93782SGreg Clayton 
273144d93782SGreg Clayton     void
273244d93782SGreg Clayton     SetIdentifier (uint64_t identifier)
273344d93782SGreg Clayton     {
273444d93782SGreg Clayton         m_identifier = identifier;
273544d93782SGreg Clayton     }
273644d93782SGreg Clayton 
273744d93782SGreg Clayton 
273844d93782SGreg Clayton protected:
273944d93782SGreg Clayton     TreeItem *m_parent;
274044d93782SGreg Clayton     TreeDelegate &m_delegate;
274144d93782SGreg Clayton     //void *m_user_data;
274244d93782SGreg Clayton     uint64_t m_identifier;
274344d93782SGreg Clayton     int m_row_idx; // Zero based visible row index, -1 if not visible or for the root item
274444d93782SGreg Clayton     std::vector<TreeItem> m_children;
274544d93782SGreg Clayton     bool m_might_have_children;
274644d93782SGreg Clayton     bool m_is_expanded;
274744d93782SGreg Clayton 
274844d93782SGreg Clayton };
274944d93782SGreg Clayton 
275044d93782SGreg Clayton class TreeWindowDelegate : public WindowDelegate
275144d93782SGreg Clayton {
275244d93782SGreg Clayton public:
275344d93782SGreg Clayton     TreeWindowDelegate (Debugger &debugger, const TreeDelegateSP &delegate_sp) :
275444d93782SGreg Clayton         m_debugger (debugger),
275544d93782SGreg Clayton         m_delegate_sp (delegate_sp),
275644d93782SGreg Clayton         m_root (NULL, *delegate_sp, true),
275744d93782SGreg Clayton         m_selected_item (NULL),
275844d93782SGreg Clayton         m_num_rows (0),
275944d93782SGreg Clayton         m_selected_row_idx (0),
276044d93782SGreg Clayton         m_first_visible_row (0),
276144d93782SGreg Clayton         m_min_x (0),
276244d93782SGreg Clayton         m_min_y (0),
276344d93782SGreg Clayton         m_max_x (0),
276444d93782SGreg Clayton         m_max_y (0)
276544d93782SGreg Clayton     {
276644d93782SGreg Clayton     }
276744d93782SGreg Clayton 
276844d93782SGreg Clayton     int
276944d93782SGreg Clayton     NumVisibleRows () const
277044d93782SGreg Clayton     {
277144d93782SGreg Clayton         return m_max_y - m_min_y;
277244d93782SGreg Clayton     }
277344d93782SGreg Clayton 
277444d93782SGreg Clayton     virtual bool
277544d93782SGreg Clayton     WindowDelegateDraw (Window &window, bool force)
277644d93782SGreg Clayton     {
277744d93782SGreg Clayton         ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
277844d93782SGreg Clayton         Process *process = exe_ctx.GetProcessPtr();
277944d93782SGreg Clayton 
278044d93782SGreg Clayton         bool display_content = false;
278144d93782SGreg Clayton         if (process)
278244d93782SGreg Clayton         {
278344d93782SGreg Clayton             StateType state = process->GetState();
278444d93782SGreg Clayton             if (StateIsStoppedState(state, true))
278544d93782SGreg Clayton             {
278644d93782SGreg Clayton                 // We are stopped, so it is ok to
278744d93782SGreg Clayton                 display_content = true;
278844d93782SGreg Clayton             }
278944d93782SGreg Clayton             else if (StateIsRunningState(state))
279044d93782SGreg Clayton             {
279144d93782SGreg Clayton                 return true; // Don't do any updating when we are running
279244d93782SGreg Clayton             }
279344d93782SGreg Clayton         }
279444d93782SGreg Clayton 
279544d93782SGreg Clayton         m_min_x = 2;
279644d93782SGreg Clayton         m_min_y = 1;
279744d93782SGreg Clayton         m_max_x = window.GetWidth() - 1;
279844d93782SGreg Clayton         m_max_y = window.GetHeight() - 1;
279944d93782SGreg Clayton 
280044d93782SGreg Clayton         window.Erase();
280144d93782SGreg Clayton         window.DrawTitleBox (window.GetName());
280244d93782SGreg Clayton 
280344d93782SGreg Clayton         if (display_content)
280444d93782SGreg Clayton         {
280544d93782SGreg Clayton             const int num_visible_rows = NumVisibleRows();
280644d93782SGreg Clayton             m_num_rows = 0;
280744d93782SGreg Clayton             m_root.CalculateRowIndexes(m_num_rows);
280844d93782SGreg Clayton 
280944d93782SGreg Clayton             // If we unexpanded while having something selected our
281044d93782SGreg Clayton             // total number of rows is less than the num visible rows,
281144d93782SGreg Clayton             // then make sure we show all the rows by setting the first
281244d93782SGreg Clayton             // visible row accordingly.
281344d93782SGreg Clayton             if (m_first_visible_row > 0 && m_num_rows < num_visible_rows)
281444d93782SGreg Clayton                 m_first_visible_row = 0;
281544d93782SGreg Clayton 
281644d93782SGreg Clayton             // Make sure the selected row is always visible
281744d93782SGreg Clayton             if (m_selected_row_idx < m_first_visible_row)
281844d93782SGreg Clayton                 m_first_visible_row = m_selected_row_idx;
281944d93782SGreg Clayton             else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
282044d93782SGreg Clayton                 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
282144d93782SGreg Clayton 
282244d93782SGreg Clayton             int row_idx = 0;
282344d93782SGreg Clayton             int num_rows_left = num_visible_rows;
282444d93782SGreg Clayton             m_root.Draw (window, m_first_visible_row, m_selected_row_idx, row_idx, num_rows_left);
282544d93782SGreg Clayton             // Get the selected row
282644d93782SGreg Clayton             m_selected_item = m_root.GetItemForRowIndex (m_selected_row_idx);
282744d93782SGreg Clayton         }
282844d93782SGreg Clayton         else
282944d93782SGreg Clayton         {
283044d93782SGreg Clayton             m_selected_item = NULL;
283144d93782SGreg Clayton         }
283244d93782SGreg Clayton 
283344d93782SGreg Clayton         window.DeferredRefresh();
283444d93782SGreg Clayton 
283544d93782SGreg Clayton 
283644d93782SGreg Clayton         return true; // Drawing handled
283744d93782SGreg Clayton     }
283844d93782SGreg Clayton 
283944d93782SGreg Clayton 
284044d93782SGreg Clayton     virtual const char *
284144d93782SGreg Clayton     WindowDelegateGetHelpText ()
284244d93782SGreg Clayton     {
284344d93782SGreg Clayton         return "Thread window keyboard shortcuts:";
284444d93782SGreg Clayton     }
284544d93782SGreg Clayton 
284644d93782SGreg Clayton     virtual KeyHelp *
284744d93782SGreg Clayton     WindowDelegateGetKeyHelp ()
284844d93782SGreg Clayton     {
284944d93782SGreg Clayton         static curses::KeyHelp g_source_view_key_help[] = {
285044d93782SGreg Clayton             { KEY_UP, "Select previous item" },
285144d93782SGreg Clayton             { KEY_DOWN, "Select next item" },
285244d93782SGreg Clayton             { KEY_RIGHT, "Expand the selected item" },
285344d93782SGreg Clayton             { KEY_LEFT, "Unexpand the selected item or select parent if not expanded" },
285444d93782SGreg Clayton             { KEY_PPAGE, "Page up" },
285544d93782SGreg Clayton             { KEY_NPAGE, "Page down" },
285644d93782SGreg Clayton             { 'h', "Show help dialog" },
285744d93782SGreg Clayton             { ' ', "Toggle item expansion" },
285844d93782SGreg Clayton             { ',', "Page up" },
285944d93782SGreg Clayton             { '.', "Page down" },
286044d93782SGreg Clayton             { '\0', NULL }
286144d93782SGreg Clayton         };
286244d93782SGreg Clayton         return g_source_view_key_help;
286344d93782SGreg Clayton     }
286444d93782SGreg Clayton 
286544d93782SGreg Clayton     virtual HandleCharResult
286644d93782SGreg Clayton     WindowDelegateHandleChar (Window &window, int c)
286744d93782SGreg Clayton     {
286844d93782SGreg Clayton         switch(c)
286944d93782SGreg Clayton         {
287044d93782SGreg Clayton             case ',':
287144d93782SGreg Clayton             case KEY_PPAGE:
287244d93782SGreg Clayton                 // Page up key
287344d93782SGreg Clayton                 if (m_first_visible_row > 0)
287444d93782SGreg Clayton                 {
287544d93782SGreg Clayton                     if (m_first_visible_row > m_max_y)
287644d93782SGreg Clayton                         m_first_visible_row -= m_max_y;
287744d93782SGreg Clayton                     else
287844d93782SGreg Clayton                         m_first_visible_row = 0;
287944d93782SGreg Clayton                     m_selected_row_idx = m_first_visible_row;
288044d93782SGreg Clayton                     m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
288144d93782SGreg Clayton                     if (m_selected_item)
288244d93782SGreg Clayton                         m_selected_item->ItemWasSelected ();
288344d93782SGreg Clayton                 }
288444d93782SGreg Clayton                 return eKeyHandled;
288544d93782SGreg Clayton 
288644d93782SGreg Clayton             case '.':
288744d93782SGreg Clayton             case KEY_NPAGE:
288844d93782SGreg Clayton                 // Page down key
288944d93782SGreg Clayton                 if (m_num_rows > m_max_y)
289044d93782SGreg Clayton                 {
289144d93782SGreg Clayton                     if (m_first_visible_row + m_max_y < m_num_rows)
289244d93782SGreg Clayton                     {
289344d93782SGreg Clayton                         m_first_visible_row += m_max_y;
289444d93782SGreg Clayton                         m_selected_row_idx = m_first_visible_row;
289544d93782SGreg Clayton                         m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
289644d93782SGreg Clayton                         if (m_selected_item)
289744d93782SGreg Clayton                             m_selected_item->ItemWasSelected ();
289844d93782SGreg Clayton                     }
289944d93782SGreg Clayton                 }
290044d93782SGreg Clayton                 return eKeyHandled;
290144d93782SGreg Clayton 
290244d93782SGreg Clayton             case KEY_UP:
290344d93782SGreg Clayton                 if (m_selected_row_idx > 0)
290444d93782SGreg Clayton                 {
290544d93782SGreg Clayton                     --m_selected_row_idx;
290644d93782SGreg Clayton                     m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
290744d93782SGreg Clayton                     if (m_selected_item)
290844d93782SGreg Clayton                         m_selected_item->ItemWasSelected ();
290944d93782SGreg Clayton                 }
291044d93782SGreg Clayton                 return eKeyHandled;
291144d93782SGreg Clayton             case KEY_DOWN:
291244d93782SGreg Clayton                 if (m_selected_row_idx + 1 < m_num_rows)
291344d93782SGreg Clayton                 {
291444d93782SGreg Clayton                     ++m_selected_row_idx;
291544d93782SGreg Clayton                     m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
291644d93782SGreg Clayton                     if (m_selected_item)
291744d93782SGreg Clayton                         m_selected_item->ItemWasSelected ();
291844d93782SGreg Clayton                 }
291944d93782SGreg Clayton                 return eKeyHandled;
292044d93782SGreg Clayton 
292144d93782SGreg Clayton             case KEY_RIGHT:
292244d93782SGreg Clayton                 if (m_selected_item)
292344d93782SGreg Clayton                 {
292444d93782SGreg Clayton                     if (!m_selected_item->IsExpanded())
292544d93782SGreg Clayton                         m_selected_item->Expand();
292644d93782SGreg Clayton                 }
292744d93782SGreg Clayton                 return eKeyHandled;
292844d93782SGreg Clayton 
292944d93782SGreg Clayton             case KEY_LEFT:
293044d93782SGreg Clayton                 if (m_selected_item)
293144d93782SGreg Clayton                 {
293244d93782SGreg Clayton                     if (m_selected_item->IsExpanded())
293344d93782SGreg Clayton                         m_selected_item->Unexpand();
293444d93782SGreg Clayton                     else if (m_selected_item->GetParent())
293544d93782SGreg Clayton                     {
293644d93782SGreg Clayton                         m_selected_row_idx = m_selected_item->GetParent()->GetRowIndex();
293744d93782SGreg Clayton                         m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
293844d93782SGreg Clayton                         if (m_selected_item)
293944d93782SGreg Clayton                             m_selected_item->ItemWasSelected ();
294044d93782SGreg Clayton                     }
294144d93782SGreg Clayton                 }
294244d93782SGreg Clayton                 return eKeyHandled;
294344d93782SGreg Clayton 
294444d93782SGreg Clayton             case ' ':
294544d93782SGreg Clayton                 // Toggle expansion state when SPACE is pressed
294644d93782SGreg Clayton                 if (m_selected_item)
294744d93782SGreg Clayton                 {
294844d93782SGreg Clayton                     if (m_selected_item->IsExpanded())
294944d93782SGreg Clayton                         m_selected_item->Unexpand();
295044d93782SGreg Clayton                     else
295144d93782SGreg Clayton                         m_selected_item->Expand();
295244d93782SGreg Clayton                 }
295344d93782SGreg Clayton                 return eKeyHandled;
295444d93782SGreg Clayton 
295544d93782SGreg Clayton             case 'h':
295644d93782SGreg Clayton                 window.CreateHelpSubwindow ();
295744d93782SGreg Clayton                 return eKeyHandled;
295844d93782SGreg Clayton 
295944d93782SGreg Clayton             default:
296044d93782SGreg Clayton                 break;
296144d93782SGreg Clayton         }
296244d93782SGreg Clayton         return eKeyNotHandled;
296344d93782SGreg Clayton     }
296444d93782SGreg Clayton 
296544d93782SGreg Clayton protected:
296644d93782SGreg Clayton     Debugger &m_debugger;
296744d93782SGreg Clayton     TreeDelegateSP m_delegate_sp;
296844d93782SGreg Clayton     TreeItem m_root;
296944d93782SGreg Clayton     TreeItem *m_selected_item;
297044d93782SGreg Clayton     int m_num_rows;
297144d93782SGreg Clayton     int m_selected_row_idx;
297244d93782SGreg Clayton     int m_first_visible_row;
297344d93782SGreg Clayton     int m_min_x;
297444d93782SGreg Clayton     int m_min_y;
297544d93782SGreg Clayton     int m_max_x;
297644d93782SGreg Clayton     int m_max_y;
297744d93782SGreg Clayton 
297844d93782SGreg Clayton };
297944d93782SGreg Clayton 
298044d93782SGreg Clayton class FrameTreeDelegate : public TreeDelegate
298144d93782SGreg Clayton {
298244d93782SGreg Clayton public:
298344d93782SGreg Clayton     FrameTreeDelegate (const ThreadSP &thread_sp) :
298444d93782SGreg Clayton         TreeDelegate(),
298544d93782SGreg Clayton         m_thread_wp()
298644d93782SGreg Clayton     {
298744d93782SGreg Clayton         if (thread_sp)
298844d93782SGreg Clayton             m_thread_wp = thread_sp;
298944d93782SGreg Clayton     }
299044d93782SGreg Clayton 
299144d93782SGreg Clayton     virtual ~FrameTreeDelegate()
299244d93782SGreg Clayton     {
299344d93782SGreg Clayton     }
299444d93782SGreg Clayton 
299544d93782SGreg Clayton     virtual void
299644d93782SGreg Clayton     TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
299744d93782SGreg Clayton     {
299844d93782SGreg Clayton         ThreadSP thread_sp = m_thread_wp.lock();
299944d93782SGreg Clayton         if (thread_sp)
300044d93782SGreg Clayton         {
300144d93782SGreg Clayton             const uint64_t frame_idx = item.GetIdentifier();
300244d93782SGreg Clayton             StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(frame_idx);
300344d93782SGreg Clayton             if (frame_sp)
300444d93782SGreg Clayton             {
300544d93782SGreg Clayton                 StreamString strm;
300644d93782SGreg Clayton                 const SymbolContext &sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
300744d93782SGreg Clayton                 ExecutionContext exe_ctx (frame_sp);
300844d93782SGreg Clayton                 //const char *frame_format = "frame #${frame.index}: ${module.file.basename}{`${function.name}${function.pc-offset}}}";
300944d93782SGreg Clayton                 const char *frame_format = "frame #${frame.index}: {${function.name}${function.pc-offset}}}";
301044d93782SGreg Clayton                 if (Debugger::FormatPrompt (frame_format, &sc, &exe_ctx, NULL, strm))
301144d93782SGreg Clayton                 {
301244d93782SGreg Clayton                     int right_pad = 1;
301344d93782SGreg Clayton                     window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
301444d93782SGreg Clayton                 }
301544d93782SGreg Clayton             }
301644d93782SGreg Clayton         }
301744d93782SGreg Clayton     }
301844d93782SGreg Clayton     virtual void
301944d93782SGreg Clayton     TreeDelegateGenerateChildren (TreeItem &item)
302044d93782SGreg Clayton     {
302144d93782SGreg Clayton         // No children for frames yet...
302244d93782SGreg Clayton     }
302344d93782SGreg Clayton 
302444d93782SGreg Clayton     virtual bool
302544d93782SGreg Clayton     TreeDelegateItemSelected (TreeItem &item)
302644d93782SGreg Clayton     {
302744d93782SGreg Clayton         ThreadSP thread_sp = m_thread_wp.lock();
302844d93782SGreg Clayton         if (thread_sp)
302944d93782SGreg Clayton         {
303044d93782SGreg Clayton             const uint64_t frame_idx = item.GetIdentifier();
303144d93782SGreg Clayton             thread_sp->SetSelectedFrameByIndex(frame_idx);
303244d93782SGreg Clayton             return true;
303344d93782SGreg Clayton         }
303444d93782SGreg Clayton         return false;
303544d93782SGreg Clayton     }
303644d93782SGreg Clayton     void
303744d93782SGreg Clayton     SetThread (ThreadSP thread_sp)
303844d93782SGreg Clayton     {
303944d93782SGreg Clayton         m_thread_wp = thread_sp;
304044d93782SGreg Clayton     }
304144d93782SGreg Clayton 
304244d93782SGreg Clayton protected:
304344d93782SGreg Clayton     ThreadWP m_thread_wp;
304444d93782SGreg Clayton };
304544d93782SGreg Clayton 
304644d93782SGreg Clayton class ThreadTreeDelegate : public TreeDelegate
304744d93782SGreg Clayton {
304844d93782SGreg Clayton public:
304944d93782SGreg Clayton     ThreadTreeDelegate (Debugger &debugger) :
305044d93782SGreg Clayton         TreeDelegate(),
305144d93782SGreg Clayton         m_debugger (debugger),
305244d93782SGreg Clayton         m_thread_wp (),
305344d93782SGreg Clayton         m_tid (LLDB_INVALID_THREAD_ID),
305444d93782SGreg Clayton         m_stop_id (UINT32_MAX)
305544d93782SGreg Clayton     {
305644d93782SGreg Clayton     }
305744d93782SGreg Clayton 
305844d93782SGreg Clayton     virtual
305944d93782SGreg Clayton     ~ThreadTreeDelegate()
306044d93782SGreg Clayton     {
306144d93782SGreg Clayton     }
306244d93782SGreg Clayton 
306344d93782SGreg Clayton     virtual void
306444d93782SGreg Clayton     TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
306544d93782SGreg Clayton     {
306644d93782SGreg Clayton         ThreadSP thread_sp = m_thread_wp.lock();
306744d93782SGreg Clayton         if (thread_sp)
306844d93782SGreg Clayton         {
306944d93782SGreg Clayton             StreamString strm;
307044d93782SGreg Clayton             ExecutionContext exe_ctx (thread_sp);
307144d93782SGreg Clayton             const char *format = "thread #${thread.index}: tid = ${thread.id}{, stop reason = ${thread.stop-reason}}";
307244d93782SGreg Clayton             if (Debugger::FormatPrompt (format, NULL, &exe_ctx, NULL, strm))
307344d93782SGreg Clayton             {
307444d93782SGreg Clayton                 int right_pad = 1;
307544d93782SGreg Clayton                 window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
307644d93782SGreg Clayton             }
307744d93782SGreg Clayton         }
307844d93782SGreg Clayton     }
307944d93782SGreg Clayton     virtual void
308044d93782SGreg Clayton     TreeDelegateGenerateChildren (TreeItem &item)
308144d93782SGreg Clayton     {
308244d93782SGreg Clayton         TargetSP target_sp (m_debugger.GetSelectedTarget());
308344d93782SGreg Clayton         if (target_sp)
308444d93782SGreg Clayton         {
308544d93782SGreg Clayton             ProcessSP process_sp = target_sp->GetProcessSP();
308644d93782SGreg Clayton             if (process_sp && process_sp->IsAlive())
308744d93782SGreg Clayton             {
308844d93782SGreg Clayton                 StateType state = process_sp->GetState();
308944d93782SGreg Clayton                 if (StateIsStoppedState(state, true))
309044d93782SGreg Clayton                 {
309144d93782SGreg Clayton                     ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread();
309244d93782SGreg Clayton                     if (thread_sp)
309344d93782SGreg Clayton                     {
309444d93782SGreg Clayton                         if (m_stop_id == process_sp->GetStopID() && thread_sp->GetID() == m_tid)
309544d93782SGreg Clayton                             return; // Children are already up to date
309644d93782SGreg Clayton                         if (m_frame_delegate_sp)
309744d93782SGreg Clayton                             m_frame_delegate_sp->SetThread(thread_sp);
309844d93782SGreg Clayton                         else
309944d93782SGreg Clayton                         {
310044d93782SGreg Clayton                             // Always expand the thread item the first time we show it
310144d93782SGreg Clayton                             item.Expand();
310244d93782SGreg Clayton                             m_frame_delegate_sp.reset (new FrameTreeDelegate(thread_sp));
310344d93782SGreg Clayton                         }
310444d93782SGreg Clayton 
310544d93782SGreg Clayton                         m_stop_id = process_sp->GetStopID();
310644d93782SGreg Clayton                         m_thread_wp = thread_sp;
310744d93782SGreg Clayton                         m_tid = thread_sp->GetID();
310844d93782SGreg Clayton 
310944d93782SGreg Clayton                         TreeItem t (&item, *m_frame_delegate_sp, false);
311044d93782SGreg Clayton                         size_t num_frames = thread_sp->GetStackFrameCount();
311144d93782SGreg Clayton                         item.Resize (num_frames, t);
311244d93782SGreg Clayton                         for (size_t i=0; i<num_frames; ++i)
311344d93782SGreg Clayton                         {
311444d93782SGreg Clayton                             item[i].SetIdentifier(i);
311544d93782SGreg Clayton                         }
311644d93782SGreg Clayton                     }
311744d93782SGreg Clayton                     return;
311844d93782SGreg Clayton                 }
311944d93782SGreg Clayton             }
312044d93782SGreg Clayton         }
312144d93782SGreg Clayton         item.ClearChildren();
312244d93782SGreg Clayton     }
312344d93782SGreg Clayton 
312444d93782SGreg Clayton     virtual bool
312544d93782SGreg Clayton     TreeDelegateItemSelected (TreeItem &item)
312644d93782SGreg Clayton     {
312744d93782SGreg Clayton         ThreadSP thread_sp = m_thread_wp.lock();
312844d93782SGreg Clayton         if (thread_sp)
312944d93782SGreg Clayton         {
313044d93782SGreg Clayton             ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
313144d93782SGreg Clayton             Mutex::Locker locker (thread_list.GetMutex());
313244d93782SGreg Clayton             ThreadSP selected_thread_sp = thread_list.GetSelectedThread();
313344d93782SGreg Clayton             if (selected_thread_sp->GetID() != thread_sp->GetID())
313444d93782SGreg Clayton             {
313544d93782SGreg Clayton                 thread_list.SetSelectedThreadByID(thread_sp->GetID());
313644d93782SGreg Clayton                 return true;
313744d93782SGreg Clayton             }
313844d93782SGreg Clayton         }
313944d93782SGreg Clayton         return false;
314044d93782SGreg Clayton     }
314144d93782SGreg Clayton 
314244d93782SGreg Clayton protected:
314344d93782SGreg Clayton     Debugger &m_debugger;
314444d93782SGreg Clayton     ThreadWP m_thread_wp;
314544d93782SGreg Clayton     std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp;
314644d93782SGreg Clayton     lldb::user_id_t m_tid;
314744d93782SGreg Clayton     uint32_t m_stop_id;
314844d93782SGreg Clayton };
314944d93782SGreg Clayton 
315044d93782SGreg Clayton class ValueObjectListDelegate : public WindowDelegate
315144d93782SGreg Clayton {
315244d93782SGreg Clayton public:
315344d93782SGreg Clayton     ValueObjectListDelegate () :
315444d93782SGreg Clayton         m_valobj_list (),
315544d93782SGreg Clayton         m_rows (),
315644d93782SGreg Clayton         m_selected_row (NULL),
315744d93782SGreg Clayton         m_selected_row_idx (0),
315844d93782SGreg Clayton         m_first_visible_row (0),
315944d93782SGreg Clayton         m_num_rows (0),
316044d93782SGreg Clayton         m_max_x (0),
316144d93782SGreg Clayton         m_max_y (0)
316244d93782SGreg Clayton     {
316344d93782SGreg Clayton     }
316444d93782SGreg Clayton 
316544d93782SGreg Clayton     ValueObjectListDelegate (ValueObjectList &valobj_list) :
316644d93782SGreg Clayton         m_valobj_list (valobj_list),
316744d93782SGreg Clayton         m_rows (),
316844d93782SGreg Clayton         m_selected_row (NULL),
316944d93782SGreg Clayton         m_selected_row_idx (0),
317044d93782SGreg Clayton         m_first_visible_row (0),
317144d93782SGreg Clayton         m_num_rows (0),
317244d93782SGreg Clayton         m_max_x (0),
317344d93782SGreg Clayton         m_max_y (0)
317444d93782SGreg Clayton     {
317544d93782SGreg Clayton         SetValues (valobj_list);
317644d93782SGreg Clayton     }
317744d93782SGreg Clayton 
317844d93782SGreg Clayton     virtual
317944d93782SGreg Clayton     ~ValueObjectListDelegate()
318044d93782SGreg Clayton     {
318144d93782SGreg Clayton     }
318244d93782SGreg Clayton 
318344d93782SGreg Clayton     void
318444d93782SGreg Clayton     SetValues (ValueObjectList &valobj_list)
318544d93782SGreg Clayton     {
318644d93782SGreg Clayton         m_selected_row = NULL;
318744d93782SGreg Clayton         m_selected_row_idx = 0;
318844d93782SGreg Clayton         m_first_visible_row = 0;
318944d93782SGreg Clayton         m_num_rows = 0;
319044d93782SGreg Clayton         m_rows.clear();
319144d93782SGreg Clayton         m_valobj_list = valobj_list;
319244d93782SGreg Clayton         const size_t num_values = m_valobj_list.GetSize();
319344d93782SGreg Clayton         for (size_t i=0; i<num_values; ++i)
319444d93782SGreg Clayton             m_rows.push_back(Row(m_valobj_list.GetValueObjectAtIndex(i), NULL));
319544d93782SGreg Clayton     }
319644d93782SGreg Clayton 
319744d93782SGreg Clayton     virtual bool
319844d93782SGreg Clayton     WindowDelegateDraw (Window &window, bool force)
319944d93782SGreg Clayton     {
320044d93782SGreg Clayton         m_num_rows = 0;
320144d93782SGreg Clayton         m_min_x = 2;
320244d93782SGreg Clayton         m_min_y = 1;
320344d93782SGreg Clayton         m_max_x = window.GetWidth() - 1;
320444d93782SGreg Clayton         m_max_y = window.GetHeight() - 1;
320544d93782SGreg Clayton 
320644d93782SGreg Clayton         window.Erase();
320744d93782SGreg Clayton         window.DrawTitleBox (window.GetName());
320844d93782SGreg Clayton 
320944d93782SGreg Clayton         const int num_visible_rows = NumVisibleRows();
321044d93782SGreg Clayton         const int num_rows = CalculateTotalNumberRows (m_rows);
321144d93782SGreg Clayton 
321244d93782SGreg Clayton         // If we unexpanded while having something selected our
321344d93782SGreg Clayton         // total number of rows is less than the num visible rows,
321444d93782SGreg Clayton         // then make sure we show all the rows by setting the first
321544d93782SGreg Clayton         // visible row accordingly.
321644d93782SGreg Clayton         if (m_first_visible_row > 0 && num_rows < num_visible_rows)
321744d93782SGreg Clayton             m_first_visible_row = 0;
321844d93782SGreg Clayton 
321944d93782SGreg Clayton         // Make sure the selected row is always visible
322044d93782SGreg Clayton         if (m_selected_row_idx < m_first_visible_row)
322144d93782SGreg Clayton             m_first_visible_row = m_selected_row_idx;
322244d93782SGreg Clayton         else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
322344d93782SGreg Clayton             m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
322444d93782SGreg Clayton 
322544d93782SGreg Clayton         DisplayRows (window, m_rows, g_options);
322644d93782SGreg Clayton 
322744d93782SGreg Clayton         window.DeferredRefresh();
322844d93782SGreg Clayton 
322944d93782SGreg Clayton         // Get the selected row
323044d93782SGreg Clayton         m_selected_row = GetRowForRowIndex (m_selected_row_idx);
323144d93782SGreg Clayton         // Keep the cursor on the selected row so the highlight and the cursor
323244d93782SGreg Clayton         // are always on the same line
323344d93782SGreg Clayton         if (m_selected_row)
323444d93782SGreg Clayton             window.MoveCursor (m_selected_row->x,
323544d93782SGreg Clayton                                m_selected_row->y);
323644d93782SGreg Clayton 
323744d93782SGreg Clayton         return true; // Drawing handled
323844d93782SGreg Clayton     }
323944d93782SGreg Clayton 
324044d93782SGreg Clayton     virtual KeyHelp *
324144d93782SGreg Clayton     WindowDelegateGetKeyHelp ()
324244d93782SGreg Clayton     {
324344d93782SGreg Clayton         static curses::KeyHelp g_source_view_key_help[] = {
324444d93782SGreg Clayton             { KEY_UP, "Select previous item" },
324544d93782SGreg Clayton             { KEY_DOWN, "Select next item" },
324644d93782SGreg Clayton             { KEY_RIGHT, "Expand selected item" },
324744d93782SGreg Clayton             { KEY_LEFT, "Unexpand selected item or select parent if not expanded" },
324844d93782SGreg Clayton             { KEY_PPAGE, "Page up" },
324944d93782SGreg Clayton             { KEY_NPAGE, "Page down" },
325044d93782SGreg Clayton             { 'A', "Format as annotated address" },
325144d93782SGreg Clayton             { 'b', "Format as binary" },
325244d93782SGreg Clayton             { 'B', "Format as hex bytes with ASCII" },
325344d93782SGreg Clayton             { 'c', "Format as character" },
325444d93782SGreg Clayton             { 'd', "Format as a signed integer" },
325544d93782SGreg Clayton             { 'D', "Format selected value using the default format for the type" },
325644d93782SGreg Clayton             { 'f', "Format as float" },
325744d93782SGreg Clayton             { 'h', "Show help dialog" },
325844d93782SGreg Clayton             { 'i', "Format as instructions" },
325944d93782SGreg Clayton             { 'o', "Format as octal" },
326044d93782SGreg Clayton             { 'p', "Format as pointer" },
326144d93782SGreg Clayton             { 's', "Format as C string" },
326244d93782SGreg Clayton             { 't', "Toggle showing/hiding type names" },
326344d93782SGreg Clayton             { 'u', "Format as an unsigned integer" },
326444d93782SGreg Clayton             { 'x', "Format as hex" },
326544d93782SGreg Clayton             { 'X', "Format as uppercase hex" },
326644d93782SGreg Clayton             { ' ', "Toggle item expansion" },
326744d93782SGreg Clayton             { ',', "Page up" },
326844d93782SGreg Clayton             { '.', "Page down" },
326944d93782SGreg Clayton             { '\0', NULL }
327044d93782SGreg Clayton         };
327144d93782SGreg Clayton         return g_source_view_key_help;
327244d93782SGreg Clayton     }
327344d93782SGreg Clayton 
327444d93782SGreg Clayton 
327544d93782SGreg Clayton     virtual HandleCharResult
327644d93782SGreg Clayton     WindowDelegateHandleChar (Window &window, int c)
327744d93782SGreg Clayton     {
327844d93782SGreg Clayton         switch(c)
327944d93782SGreg Clayton         {
328044d93782SGreg Clayton             case 'x':
328144d93782SGreg Clayton             case 'X':
328244d93782SGreg Clayton             case 'o':
328344d93782SGreg Clayton             case 's':
328444d93782SGreg Clayton             case 'u':
328544d93782SGreg Clayton             case 'd':
328644d93782SGreg Clayton             case 'D':
328744d93782SGreg Clayton             case 'i':
328844d93782SGreg Clayton             case 'A':
328944d93782SGreg Clayton             case 'p':
329044d93782SGreg Clayton             case 'c':
329144d93782SGreg Clayton             case 'b':
329244d93782SGreg Clayton             case 'B':
329344d93782SGreg Clayton             case 'f':
329444d93782SGreg Clayton                 // Change the format for the currently selected item
329544d93782SGreg Clayton                 if (m_selected_row)
329644d93782SGreg Clayton                     m_selected_row->valobj->SetFormat (FormatForChar (c));
329744d93782SGreg Clayton                 return eKeyHandled;
329844d93782SGreg Clayton 
329944d93782SGreg Clayton             case 't':
330044d93782SGreg Clayton                 // Toggle showing type names
330144d93782SGreg Clayton                 g_options.show_types = !g_options.show_types;
330244d93782SGreg Clayton                 return eKeyHandled;
330344d93782SGreg Clayton 
330444d93782SGreg Clayton             case ',':
330544d93782SGreg Clayton             case KEY_PPAGE:
330644d93782SGreg Clayton                 // Page up key
330744d93782SGreg Clayton                 if (m_first_visible_row > 0)
330844d93782SGreg Clayton                 {
330944d93782SGreg Clayton                     if (m_first_visible_row > m_max_y)
331044d93782SGreg Clayton                         m_first_visible_row -= m_max_y;
331144d93782SGreg Clayton                     else
331244d93782SGreg Clayton                         m_first_visible_row = 0;
331344d93782SGreg Clayton                     m_selected_row_idx = m_first_visible_row;
331444d93782SGreg Clayton                 }
331544d93782SGreg Clayton                 return eKeyHandled;
331644d93782SGreg Clayton 
331744d93782SGreg Clayton             case '.':
331844d93782SGreg Clayton             case KEY_NPAGE:
331944d93782SGreg Clayton                 // Page down key
332044d93782SGreg Clayton                 if (m_num_rows > m_max_y)
332144d93782SGreg Clayton                 {
332244d93782SGreg Clayton                     if (m_first_visible_row + m_max_y < m_num_rows)
332344d93782SGreg Clayton                     {
332444d93782SGreg Clayton                         m_first_visible_row += m_max_y;
332544d93782SGreg Clayton                         m_selected_row_idx = m_first_visible_row;
332644d93782SGreg Clayton                     }
332744d93782SGreg Clayton                 }
332844d93782SGreg Clayton                 return eKeyHandled;
332944d93782SGreg Clayton 
333044d93782SGreg Clayton             case KEY_UP:
333144d93782SGreg Clayton                 if (m_selected_row_idx > 0)
333244d93782SGreg Clayton                     --m_selected_row_idx;
333344d93782SGreg Clayton                 return eKeyHandled;
333444d93782SGreg Clayton             case KEY_DOWN:
333544d93782SGreg Clayton                 if (m_selected_row_idx + 1 < m_num_rows)
333644d93782SGreg Clayton                     ++m_selected_row_idx;
333744d93782SGreg Clayton                 return eKeyHandled;
333844d93782SGreg Clayton 
333944d93782SGreg Clayton             case KEY_RIGHT:
334044d93782SGreg Clayton                 if (m_selected_row)
334144d93782SGreg Clayton                 {
334244d93782SGreg Clayton                     if (!m_selected_row->expanded)
334344d93782SGreg Clayton                         m_selected_row->Expand();
334444d93782SGreg Clayton                 }
334544d93782SGreg Clayton                 return eKeyHandled;
334644d93782SGreg Clayton 
334744d93782SGreg Clayton             case KEY_LEFT:
334844d93782SGreg Clayton                 if (m_selected_row)
334944d93782SGreg Clayton                 {
335044d93782SGreg Clayton                     if (m_selected_row->expanded)
335144d93782SGreg Clayton                         m_selected_row->Unexpand();
335244d93782SGreg Clayton                     else if (m_selected_row->parent)
335344d93782SGreg Clayton                         m_selected_row_idx = m_selected_row->parent->row_idx;
335444d93782SGreg Clayton                 }
335544d93782SGreg Clayton                 return eKeyHandled;
335644d93782SGreg Clayton 
335744d93782SGreg Clayton             case ' ':
335844d93782SGreg Clayton                 // Toggle expansion state when SPACE is pressed
335944d93782SGreg Clayton                 if (m_selected_row)
336044d93782SGreg Clayton                 {
336144d93782SGreg Clayton                     if (m_selected_row->expanded)
336244d93782SGreg Clayton                         m_selected_row->Unexpand();
336344d93782SGreg Clayton                     else
336444d93782SGreg Clayton                         m_selected_row->Expand();
336544d93782SGreg Clayton                 }
336644d93782SGreg Clayton                 return eKeyHandled;
336744d93782SGreg Clayton 
336844d93782SGreg Clayton             case 'h':
336944d93782SGreg Clayton                 window.CreateHelpSubwindow ();
337044d93782SGreg Clayton                 return eKeyHandled;
337144d93782SGreg Clayton 
337244d93782SGreg Clayton             default:
337344d93782SGreg Clayton                 break;
337444d93782SGreg Clayton         }
337544d93782SGreg Clayton         return eKeyNotHandled;
337644d93782SGreg Clayton     }
337744d93782SGreg Clayton 
337844d93782SGreg Clayton protected:
337944d93782SGreg Clayton     ValueObjectList m_valobj_list;
338044d93782SGreg Clayton     std::vector<Row> m_rows;
338144d93782SGreg Clayton     Row *m_selected_row;
338244d93782SGreg Clayton     uint32_t m_selected_row_idx;
338344d93782SGreg Clayton     uint32_t m_first_visible_row;
338444d93782SGreg Clayton     uint32_t m_num_rows;
338544d93782SGreg Clayton     int m_min_x;
338644d93782SGreg Clayton     int m_min_y;
338744d93782SGreg Clayton     int m_max_x;
338844d93782SGreg Clayton     int m_max_y;
338944d93782SGreg Clayton 
339044d93782SGreg Clayton     static Format
339144d93782SGreg Clayton     FormatForChar (int c)
339244d93782SGreg Clayton     {
339344d93782SGreg Clayton         switch (c)
339444d93782SGreg Clayton         {
339544d93782SGreg Clayton             case 'x': return eFormatHex;
339644d93782SGreg Clayton             case 'X': return eFormatHexUppercase;
339744d93782SGreg Clayton             case 'o': return eFormatOctal;
339844d93782SGreg Clayton             case 's': return eFormatCString;
339944d93782SGreg Clayton             case 'u': return eFormatUnsigned;
340044d93782SGreg Clayton             case 'd': return eFormatDecimal;
340144d93782SGreg Clayton             case 'D': return eFormatDefault;
340244d93782SGreg Clayton             case 'i': return eFormatInstruction;
340344d93782SGreg Clayton             case 'A': return eFormatAddressInfo;
340444d93782SGreg Clayton             case 'p': return eFormatPointer;
340544d93782SGreg Clayton             case 'c': return eFormatChar;
340644d93782SGreg Clayton             case 'b': return eFormatBinary;
340744d93782SGreg Clayton             case 'B': return eFormatBytesWithASCII;
340844d93782SGreg Clayton             case 'f': return eFormatFloat;
340944d93782SGreg Clayton         }
341044d93782SGreg Clayton         return eFormatDefault;
341144d93782SGreg Clayton     }
341244d93782SGreg Clayton 
341344d93782SGreg Clayton     bool
341444d93782SGreg Clayton     DisplayRowObject (Window &window,
341544d93782SGreg Clayton                       Row &row,
341644d93782SGreg Clayton                       DisplayOptions &options,
341744d93782SGreg Clayton                       bool highlight,
341844d93782SGreg Clayton                       bool last_child)
341944d93782SGreg Clayton     {
342044d93782SGreg Clayton         ValueObject *valobj = row.valobj.get();
342144d93782SGreg Clayton 
342244d93782SGreg Clayton         if (valobj == NULL)
342344d93782SGreg Clayton             return false;
342444d93782SGreg Clayton 
342544d93782SGreg Clayton         const char *type_name = options.show_types ? valobj->GetTypeName().GetCString() : NULL;
342644d93782SGreg Clayton         const char *name = valobj->GetName().GetCString();
342744d93782SGreg Clayton         const char *value = valobj->GetValueAsCString ();
342844d93782SGreg Clayton         const char *summary = valobj->GetSummaryAsCString ();
342944d93782SGreg Clayton 
343044d93782SGreg Clayton         window.MoveCursor (row.x, row.y);
343144d93782SGreg Clayton 
343244d93782SGreg Clayton         row.DrawTree (window);
343344d93782SGreg Clayton 
343444d93782SGreg Clayton         if (highlight)
343544d93782SGreg Clayton             window.AttributeOn(A_REVERSE);
343644d93782SGreg Clayton 
343744d93782SGreg Clayton         if (type_name && type_name[0])
343844d93782SGreg Clayton             window.Printf ("(%s) ", type_name);
343944d93782SGreg Clayton 
344044d93782SGreg Clayton         if (name && name[0])
344144d93782SGreg Clayton             window.PutCString(name);
344244d93782SGreg Clayton 
344344d93782SGreg Clayton         attr_t changd_attr = 0;
344444d93782SGreg Clayton         if (valobj->GetValueDidChange())
344544d93782SGreg Clayton             changd_attr = COLOR_PAIR(5) | A_BOLD;
344644d93782SGreg Clayton 
344744d93782SGreg Clayton         if (value && value[0])
344844d93782SGreg Clayton         {
344944d93782SGreg Clayton             window.PutCString(" = ");
345044d93782SGreg Clayton             if (changd_attr)
345144d93782SGreg Clayton                 window.AttributeOn(changd_attr);
345244d93782SGreg Clayton             window.PutCString (value);
345344d93782SGreg Clayton             if (changd_attr)
345444d93782SGreg Clayton                 window.AttributeOff(changd_attr);
345544d93782SGreg Clayton         }
345644d93782SGreg Clayton 
345744d93782SGreg Clayton         if (summary && summary[0])
345844d93782SGreg Clayton         {
345944d93782SGreg Clayton             window.PutChar(' ');
346044d93782SGreg Clayton             if (changd_attr)
346144d93782SGreg Clayton                 window.AttributeOn(changd_attr);
346244d93782SGreg Clayton             window.PutCString(summary);
346344d93782SGreg Clayton             if (changd_attr)
346444d93782SGreg Clayton                 window.AttributeOff(changd_attr);
346544d93782SGreg Clayton         }
346644d93782SGreg Clayton 
346744d93782SGreg Clayton         if (highlight)
346844d93782SGreg Clayton             window.AttributeOff (A_REVERSE);
346944d93782SGreg Clayton 
347044d93782SGreg Clayton         return true;
347144d93782SGreg Clayton     }
347244d93782SGreg Clayton     void
347344d93782SGreg Clayton     DisplayRows (Window &window,
347444d93782SGreg Clayton                  std::vector<Row> &rows,
347544d93782SGreg Clayton                  DisplayOptions &options)
347644d93782SGreg Clayton     {
347744d93782SGreg Clayton         // >   0x25B7
347844d93782SGreg Clayton         // \/  0x25BD
347944d93782SGreg Clayton 
348044d93782SGreg Clayton         bool window_is_active = window.IsActive();
348144d93782SGreg Clayton         for (auto &row : rows)
348244d93782SGreg Clayton         {
348344d93782SGreg Clayton             const bool last_child = row.parent && &rows[rows.size()-1] == &row;
348444d93782SGreg Clayton             // Save the row index in each Row structure
348544d93782SGreg Clayton             row.row_idx = m_num_rows;
348644d93782SGreg Clayton             if ((m_num_rows >= m_first_visible_row) &&
348744d93782SGreg Clayton                 ((m_num_rows - m_first_visible_row) < NumVisibleRows()))
348844d93782SGreg Clayton             {
348944d93782SGreg Clayton                 row.x = m_min_x;
349044d93782SGreg Clayton                 row.y = m_num_rows - m_first_visible_row + 1;
349144d93782SGreg Clayton                 if (DisplayRowObject (window,
349244d93782SGreg Clayton                                       row,
349344d93782SGreg Clayton                                       options,
349444d93782SGreg Clayton                                       window_is_active && m_num_rows == m_selected_row_idx,
349544d93782SGreg Clayton                                       last_child))
349644d93782SGreg Clayton                 {
349744d93782SGreg Clayton                     ++m_num_rows;
349844d93782SGreg Clayton                 }
349944d93782SGreg Clayton                 else
350044d93782SGreg Clayton                 {
350144d93782SGreg Clayton                     row.x = 0;
350244d93782SGreg Clayton                     row.y = 0;
350344d93782SGreg Clayton                 }
350444d93782SGreg Clayton             }
350544d93782SGreg Clayton             else
350644d93782SGreg Clayton             {
350744d93782SGreg Clayton                 row.x = 0;
350844d93782SGreg Clayton                 row.y = 0;
350944d93782SGreg Clayton                 ++m_num_rows;
351044d93782SGreg Clayton             }
351144d93782SGreg Clayton 
351244d93782SGreg Clayton             if (row.expanded && !row.children.empty())
351344d93782SGreg Clayton             {
351444d93782SGreg Clayton                 DisplayRows (window,
351544d93782SGreg Clayton                              row.children,
351644d93782SGreg Clayton                              options);
351744d93782SGreg Clayton             }
351844d93782SGreg Clayton         }
351944d93782SGreg Clayton     }
352044d93782SGreg Clayton 
352144d93782SGreg Clayton     int
352244d93782SGreg Clayton     CalculateTotalNumberRows (const std::vector<Row> &rows)
352344d93782SGreg Clayton     {
352444d93782SGreg Clayton         int row_count = 0;
352544d93782SGreg Clayton         for (const auto &row : rows)
352644d93782SGreg Clayton         {
352744d93782SGreg Clayton             ++row_count;
352844d93782SGreg Clayton             if (row.expanded)
352944d93782SGreg Clayton                 row_count += CalculateTotalNumberRows(row.children);
353044d93782SGreg Clayton         }
353144d93782SGreg Clayton         return row_count;
353244d93782SGreg Clayton     }
353344d93782SGreg Clayton     static Row *
353444d93782SGreg Clayton     GetRowForRowIndexImpl (std::vector<Row> &rows, size_t &row_index)
353544d93782SGreg Clayton     {
353644d93782SGreg Clayton         for (auto &row : rows)
353744d93782SGreg Clayton         {
353844d93782SGreg Clayton             if (row_index == 0)
353944d93782SGreg Clayton                 return &row;
354044d93782SGreg Clayton             else
354144d93782SGreg Clayton             {
354244d93782SGreg Clayton                 --row_index;
354344d93782SGreg Clayton                 if (row.expanded && !row.children.empty())
354444d93782SGreg Clayton                 {
354544d93782SGreg Clayton                     Row *result = GetRowForRowIndexImpl (row.children, row_index);
354644d93782SGreg Clayton                     if (result)
354744d93782SGreg Clayton                         return result;
354844d93782SGreg Clayton                 }
354944d93782SGreg Clayton             }
355044d93782SGreg Clayton         }
355144d93782SGreg Clayton         return NULL;
355244d93782SGreg Clayton     }
355344d93782SGreg Clayton 
355444d93782SGreg Clayton     Row *
355544d93782SGreg Clayton     GetRowForRowIndex (size_t row_index)
355644d93782SGreg Clayton     {
355744d93782SGreg Clayton         return GetRowForRowIndexImpl (m_rows, row_index);
355844d93782SGreg Clayton     }
355944d93782SGreg Clayton 
356044d93782SGreg Clayton     int
356144d93782SGreg Clayton     NumVisibleRows () const
356244d93782SGreg Clayton     {
356344d93782SGreg Clayton         return m_max_y - m_min_y;
356444d93782SGreg Clayton     }
356544d93782SGreg Clayton 
356644d93782SGreg Clayton     static DisplayOptions g_options;
356744d93782SGreg Clayton };
356844d93782SGreg Clayton 
356944d93782SGreg Clayton class FrameVariablesWindowDelegate : public ValueObjectListDelegate
357044d93782SGreg Clayton {
357144d93782SGreg Clayton public:
357244d93782SGreg Clayton     FrameVariablesWindowDelegate (Debugger &debugger) :
357344d93782SGreg Clayton         ValueObjectListDelegate (),
357444d93782SGreg Clayton         m_debugger (debugger),
357544d93782SGreg Clayton         m_frame_block (NULL)
357644d93782SGreg Clayton     {
357744d93782SGreg Clayton     }
357844d93782SGreg Clayton 
357944d93782SGreg Clayton     virtual
358044d93782SGreg Clayton     ~FrameVariablesWindowDelegate()
358144d93782SGreg Clayton     {
358244d93782SGreg Clayton     }
358344d93782SGreg Clayton 
358444d93782SGreg Clayton     virtual const char *
358544d93782SGreg Clayton     WindowDelegateGetHelpText ()
358644d93782SGreg Clayton     {
358744d93782SGreg Clayton         return "Frame variable window keyboard shortcuts:";
358844d93782SGreg Clayton     }
358944d93782SGreg Clayton 
359044d93782SGreg Clayton     virtual bool
359144d93782SGreg Clayton     WindowDelegateDraw (Window &window, bool force)
359244d93782SGreg Clayton     {
359344d93782SGreg Clayton         ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
359444d93782SGreg Clayton         Process *process = exe_ctx.GetProcessPtr();
359544d93782SGreg Clayton         Block *frame_block = NULL;
359644d93782SGreg Clayton         StackFrame *frame = NULL;
359744d93782SGreg Clayton 
359844d93782SGreg Clayton         if (process)
359944d93782SGreg Clayton         {
360044d93782SGreg Clayton             StateType state = process->GetState();
360144d93782SGreg Clayton             if (StateIsStoppedState(state, true))
360244d93782SGreg Clayton             {
360344d93782SGreg Clayton                 frame = exe_ctx.GetFramePtr();
360444d93782SGreg Clayton                 if (frame)
360544d93782SGreg Clayton                     frame_block = frame->GetFrameBlock ();
360644d93782SGreg Clayton             }
360744d93782SGreg Clayton             else if (StateIsRunningState(state))
360844d93782SGreg Clayton             {
360944d93782SGreg Clayton                 return true; // Don't do any updating when we are running
361044d93782SGreg Clayton             }
361144d93782SGreg Clayton         }
361244d93782SGreg Clayton 
361344d93782SGreg Clayton         ValueObjectList local_values;
361444d93782SGreg Clayton         if (frame_block)
361544d93782SGreg Clayton         {
361644d93782SGreg Clayton             // Only update the variables if they have changed
361744d93782SGreg Clayton             if (m_frame_block != frame_block)
361844d93782SGreg Clayton             {
361944d93782SGreg Clayton                 m_frame_block = frame_block;
362044d93782SGreg Clayton 
362144d93782SGreg Clayton                 VariableList *locals = frame->GetVariableList(true);
362244d93782SGreg Clayton                 if (locals)
362344d93782SGreg Clayton                 {
362444d93782SGreg Clayton                     const DynamicValueType use_dynamic = eDynamicDontRunTarget;
362544d93782SGreg Clayton                     const size_t num_locals = locals->GetSize();
362644d93782SGreg Clayton                     for (size_t i=0; i<num_locals; ++i)
362744d93782SGreg Clayton                         local_values.Append(frame->GetValueObjectForFrameVariable (locals->GetVariableAtIndex(i), use_dynamic));
362844d93782SGreg Clayton                     // Update the values
362944d93782SGreg Clayton                     SetValues(local_values);
363044d93782SGreg Clayton                 }
363144d93782SGreg Clayton             }
363244d93782SGreg Clayton         }
363344d93782SGreg Clayton         else
363444d93782SGreg Clayton         {
363544d93782SGreg Clayton             m_frame_block = NULL;
363644d93782SGreg Clayton             // Update the values with an empty list if there is no frame
363744d93782SGreg Clayton             SetValues(local_values);
363844d93782SGreg Clayton         }
363944d93782SGreg Clayton 
364044d93782SGreg Clayton         return ValueObjectListDelegate::WindowDelegateDraw (window, force);
364144d93782SGreg Clayton 
364244d93782SGreg Clayton     }
364344d93782SGreg Clayton 
364444d93782SGreg Clayton protected:
364544d93782SGreg Clayton     Debugger &m_debugger;
364644d93782SGreg Clayton     Block *m_frame_block;
364744d93782SGreg Clayton };
364844d93782SGreg Clayton 
364944d93782SGreg Clayton 
365044d93782SGreg Clayton class RegistersWindowDelegate : public ValueObjectListDelegate
365144d93782SGreg Clayton {
365244d93782SGreg Clayton public:
365344d93782SGreg Clayton     RegistersWindowDelegate (Debugger &debugger) :
365444d93782SGreg Clayton         ValueObjectListDelegate (),
365544d93782SGreg Clayton         m_debugger (debugger)
365644d93782SGreg Clayton     {
365744d93782SGreg Clayton     }
365844d93782SGreg Clayton 
365944d93782SGreg Clayton     virtual
366044d93782SGreg Clayton     ~RegistersWindowDelegate()
366144d93782SGreg Clayton     {
366244d93782SGreg Clayton     }
366344d93782SGreg Clayton 
366444d93782SGreg Clayton     virtual const char *
366544d93782SGreg Clayton     WindowDelegateGetHelpText ()
366644d93782SGreg Clayton     {
366744d93782SGreg Clayton         return "Register window keyboard shortcuts:";
366844d93782SGreg Clayton     }
366944d93782SGreg Clayton 
367044d93782SGreg Clayton     virtual bool
367144d93782SGreg Clayton     WindowDelegateDraw (Window &window, bool force)
367244d93782SGreg Clayton     {
367344d93782SGreg Clayton         ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
367444d93782SGreg Clayton         StackFrame *frame = exe_ctx.GetFramePtr();
367544d93782SGreg Clayton 
367644d93782SGreg Clayton         ValueObjectList value_list;
367744d93782SGreg Clayton         if (frame)
367844d93782SGreg Clayton         {
367944d93782SGreg Clayton             if (frame->GetStackID() != m_stack_id)
368044d93782SGreg Clayton             {
368144d93782SGreg Clayton                 m_stack_id = frame->GetStackID();
368244d93782SGreg Clayton                 RegisterContextSP reg_ctx (frame->GetRegisterContext());
368344d93782SGreg Clayton                 if (reg_ctx)
368444d93782SGreg Clayton                 {
368544d93782SGreg Clayton                     const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
368644d93782SGreg Clayton                     for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx)
368744d93782SGreg Clayton                     {
368844d93782SGreg Clayton                         value_list.Append(ValueObjectRegisterSet::Create (frame, reg_ctx, set_idx));
368944d93782SGreg Clayton                     }
369044d93782SGreg Clayton                 }
369144d93782SGreg Clayton                 SetValues(value_list);
369244d93782SGreg Clayton             }
369344d93782SGreg Clayton         }
369444d93782SGreg Clayton         else
369544d93782SGreg Clayton         {
369644d93782SGreg Clayton             Process *process = exe_ctx.GetProcessPtr();
369744d93782SGreg Clayton             if (process && process->IsAlive())
369844d93782SGreg Clayton                 return true; // Don't do any updating if we are running
369944d93782SGreg Clayton             else
370044d93782SGreg Clayton             {
370144d93782SGreg Clayton                 // Update the values with an empty list if there
370244d93782SGreg Clayton                 // is no process or the process isn't alive anymore
370344d93782SGreg Clayton                 SetValues(value_list);
370444d93782SGreg Clayton             }
370544d93782SGreg Clayton         }
370644d93782SGreg Clayton         return ValueObjectListDelegate::WindowDelegateDraw (window, force);
370744d93782SGreg Clayton     }
370844d93782SGreg Clayton 
370944d93782SGreg Clayton protected:
371044d93782SGreg Clayton     Debugger &m_debugger;
371144d93782SGreg Clayton     StackID m_stack_id;
371244d93782SGreg Clayton };
371344d93782SGreg Clayton 
371444d93782SGreg Clayton static const char *
371544d93782SGreg Clayton CursesKeyToCString (int ch)
371644d93782SGreg Clayton {
371744d93782SGreg Clayton     static char g_desc[32];
371844d93782SGreg Clayton     if (ch >= KEY_F0 && ch < KEY_F0 + 64)
371944d93782SGreg Clayton     {
372044d93782SGreg Clayton         snprintf(g_desc, sizeof(g_desc), "F%u", ch - KEY_F0);
372144d93782SGreg Clayton         return g_desc;
372244d93782SGreg Clayton     }
372344d93782SGreg Clayton     switch (ch)
372444d93782SGreg Clayton     {
372544d93782SGreg Clayton         case KEY_DOWN:  return "down";
372644d93782SGreg Clayton         case KEY_UP:    return "up";
372744d93782SGreg Clayton         case KEY_LEFT:  return "left";
372844d93782SGreg Clayton         case KEY_RIGHT: return "right";
372944d93782SGreg Clayton         case KEY_HOME:  return "home";
373044d93782SGreg Clayton         case KEY_BACKSPACE: return "backspace";
373144d93782SGreg Clayton         case KEY_DL:        return "delete-line";
373244d93782SGreg Clayton         case KEY_IL:        return "insert-line";
373344d93782SGreg Clayton         case KEY_DC:        return "delete-char";
373444d93782SGreg Clayton         case KEY_IC:        return "insert-char";
373544d93782SGreg Clayton         case KEY_CLEAR:     return "clear";
373644d93782SGreg Clayton         case KEY_EOS:       return "clear-to-eos";
373744d93782SGreg Clayton         case KEY_EOL:       return "clear-to-eol";
373844d93782SGreg Clayton         case KEY_SF:        return "scroll-forward";
373944d93782SGreg Clayton         case KEY_SR:        return "scroll-backward";
374044d93782SGreg Clayton         case KEY_NPAGE:     return "page-down";
374144d93782SGreg Clayton         case KEY_PPAGE:     return "page-up";
374244d93782SGreg Clayton         case KEY_STAB:      return "set-tab";
374344d93782SGreg Clayton         case KEY_CTAB:      return "clear-tab";
374444d93782SGreg Clayton         case KEY_CATAB:     return "clear-all-tabs";
374544d93782SGreg Clayton         case KEY_ENTER:     return "enter";
374644d93782SGreg Clayton         case KEY_PRINT:     return "print";
374744d93782SGreg Clayton         case KEY_LL:        return "lower-left key";
374844d93782SGreg Clayton         case KEY_A1:        return "upper left of keypad";
374944d93782SGreg Clayton         case KEY_A3:        return "upper right of keypad";
375044d93782SGreg Clayton         case KEY_B2:        return "center of keypad";
375144d93782SGreg Clayton         case KEY_C1:        return "lower left of keypad";
375244d93782SGreg Clayton         case KEY_C3:        return "lower right of keypad";
375344d93782SGreg Clayton         case KEY_BTAB:      return "back-tab key";
375444d93782SGreg Clayton         case KEY_BEG:       return "begin key";
375544d93782SGreg Clayton         case KEY_CANCEL:    return "cancel key";
375644d93782SGreg Clayton         case KEY_CLOSE:     return "close key";
375744d93782SGreg Clayton         case KEY_COMMAND:   return "command key";
375844d93782SGreg Clayton         case KEY_COPY:      return "copy key";
375944d93782SGreg Clayton         case KEY_CREATE:    return "create key";
376044d93782SGreg Clayton         case KEY_END:       return "end key";
376144d93782SGreg Clayton         case KEY_EXIT:      return "exit key";
376244d93782SGreg Clayton         case KEY_FIND:      return "find key";
376344d93782SGreg Clayton         case KEY_HELP:      return "help key";
376444d93782SGreg Clayton         case KEY_MARK:      return "mark key";
376544d93782SGreg Clayton         case KEY_MESSAGE:   return "message key";
376644d93782SGreg Clayton         case KEY_MOVE:      return "move key";
376744d93782SGreg Clayton         case KEY_NEXT:      return "next key";
376844d93782SGreg Clayton         case KEY_OPEN:      return "open key";
376944d93782SGreg Clayton         case KEY_OPTIONS:   return "options key";
377044d93782SGreg Clayton         case KEY_PREVIOUS:  return "previous key";
377144d93782SGreg Clayton         case KEY_REDO:      return "redo key";
377244d93782SGreg Clayton         case KEY_REFERENCE: return "reference key";
377344d93782SGreg Clayton         case KEY_REFRESH:   return "refresh key";
377444d93782SGreg Clayton         case KEY_REPLACE:   return "replace key";
377544d93782SGreg Clayton         case KEY_RESTART:   return "restart key";
377644d93782SGreg Clayton         case KEY_RESUME:    return "resume key";
377744d93782SGreg Clayton         case KEY_SAVE:      return "save key";
377844d93782SGreg Clayton         case KEY_SBEG:      return "shifted begin key";
377944d93782SGreg Clayton         case KEY_SCANCEL:   return "shifted cancel key";
378044d93782SGreg Clayton         case KEY_SCOMMAND:  return "shifted command key";
378144d93782SGreg Clayton         case KEY_SCOPY:     return "shifted copy key";
378244d93782SGreg Clayton         case KEY_SCREATE:   return "shifted create key";
378344d93782SGreg Clayton         case KEY_SDC:       return "shifted delete-character key";
378444d93782SGreg Clayton         case KEY_SDL:       return "shifted delete-line key";
378544d93782SGreg Clayton         case KEY_SELECT:    return "select key";
378644d93782SGreg Clayton         case KEY_SEND:      return "shifted end key";
378744d93782SGreg Clayton         case KEY_SEOL:      return "shifted clear-to-end-of-line key";
378844d93782SGreg Clayton         case KEY_SEXIT:     return "shifted exit key";
378944d93782SGreg Clayton         case KEY_SFIND:     return "shifted find key";
379044d93782SGreg Clayton         case KEY_SHELP:     return "shifted help key";
379144d93782SGreg Clayton         case KEY_SHOME:     return "shifted home key";
379244d93782SGreg Clayton         case KEY_SIC:       return "shifted insert-character key";
379344d93782SGreg Clayton         case KEY_SLEFT:     return "shifted left-arrow key";
379444d93782SGreg Clayton         case KEY_SMESSAGE:  return "shifted message key";
379544d93782SGreg Clayton         case KEY_SMOVE:     return "shifted move key";
379644d93782SGreg Clayton         case KEY_SNEXT:     return "shifted next key";
379744d93782SGreg Clayton         case KEY_SOPTIONS:  return "shifted options key";
379844d93782SGreg Clayton         case KEY_SPREVIOUS: return "shifted previous key";
379944d93782SGreg Clayton         case KEY_SPRINT:    return "shifted print key";
380044d93782SGreg Clayton         case KEY_SREDO:     return "shifted redo key";
380144d93782SGreg Clayton         case KEY_SREPLACE:  return "shifted replace key";
380244d93782SGreg Clayton         case KEY_SRIGHT:    return "shifted right-arrow key";
380344d93782SGreg Clayton         case KEY_SRSUME:    return "shifted resume key";
380444d93782SGreg Clayton         case KEY_SSAVE:     return "shifted save key";
380544d93782SGreg Clayton         case KEY_SSUSPEND:  return "shifted suspend key";
380644d93782SGreg Clayton         case KEY_SUNDO:     return "shifted undo key";
380744d93782SGreg Clayton         case KEY_SUSPEND:   return "suspend key";
380844d93782SGreg Clayton         case KEY_UNDO:      return "undo key";
380944d93782SGreg Clayton         case KEY_MOUSE:     return "Mouse event has occurred";
381044d93782SGreg Clayton         case KEY_RESIZE:    return "Terminal resize event";
381144d93782SGreg Clayton         case KEY_EVENT:     return "We were interrupted by an event";
381244d93782SGreg Clayton         case KEY_RETURN:    return "return";
381344d93782SGreg Clayton         case ' ':           return "space";
3814*5fdb09bbSGreg Clayton         case '\t':          return "tab";
381544d93782SGreg Clayton         case KEY_ESCAPE:    return "escape";
381644d93782SGreg Clayton         default:
381744d93782SGreg Clayton             if (isprint(ch))
381844d93782SGreg Clayton                 snprintf(g_desc, sizeof(g_desc), "%c", ch);
381944d93782SGreg Clayton             else
382044d93782SGreg Clayton                 snprintf(g_desc, sizeof(g_desc), "\\x%2.2x", ch);
382144d93782SGreg Clayton             return g_desc;
382244d93782SGreg Clayton     }
382344d93782SGreg Clayton     return NULL;
382444d93782SGreg Clayton }
382544d93782SGreg Clayton 
382644d93782SGreg Clayton HelpDialogDelegate::HelpDialogDelegate (const char *text, KeyHelp *key_help_array) :
382744d93782SGreg Clayton     m_text (),
382844d93782SGreg Clayton     m_first_visible_line (0)
382944d93782SGreg Clayton {
383044d93782SGreg Clayton     if (text && text[0])
383144d93782SGreg Clayton     {
383244d93782SGreg Clayton         m_text.SplitIntoLines(text);
383344d93782SGreg Clayton         m_text.AppendString("");
383444d93782SGreg Clayton     }
383544d93782SGreg Clayton     if (key_help_array)
383644d93782SGreg Clayton     {
383744d93782SGreg Clayton         for (KeyHelp *key = key_help_array; key->ch; ++key)
383844d93782SGreg Clayton         {
383944d93782SGreg Clayton             StreamString key_description;
384044d93782SGreg Clayton             key_description.Printf("%10s - %s", CursesKeyToCString(key->ch), key->description);
384144d93782SGreg Clayton             m_text.AppendString(std::move(key_description.GetString()));
384244d93782SGreg Clayton         }
384344d93782SGreg Clayton     }
384444d93782SGreg Clayton }
384544d93782SGreg Clayton 
384644d93782SGreg Clayton HelpDialogDelegate::~HelpDialogDelegate()
384744d93782SGreg Clayton {
384844d93782SGreg Clayton }
384944d93782SGreg Clayton 
385044d93782SGreg Clayton bool
385144d93782SGreg Clayton HelpDialogDelegate::WindowDelegateDraw (Window &window, bool force)
385244d93782SGreg Clayton {
385344d93782SGreg Clayton     window.Erase();
385444d93782SGreg Clayton     const int window_height = window.GetHeight();
385544d93782SGreg Clayton     int x = 2;
385644d93782SGreg Clayton     int y = 1;
385744d93782SGreg Clayton     const int min_y = y;
385844d93782SGreg Clayton     const int max_y = window_height - 1 - y;
385944d93782SGreg Clayton     const int num_visible_lines = max_y - min_y + 1;
386044d93782SGreg Clayton     const size_t num_lines = m_text.GetSize();
386144d93782SGreg Clayton     const char *bottom_message;
386244d93782SGreg Clayton     if (num_lines <= num_visible_lines)
386344d93782SGreg Clayton         bottom_message = "Press any key to exit";
386444d93782SGreg Clayton     else
386544d93782SGreg Clayton         bottom_message = "Use arrows to scroll, any other key to exit";
386644d93782SGreg Clayton     window.DrawTitleBox(window.GetName(), bottom_message);
386744d93782SGreg Clayton     while (y <= max_y)
386844d93782SGreg Clayton     {
386944d93782SGreg Clayton         window.MoveCursor(x, y);
387044d93782SGreg Clayton         window.PutCStringTruncated(m_text.GetStringAtIndex(m_first_visible_line + y - min_y), 1);
387144d93782SGreg Clayton         ++y;
387244d93782SGreg Clayton     }
387344d93782SGreg Clayton     return true;
387444d93782SGreg Clayton }
387544d93782SGreg Clayton 
387644d93782SGreg Clayton HandleCharResult
387744d93782SGreg Clayton HelpDialogDelegate::WindowDelegateHandleChar (Window &window, int key)
387844d93782SGreg Clayton {
387944d93782SGreg Clayton     bool done = false;
388044d93782SGreg Clayton     const size_t num_lines = m_text.GetSize();
388144d93782SGreg Clayton     const size_t num_visible_lines = window.GetHeight() - 2;
388244d93782SGreg Clayton 
388344d93782SGreg Clayton     if (num_lines <= num_visible_lines)
388444d93782SGreg Clayton     {
388544d93782SGreg Clayton         done = true;
388644d93782SGreg Clayton         // If we have all lines visible and don't need scrolling, then any
388744d93782SGreg Clayton         // key press will cause us to exit
388844d93782SGreg Clayton     }
388944d93782SGreg Clayton     else
389044d93782SGreg Clayton     {
389144d93782SGreg Clayton         switch (key)
389244d93782SGreg Clayton         {
389344d93782SGreg Clayton             case KEY_UP:
389444d93782SGreg Clayton                 if (m_first_visible_line > 0)
389544d93782SGreg Clayton                     --m_first_visible_line;
389644d93782SGreg Clayton                 break;
389744d93782SGreg Clayton 
389844d93782SGreg Clayton             case KEY_DOWN:
389944d93782SGreg Clayton                 if (m_first_visible_line + num_visible_lines < num_lines)
390044d93782SGreg Clayton                     ++m_first_visible_line;
390144d93782SGreg Clayton                 break;
390244d93782SGreg Clayton 
390344d93782SGreg Clayton             case KEY_PPAGE:
390444d93782SGreg Clayton             case ',':
390544d93782SGreg Clayton                 if (m_first_visible_line > 0)
390644d93782SGreg Clayton                 {
390744d93782SGreg Clayton                     if (m_first_visible_line >= num_visible_lines)
390844d93782SGreg Clayton                         m_first_visible_line -= num_visible_lines;
390944d93782SGreg Clayton                     else
391044d93782SGreg Clayton                         m_first_visible_line = 0;
391144d93782SGreg Clayton                 }
391244d93782SGreg Clayton                 break;
391344d93782SGreg Clayton             case KEY_NPAGE:
391444d93782SGreg Clayton             case '.':
391544d93782SGreg Clayton                 if (m_first_visible_line + num_visible_lines < num_lines)
391644d93782SGreg Clayton                 {
391744d93782SGreg Clayton                     m_first_visible_line += num_visible_lines;
391844d93782SGreg Clayton                     if (m_first_visible_line > num_lines)
391944d93782SGreg Clayton                         m_first_visible_line = num_lines - num_visible_lines;
392044d93782SGreg Clayton                 }
392144d93782SGreg Clayton                 break;
392244d93782SGreg Clayton             default:
392344d93782SGreg Clayton                 done = true;
392444d93782SGreg Clayton                 break;
392544d93782SGreg Clayton         }
392644d93782SGreg Clayton     }
392744d93782SGreg Clayton     if (done)
392844d93782SGreg Clayton         window.GetParent()->RemoveSubWindow(&window);
392944d93782SGreg Clayton     return eKeyHandled;
393044d93782SGreg Clayton }
393144d93782SGreg Clayton 
393244d93782SGreg Clayton class ApplicationDelegate :
393344d93782SGreg Clayton     public WindowDelegate,
393444d93782SGreg Clayton     public MenuDelegate
393544d93782SGreg Clayton {
393644d93782SGreg Clayton public:
393744d93782SGreg Clayton     enum {
393844d93782SGreg Clayton         eMenuID_LLDB = 1,
393944d93782SGreg Clayton         eMenuID_LLDBAbout,
394044d93782SGreg Clayton         eMenuID_LLDBExit,
394144d93782SGreg Clayton 
394244d93782SGreg Clayton         eMenuID_Target,
394344d93782SGreg Clayton         eMenuID_TargetCreate,
394444d93782SGreg Clayton         eMenuID_TargetDelete,
394544d93782SGreg Clayton 
394644d93782SGreg Clayton         eMenuID_Process,
394744d93782SGreg Clayton         eMenuID_ProcessAttach,
394844d93782SGreg Clayton         eMenuID_ProcessDetach,
394944d93782SGreg Clayton         eMenuID_ProcessLaunch,
395044d93782SGreg Clayton         eMenuID_ProcessContinue,
395144d93782SGreg Clayton         eMenuID_ProcessHalt,
395244d93782SGreg Clayton         eMenuID_ProcessKill,
395344d93782SGreg Clayton 
395444d93782SGreg Clayton         eMenuID_Thread,
395544d93782SGreg Clayton         eMenuID_ThreadStepIn,
395644d93782SGreg Clayton         eMenuID_ThreadStepOver,
395744d93782SGreg Clayton         eMenuID_ThreadStepOut,
395844d93782SGreg Clayton 
395944d93782SGreg Clayton         eMenuID_View,
396044d93782SGreg Clayton         eMenuID_ViewBacktrace,
396144d93782SGreg Clayton         eMenuID_ViewRegisters,
396244d93782SGreg Clayton         eMenuID_ViewSource,
396344d93782SGreg Clayton         eMenuID_ViewVariables,
396444d93782SGreg Clayton 
396544d93782SGreg Clayton         eMenuID_Help,
396644d93782SGreg Clayton         eMenuID_HelpGUIHelp
396744d93782SGreg Clayton     };
396844d93782SGreg Clayton 
396944d93782SGreg Clayton     ApplicationDelegate (Application &app, Debugger &debugger) :
397044d93782SGreg Clayton         WindowDelegate (),
397144d93782SGreg Clayton         MenuDelegate (),
397244d93782SGreg Clayton         m_app (app),
397344d93782SGreg Clayton         m_debugger (debugger)
397444d93782SGreg Clayton     {
397544d93782SGreg Clayton     }
397644d93782SGreg Clayton 
397744d93782SGreg Clayton     virtual
397844d93782SGreg Clayton     ~ApplicationDelegate ()
397944d93782SGreg Clayton     {
398044d93782SGreg Clayton     }
398144d93782SGreg Clayton     virtual bool
398244d93782SGreg Clayton     WindowDelegateDraw (Window &window, bool force)
398344d93782SGreg Clayton     {
398444d93782SGreg Clayton         return false; // Drawing not handled, let standard window drawing happen
398544d93782SGreg Clayton     }
398644d93782SGreg Clayton 
398744d93782SGreg Clayton     virtual HandleCharResult
398844d93782SGreg Clayton     WindowDelegateHandleChar (Window &window, int key)
398944d93782SGreg Clayton     {
3990*5fdb09bbSGreg Clayton         switch (key)
399144d93782SGreg Clayton         {
3992*5fdb09bbSGreg Clayton             case '\t':
399344d93782SGreg Clayton                 window.SelectNextWindowAsActive();
399444d93782SGreg Clayton                 return eKeyHandled;
3995*5fdb09bbSGreg Clayton 
3996*5fdb09bbSGreg Clayton             case 'h':
3997*5fdb09bbSGreg Clayton                 window.CreateHelpSubwindow();
3998*5fdb09bbSGreg Clayton                 return eKeyHandled;
3999*5fdb09bbSGreg Clayton 
4000*5fdb09bbSGreg Clayton             case KEY_ESCAPE:
4001*5fdb09bbSGreg Clayton                 return eQuitApplication;
4002*5fdb09bbSGreg Clayton 
4003*5fdb09bbSGreg Clayton             default:
4004*5fdb09bbSGreg Clayton                 break;
400544d93782SGreg Clayton         }
400644d93782SGreg Clayton         return eKeyNotHandled;
400744d93782SGreg Clayton     }
400844d93782SGreg Clayton 
4009*5fdb09bbSGreg Clayton 
4010*5fdb09bbSGreg Clayton     virtual const char *
4011*5fdb09bbSGreg Clayton     WindowDelegateGetHelpText ()
4012*5fdb09bbSGreg Clayton     {
4013*5fdb09bbSGreg Clayton         return "Welcome to the LLDB curses GUI.\n\n"
4014*5fdb09bbSGreg Clayton         "Press the TAB key to change the selected view.\n"
4015*5fdb09bbSGreg Clayton         "Each view has its own keyboard shortcuts, press 'h' to open a dialog to display them.\n\n"
4016*5fdb09bbSGreg Clayton         "Common key bindings for all views:";
4017*5fdb09bbSGreg Clayton     }
4018*5fdb09bbSGreg Clayton 
4019*5fdb09bbSGreg Clayton     virtual KeyHelp *
4020*5fdb09bbSGreg Clayton     WindowDelegateGetKeyHelp ()
4021*5fdb09bbSGreg Clayton     {
4022*5fdb09bbSGreg Clayton         static curses::KeyHelp g_source_view_key_help[] = {
4023*5fdb09bbSGreg Clayton             { '\t', "Select next view" },
4024*5fdb09bbSGreg Clayton             { 'h', "Show help dialog with view specific key bindings" },
4025*5fdb09bbSGreg Clayton             { ',', "Page up" },
4026*5fdb09bbSGreg Clayton             { '.', "Page down" },
4027*5fdb09bbSGreg Clayton             { KEY_UP, "Select previous" },
4028*5fdb09bbSGreg Clayton             { KEY_DOWN, "Select next" },
4029*5fdb09bbSGreg Clayton             { KEY_LEFT, "Unexpand or select parent" },
4030*5fdb09bbSGreg Clayton             { KEY_RIGHT, "Expand" },
4031*5fdb09bbSGreg Clayton             { KEY_PPAGE, "Page up" },
4032*5fdb09bbSGreg Clayton             { KEY_NPAGE, "Page down" },
4033*5fdb09bbSGreg Clayton             { '\0', NULL }
4034*5fdb09bbSGreg Clayton         };
4035*5fdb09bbSGreg Clayton         return g_source_view_key_help;
4036*5fdb09bbSGreg Clayton     }
4037*5fdb09bbSGreg Clayton 
403844d93782SGreg Clayton     virtual MenuActionResult
403944d93782SGreg Clayton     MenuDelegateAction (Menu &menu)
404044d93782SGreg Clayton     {
404144d93782SGreg Clayton         switch (menu.GetIdentifier())
404244d93782SGreg Clayton         {
404344d93782SGreg Clayton             case eMenuID_ThreadStepIn:
404444d93782SGreg Clayton                 {
404544d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
404644d93782SGreg Clayton                     if (exe_ctx.HasThreadScope())
404744d93782SGreg Clayton                     {
404844d93782SGreg Clayton                         Process *process = exe_ctx.GetProcessPtr();
404944d93782SGreg Clayton                         if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
405044d93782SGreg Clayton                             exe_ctx.GetThreadRef().StepIn(true, true);
405144d93782SGreg Clayton                     }
405244d93782SGreg Clayton                 }
405344d93782SGreg Clayton                 return MenuActionResult::Handled;
405444d93782SGreg Clayton 
405544d93782SGreg Clayton             case eMenuID_ThreadStepOut:
405644d93782SGreg Clayton                 {
405744d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
405844d93782SGreg Clayton                     if (exe_ctx.HasThreadScope())
405944d93782SGreg Clayton                     {
406044d93782SGreg Clayton                         Process *process = exe_ctx.GetProcessPtr();
406144d93782SGreg Clayton                         if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
406244d93782SGreg Clayton                             exe_ctx.GetThreadRef().StepOut();
406344d93782SGreg Clayton                     }
406444d93782SGreg Clayton                 }
406544d93782SGreg Clayton                 return MenuActionResult::Handled;
406644d93782SGreg Clayton 
406744d93782SGreg Clayton             case eMenuID_ThreadStepOver:
406844d93782SGreg Clayton                 {
406944d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
407044d93782SGreg Clayton                     if (exe_ctx.HasThreadScope())
407144d93782SGreg Clayton                     {
407244d93782SGreg Clayton                         Process *process = exe_ctx.GetProcessPtr();
407344d93782SGreg Clayton                         if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
407444d93782SGreg Clayton                             exe_ctx.GetThreadRef().StepOver(true);
407544d93782SGreg Clayton                     }
407644d93782SGreg Clayton                 }
407744d93782SGreg Clayton                 return MenuActionResult::Handled;
407844d93782SGreg Clayton 
407944d93782SGreg Clayton             case eMenuID_ProcessContinue:
408044d93782SGreg Clayton                 {
408144d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
408244d93782SGreg Clayton                     if (exe_ctx.HasProcessScope())
408344d93782SGreg Clayton                     {
408444d93782SGreg Clayton                         Process *process = exe_ctx.GetProcessPtr();
408544d93782SGreg Clayton                         if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
408644d93782SGreg Clayton                             process->Resume();
408744d93782SGreg Clayton                     }
408844d93782SGreg Clayton                 }
408944d93782SGreg Clayton                 return MenuActionResult::Handled;
409044d93782SGreg Clayton 
409144d93782SGreg Clayton             case eMenuID_ProcessKill:
409244d93782SGreg Clayton                 {
409344d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
409444d93782SGreg Clayton                     if (exe_ctx.HasProcessScope())
409544d93782SGreg Clayton                     {
409644d93782SGreg Clayton                         Process *process = exe_ctx.GetProcessPtr();
409744d93782SGreg Clayton                         if (process && process->IsAlive())
409844d93782SGreg Clayton                             process->Destroy();
409944d93782SGreg Clayton                     }
410044d93782SGreg Clayton                 }
410144d93782SGreg Clayton                 return MenuActionResult::Handled;
410244d93782SGreg Clayton 
410344d93782SGreg Clayton             case eMenuID_ProcessHalt:
410444d93782SGreg Clayton                 {
410544d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
410644d93782SGreg Clayton                     if (exe_ctx.HasProcessScope())
410744d93782SGreg Clayton                     {
410844d93782SGreg Clayton                         Process *process = exe_ctx.GetProcessPtr();
410944d93782SGreg Clayton                         if (process && process->IsAlive())
411044d93782SGreg Clayton                             process->Halt();
411144d93782SGreg Clayton                     }
411244d93782SGreg Clayton                 }
411344d93782SGreg Clayton                 return MenuActionResult::Handled;
411444d93782SGreg Clayton 
411544d93782SGreg Clayton             case eMenuID_ProcessDetach:
411644d93782SGreg Clayton                 {
411744d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
411844d93782SGreg Clayton                     if (exe_ctx.HasProcessScope())
411944d93782SGreg Clayton                     {
412044d93782SGreg Clayton                         Process *process = exe_ctx.GetProcessPtr();
412144d93782SGreg Clayton                         if (process && process->IsAlive())
412244d93782SGreg Clayton                             process->Detach(false);
412344d93782SGreg Clayton                     }
412444d93782SGreg Clayton                 }
412544d93782SGreg Clayton                 return MenuActionResult::Handled;
412644d93782SGreg Clayton 
412744d93782SGreg Clayton             case eMenuID_Process:
412844d93782SGreg Clayton                 {
412944d93782SGreg Clayton                     // Populate the menu with all of the threads if the process is stopped when
413044d93782SGreg Clayton                     // the Process menu gets selected and is about to display its submenu.
413144d93782SGreg Clayton                     Menus &submenus = menu.GetSubmenus();
413244d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
413344d93782SGreg Clayton                     Process *process = exe_ctx.GetProcessPtr();
413444d93782SGreg Clayton                     if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
413544d93782SGreg Clayton                     {
413644d93782SGreg Clayton                         if (submenus.size() == 7)
413744d93782SGreg Clayton                             menu.AddSubmenu (MenuSP (new Menu(Menu::Type::Separator)));
413844d93782SGreg Clayton                         else if (submenus.size() > 8)
413944d93782SGreg Clayton                             submenus.erase (submenus.begin() + 8, submenus.end());
414044d93782SGreg Clayton 
414144d93782SGreg Clayton                         ThreadList &threads = process->GetThreadList();
414244d93782SGreg Clayton                         Mutex::Locker locker (threads.GetMutex());
414344d93782SGreg Clayton                         size_t num_threads = threads.GetSize();
414444d93782SGreg Clayton                         for (size_t i=0; i<num_threads; ++i)
414544d93782SGreg Clayton                         {
414644d93782SGreg Clayton                             ThreadSP thread_sp = threads.GetThreadAtIndex(i);
414744d93782SGreg Clayton                             char menu_char = '\0';
414844d93782SGreg Clayton                             if (i < 9)
414944d93782SGreg Clayton                                 menu_char = '1' + i;
415044d93782SGreg Clayton                             StreamString thread_menu_title;
415144d93782SGreg Clayton                             thread_menu_title.Printf("Thread %u", thread_sp->GetIndexID());
415244d93782SGreg Clayton                             const char *thread_name = thread_sp->GetName();
415344d93782SGreg Clayton                             if (thread_name && thread_name[0])
415444d93782SGreg Clayton                                 thread_menu_title.Printf (" %s", thread_name);
415544d93782SGreg Clayton                             else
415644d93782SGreg Clayton                             {
415744d93782SGreg Clayton                                 const char *queue_name = thread_sp->GetQueueName();
415844d93782SGreg Clayton                                 if (queue_name && queue_name[0])
415944d93782SGreg Clayton                                     thread_menu_title.Printf (" %s", queue_name);
416044d93782SGreg Clayton                             }
416144d93782SGreg Clayton                             menu.AddSubmenu (MenuSP (new Menu(thread_menu_title.GetString().c_str(), NULL, menu_char, thread_sp->GetID())));
416244d93782SGreg Clayton                         }
416344d93782SGreg Clayton                     }
416444d93782SGreg Clayton                     else if (submenus.size() > 7)
416544d93782SGreg Clayton                     {
416644d93782SGreg Clayton                         // Remove the separator and any other thread submenu items
416744d93782SGreg Clayton                         // that were previously added
416844d93782SGreg Clayton                         submenus.erase (submenus.begin() + 7, submenus.end());
416944d93782SGreg Clayton                     }
417044d93782SGreg Clayton                     // Since we are adding and removing items we need to recalculate the name lengths
417144d93782SGreg Clayton                     menu.RecalculateNameLengths();
417244d93782SGreg Clayton                 }
417344d93782SGreg Clayton                 return MenuActionResult::Handled;
417444d93782SGreg Clayton 
417544d93782SGreg Clayton             case eMenuID_ViewVariables:
417644d93782SGreg Clayton                 {
417744d93782SGreg Clayton                     WindowSP main_window_sp = m_app.GetMainWindow();
417844d93782SGreg Clayton                     WindowSP source_window_sp = main_window_sp->FindSubWindow("Source");
417944d93782SGreg Clayton                     WindowSP variables_window_sp = main_window_sp->FindSubWindow("Variables");
418044d93782SGreg Clayton                     WindowSP registers_window_sp = main_window_sp->FindSubWindow("Registers");
418144d93782SGreg Clayton                     const Rect source_bounds = source_window_sp->GetBounds();
418244d93782SGreg Clayton 
418344d93782SGreg Clayton                     if (variables_window_sp)
418444d93782SGreg Clayton                     {
418544d93782SGreg Clayton                         const Rect variables_bounds = variables_window_sp->GetBounds();
418644d93782SGreg Clayton 
418744d93782SGreg Clayton                         main_window_sp->RemoveSubWindow(variables_window_sp.get());
418844d93782SGreg Clayton 
418944d93782SGreg Clayton                         if (registers_window_sp)
419044d93782SGreg Clayton                         {
419144d93782SGreg Clayton                             // We have a registers window, so give all the area back to the registers window
419244d93782SGreg Clayton                             Rect registers_bounds = variables_bounds;
419344d93782SGreg Clayton                             registers_bounds.size.width = source_bounds.size.width;
419444d93782SGreg Clayton                             registers_window_sp->SetBounds(registers_bounds);
419544d93782SGreg Clayton                         }
419644d93782SGreg Clayton                         else
419744d93782SGreg Clayton                         {
419844d93782SGreg Clayton                             // We have no registers window showing so give the bottom
419944d93782SGreg Clayton                             // area back to the source view
420044d93782SGreg Clayton                             source_window_sp->Resize (source_bounds.size.width,
420144d93782SGreg Clayton                                                       source_bounds.size.height + variables_bounds.size.height);
420244d93782SGreg Clayton                         }
420344d93782SGreg Clayton                     }
420444d93782SGreg Clayton                     else
420544d93782SGreg Clayton                     {
420644d93782SGreg Clayton                         Rect new_variables_rect;
420744d93782SGreg Clayton                         if (registers_window_sp)
420844d93782SGreg Clayton                         {
420944d93782SGreg Clayton                             // We have a registers window so split the area of the registers
421044d93782SGreg Clayton                             // window into two columns where the left hand side will be the
421144d93782SGreg Clayton                             // variables and the right hand side will be the registers
421244d93782SGreg Clayton                             const Rect variables_bounds = registers_window_sp->GetBounds();
421344d93782SGreg Clayton                             Rect new_registers_rect;
421444d93782SGreg Clayton                             variables_bounds.VerticalSplitPercentage (0.50, new_variables_rect, new_registers_rect);
421544d93782SGreg Clayton                             registers_window_sp->SetBounds (new_registers_rect);
421644d93782SGreg Clayton                         }
421744d93782SGreg Clayton                         else
421844d93782SGreg Clayton                         {
421944d93782SGreg Clayton                             // No variables window, grab the bottom part of the source window
422044d93782SGreg Clayton                             Rect new_source_rect;
422144d93782SGreg Clayton                             source_bounds.HorizontalSplitPercentage (0.70, new_source_rect, new_variables_rect);
422244d93782SGreg Clayton                             source_window_sp->SetBounds (new_source_rect);
422344d93782SGreg Clayton                         }
422444d93782SGreg Clayton                         WindowSP new_window_sp = main_window_sp->CreateSubWindow ("Variables",
422544d93782SGreg Clayton                                                                                   new_variables_rect,
422644d93782SGreg Clayton                                                                                   false);
422744d93782SGreg Clayton                         new_window_sp->SetDelegate (WindowDelegateSP(new FrameVariablesWindowDelegate(m_debugger)));
422844d93782SGreg Clayton                     }
422944d93782SGreg Clayton                     touchwin(stdscr);
423044d93782SGreg Clayton                 }
423144d93782SGreg Clayton                 return MenuActionResult::Handled;
423244d93782SGreg Clayton 
423344d93782SGreg Clayton             case eMenuID_ViewRegisters:
423444d93782SGreg Clayton                 {
423544d93782SGreg Clayton                     WindowSP main_window_sp = m_app.GetMainWindow();
423644d93782SGreg Clayton                     WindowSP source_window_sp = main_window_sp->FindSubWindow("Source");
423744d93782SGreg Clayton                     WindowSP variables_window_sp = main_window_sp->FindSubWindow("Variables");
423844d93782SGreg Clayton                     WindowSP registers_window_sp = main_window_sp->FindSubWindow("Registers");
423944d93782SGreg Clayton                     const Rect source_bounds = source_window_sp->GetBounds();
424044d93782SGreg Clayton 
424144d93782SGreg Clayton                     if (registers_window_sp)
424244d93782SGreg Clayton                     {
424344d93782SGreg Clayton                         if (variables_window_sp)
424444d93782SGreg Clayton                         {
424544d93782SGreg Clayton                             const Rect variables_bounds = variables_window_sp->GetBounds();
424644d93782SGreg Clayton 
424744d93782SGreg Clayton                             // We have a variables window, so give all the area back to the variables window
424844d93782SGreg Clayton                             variables_window_sp->Resize (variables_bounds.size.width + registers_window_sp->GetWidth(),
424944d93782SGreg Clayton                                                          variables_bounds.size.height);
425044d93782SGreg Clayton                         }
425144d93782SGreg Clayton                         else
425244d93782SGreg Clayton                         {
425344d93782SGreg Clayton                             // We have no variables window showing so give the bottom
425444d93782SGreg Clayton                             // area back to the source view
425544d93782SGreg Clayton                             source_window_sp->Resize (source_bounds.size.width,
425644d93782SGreg Clayton                                                       source_bounds.size.height + registers_window_sp->GetHeight());
425744d93782SGreg Clayton                         }
425844d93782SGreg Clayton                         main_window_sp->RemoveSubWindow(registers_window_sp.get());
425944d93782SGreg Clayton                     }
426044d93782SGreg Clayton                     else
426144d93782SGreg Clayton                     {
426244d93782SGreg Clayton                         Rect new_regs_rect;
426344d93782SGreg Clayton                         if (variables_window_sp)
426444d93782SGreg Clayton                         {
426544d93782SGreg Clayton                             // We have a variables window, split it into two columns
426644d93782SGreg Clayton                             // where the left hand side will be the variables and the
426744d93782SGreg Clayton                             // right hand side will be the registers
426844d93782SGreg Clayton                             const Rect variables_bounds = variables_window_sp->GetBounds();
426944d93782SGreg Clayton                             Rect new_vars_rect;
427044d93782SGreg Clayton                             variables_bounds.VerticalSplitPercentage (0.50, new_vars_rect, new_regs_rect);
427144d93782SGreg Clayton                             variables_window_sp->SetBounds (new_vars_rect);
427244d93782SGreg Clayton                         }
427344d93782SGreg Clayton                         else
427444d93782SGreg Clayton                         {
427544d93782SGreg Clayton                             // No registers window, grab the bottom part of the source window
427644d93782SGreg Clayton                             Rect new_source_rect;
427744d93782SGreg Clayton                             source_bounds.HorizontalSplitPercentage (0.70, new_source_rect, new_regs_rect);
427844d93782SGreg Clayton                             source_window_sp->SetBounds (new_source_rect);
427944d93782SGreg Clayton                         }
428044d93782SGreg Clayton                         WindowSP new_window_sp = main_window_sp->CreateSubWindow ("Registers",
428144d93782SGreg Clayton                                                                                   new_regs_rect,
428244d93782SGreg Clayton                                                                                   false);
428344d93782SGreg Clayton                         new_window_sp->SetDelegate (WindowDelegateSP(new RegistersWindowDelegate(m_debugger)));
428444d93782SGreg Clayton                     }
428544d93782SGreg Clayton                     touchwin(stdscr);
428644d93782SGreg Clayton                 }
428744d93782SGreg Clayton                 return MenuActionResult::Handled;
428844d93782SGreg Clayton 
428944d93782SGreg Clayton             case eMenuID_HelpGUIHelp:
4290*5fdb09bbSGreg Clayton                 m_app.GetMainWindow ()->CreateHelpSubwindow();
429144d93782SGreg Clayton                 return MenuActionResult::Handled;
429244d93782SGreg Clayton 
429344d93782SGreg Clayton             default:
429444d93782SGreg Clayton                 break;
429544d93782SGreg Clayton         }
429644d93782SGreg Clayton 
429744d93782SGreg Clayton         return MenuActionResult::NotHandled;
429844d93782SGreg Clayton     }
429944d93782SGreg Clayton protected:
430044d93782SGreg Clayton     Application &m_app;
430144d93782SGreg Clayton     Debugger &m_debugger;
430244d93782SGreg Clayton };
430344d93782SGreg Clayton 
430444d93782SGreg Clayton 
430544d93782SGreg Clayton class StatusBarWindowDelegate : public WindowDelegate
430644d93782SGreg Clayton {
430744d93782SGreg Clayton public:
430844d93782SGreg Clayton     StatusBarWindowDelegate (Debugger &debugger) :
430944d93782SGreg Clayton         m_debugger (debugger)
431044d93782SGreg Clayton     {
431144d93782SGreg Clayton     }
431244d93782SGreg Clayton 
431344d93782SGreg Clayton     virtual
431444d93782SGreg Clayton     ~StatusBarWindowDelegate ()
431544d93782SGreg Clayton     {
431644d93782SGreg Clayton     }
431744d93782SGreg Clayton     virtual bool
431844d93782SGreg Clayton     WindowDelegateDraw (Window &window, bool force)
431944d93782SGreg Clayton     {
432044d93782SGreg Clayton         ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
432144d93782SGreg Clayton         Process *process = exe_ctx.GetProcessPtr();
432244d93782SGreg Clayton         Thread *thread = exe_ctx.GetThreadPtr();
432344d93782SGreg Clayton         StackFrame *frame = exe_ctx.GetFramePtr();
432444d93782SGreg Clayton         window.Erase();
432544d93782SGreg Clayton         window.SetBackground(2);
432644d93782SGreg Clayton         window.MoveCursor (0, 0);
432744d93782SGreg Clayton         if (process)
432844d93782SGreg Clayton         {
432944d93782SGreg Clayton             const StateType state = process->GetState();
433044d93782SGreg Clayton             window.Printf ("Process: %5" PRIu64 " %10s", process->GetID(), StateAsCString(state));
433144d93782SGreg Clayton 
433244d93782SGreg Clayton             if (StateIsStoppedState(state, true))
433344d93782SGreg Clayton             {
433444d93782SGreg Clayton                 window.MoveCursor (40, 0);
433544d93782SGreg Clayton                 if (thread)
433644d93782SGreg Clayton                     window.Printf ("Thread: 0x%4.4" PRIx64, thread->GetID());
433744d93782SGreg Clayton 
433844d93782SGreg Clayton                 window.MoveCursor (60, 0);
433944d93782SGreg Clayton                 if (frame)
434044d93782SGreg Clayton                     window.Printf ("Frame: %3u  PC = 0x%16.16" PRIx64, frame->GetFrameIndex(), frame->GetFrameCodeAddress().GetOpcodeLoadAddress (exe_ctx.GetTargetPtr()));
434144d93782SGreg Clayton             }
434244d93782SGreg Clayton             else if (state == eStateExited)
434344d93782SGreg Clayton             {
434444d93782SGreg Clayton                 const char *exit_desc = process->GetExitDescription();
434544d93782SGreg Clayton                 const int exit_status = process->GetExitStatus();
434644d93782SGreg Clayton                 if (exit_desc && exit_desc[0])
434744d93782SGreg Clayton                     window.Printf (" with status = %i (%s)", exit_status, exit_desc);
434844d93782SGreg Clayton                 else
434944d93782SGreg Clayton                     window.Printf (" with status = %i", exit_status);
435044d93782SGreg Clayton             }
435144d93782SGreg Clayton         }
435244d93782SGreg Clayton         window.DeferredRefresh();
435344d93782SGreg Clayton         return true;
435444d93782SGreg Clayton     }
435544d93782SGreg Clayton 
435644d93782SGreg Clayton protected:
435744d93782SGreg Clayton     Debugger &m_debugger;
435844d93782SGreg Clayton };
435944d93782SGreg Clayton 
436044d93782SGreg Clayton class SourceFileWindowDelegate : public WindowDelegate
436144d93782SGreg Clayton {
436244d93782SGreg Clayton public:
436344d93782SGreg Clayton     SourceFileWindowDelegate (Debugger &debugger) :
436444d93782SGreg Clayton         WindowDelegate (),
436544d93782SGreg Clayton         m_debugger (debugger),
436644d93782SGreg Clayton         m_sc (),
436744d93782SGreg Clayton         m_file_sp (),
436844d93782SGreg Clayton         m_disassembly_scope (NULL),
436944d93782SGreg Clayton         m_disassembly_sp (),
437044d93782SGreg Clayton         m_disassembly_range (),
437144d93782SGreg Clayton         m_line_width (4),
437244d93782SGreg Clayton         m_selected_line (0),
437344d93782SGreg Clayton         m_pc_line (0),
437444d93782SGreg Clayton         m_stop_id (0),
437544d93782SGreg Clayton         m_frame_idx (UINT32_MAX),
437644d93782SGreg Clayton         m_first_visible_line (0),
437744d93782SGreg Clayton         m_min_x (0),
437844d93782SGreg Clayton         m_min_y (0),
437944d93782SGreg Clayton         m_max_x (0),
438044d93782SGreg Clayton         m_max_y (0)
438144d93782SGreg Clayton     {
438244d93782SGreg Clayton     }
438344d93782SGreg Clayton 
438444d93782SGreg Clayton 
438544d93782SGreg Clayton     virtual
438644d93782SGreg Clayton     ~SourceFileWindowDelegate()
438744d93782SGreg Clayton     {
438844d93782SGreg Clayton     }
438944d93782SGreg Clayton 
439044d93782SGreg Clayton     void
439144d93782SGreg Clayton     Update (const SymbolContext &sc)
439244d93782SGreg Clayton     {
439344d93782SGreg Clayton         m_sc = sc;
439444d93782SGreg Clayton     }
439544d93782SGreg Clayton 
439644d93782SGreg Clayton     uint32_t
439744d93782SGreg Clayton     NumVisibleLines () const
439844d93782SGreg Clayton     {
439944d93782SGreg Clayton         return m_max_y - m_min_y;
440044d93782SGreg Clayton     }
440144d93782SGreg Clayton 
440244d93782SGreg Clayton     virtual const char *
440344d93782SGreg Clayton     WindowDelegateGetHelpText ()
440444d93782SGreg Clayton     {
440544d93782SGreg Clayton         return "Source/Disassembly window keyboard shortcuts:";
440644d93782SGreg Clayton     }
440744d93782SGreg Clayton 
440844d93782SGreg Clayton     virtual KeyHelp *
440944d93782SGreg Clayton     WindowDelegateGetKeyHelp ()
441044d93782SGreg Clayton     {
441144d93782SGreg Clayton         static curses::KeyHelp g_source_view_key_help[] = {
441244d93782SGreg Clayton             { KEY_RETURN, "Run to selected line with one shot breakpoint" },
441344d93782SGreg Clayton             { KEY_UP, "Select previous source line" },
441444d93782SGreg Clayton             { KEY_DOWN, "Select next source line" },
441544d93782SGreg Clayton             { KEY_PPAGE, "Page up" },
441644d93782SGreg Clayton             { KEY_NPAGE, "Page down" },
441744d93782SGreg Clayton             { 'b', "Set breakpoint on selected source/disassembly line" },
441844d93782SGreg Clayton             { 'c', "Continue process" },
441944d93782SGreg Clayton             { 'd', "Detach and resume process" },
442044d93782SGreg Clayton             { 'D', "Detach with process suspended" },
442144d93782SGreg Clayton             { 'h', "Show help dialog" },
442244d93782SGreg Clayton             { 'k', "Kill process" },
442344d93782SGreg Clayton             { 'n', "Step over (source line)" },
442444d93782SGreg Clayton             { 'N', "Step over (single instruction)" },
442544d93782SGreg Clayton             { 'o', "Step out" },
442644d93782SGreg Clayton             { 's', "Step in (source line)" },
442744d93782SGreg Clayton             { 'S', "Step in (single instruction)" },
442844d93782SGreg Clayton             { ',', "Page up" },
442944d93782SGreg Clayton             { '.', "Page down" },
443044d93782SGreg Clayton             { '\0', NULL }
443144d93782SGreg Clayton         };
443244d93782SGreg Clayton         return g_source_view_key_help;
443344d93782SGreg Clayton     }
443444d93782SGreg Clayton 
443544d93782SGreg Clayton     virtual bool
443644d93782SGreg Clayton     WindowDelegateDraw (Window &window, bool force)
443744d93782SGreg Clayton     {
443844d93782SGreg Clayton         ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
443944d93782SGreg Clayton         Process *process = exe_ctx.GetProcessPtr();
444044d93782SGreg Clayton         Thread *thread = NULL;
444144d93782SGreg Clayton 
444244d93782SGreg Clayton         bool update_location = false;
444344d93782SGreg Clayton         if (process)
444444d93782SGreg Clayton         {
444544d93782SGreg Clayton             StateType state = process->GetState();
444644d93782SGreg Clayton             if (StateIsStoppedState(state, true))
444744d93782SGreg Clayton             {
444844d93782SGreg Clayton                 // We are stopped, so it is ok to
444944d93782SGreg Clayton                 update_location = true;
445044d93782SGreg Clayton             }
445144d93782SGreg Clayton         }
445244d93782SGreg Clayton 
445344d93782SGreg Clayton         m_min_x = 1;
445444d93782SGreg Clayton         m_min_y = 1;
445544d93782SGreg Clayton         m_max_x = window.GetMaxX()-1;
445644d93782SGreg Clayton         m_max_y = window.GetMaxY()-1;
445744d93782SGreg Clayton 
445844d93782SGreg Clayton         const uint32_t num_visible_lines = NumVisibleLines();
445944d93782SGreg Clayton         StackFrameSP frame_sp;
446044d93782SGreg Clayton         bool set_selected_line_to_pc = false;
446144d93782SGreg Clayton 
446244d93782SGreg Clayton 
446344d93782SGreg Clayton         if (update_location)
446444d93782SGreg Clayton         {
446544d93782SGreg Clayton 
446644d93782SGreg Clayton             const bool process_alive = process ? process->IsAlive() : false;
446744d93782SGreg Clayton             bool thread_changed = false;
446844d93782SGreg Clayton             if (process_alive)
446944d93782SGreg Clayton             {
447044d93782SGreg Clayton                 thread = exe_ctx.GetThreadPtr();
447144d93782SGreg Clayton                 if (thread)
447244d93782SGreg Clayton                 {
447344d93782SGreg Clayton                     frame_sp = thread->GetSelectedFrame();
447444d93782SGreg Clayton                     auto tid = thread->GetID();
447544d93782SGreg Clayton                     thread_changed = tid != m_tid;
447644d93782SGreg Clayton                     m_tid = tid;
447744d93782SGreg Clayton                 }
447844d93782SGreg Clayton                 else
447944d93782SGreg Clayton                 {
448044d93782SGreg Clayton                     if (m_tid != LLDB_INVALID_THREAD_ID)
448144d93782SGreg Clayton                     {
448244d93782SGreg Clayton                         thread_changed = true;
448344d93782SGreg Clayton                         m_tid = LLDB_INVALID_THREAD_ID;
448444d93782SGreg Clayton                     }
448544d93782SGreg Clayton                 }
448644d93782SGreg Clayton             }
448744d93782SGreg Clayton             const uint32_t stop_id = process ? process->GetStopID() : 0;
448844d93782SGreg Clayton             const bool stop_id_changed = stop_id != m_stop_id;
448944d93782SGreg Clayton             bool frame_changed = false;
449044d93782SGreg Clayton             m_stop_id = stop_id;
449144d93782SGreg Clayton             if (frame_sp)
449244d93782SGreg Clayton             {
449344d93782SGreg Clayton                 m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
449444d93782SGreg Clayton                 const uint32_t frame_idx = frame_sp->GetFrameIndex();
449544d93782SGreg Clayton                 frame_changed = frame_idx != m_frame_idx;
449644d93782SGreg Clayton                 m_frame_idx = frame_idx;
449744d93782SGreg Clayton             }
449844d93782SGreg Clayton             else
449944d93782SGreg Clayton             {
450044d93782SGreg Clayton                 m_sc.Clear(true);
450144d93782SGreg Clayton                 frame_changed = m_frame_idx != UINT32_MAX;
450244d93782SGreg Clayton                 m_frame_idx = UINT32_MAX;
450344d93782SGreg Clayton             }
450444d93782SGreg Clayton 
450544d93782SGreg Clayton             const bool context_changed = thread_changed || frame_changed || stop_id_changed;
450644d93782SGreg Clayton 
450744d93782SGreg Clayton             if (process_alive)
450844d93782SGreg Clayton             {
450944d93782SGreg Clayton                 if (m_sc.line_entry.IsValid())
451044d93782SGreg Clayton                 {
451144d93782SGreg Clayton                     m_pc_line = m_sc.line_entry.line;
451244d93782SGreg Clayton                     if (m_pc_line != UINT32_MAX)
451344d93782SGreg Clayton                         --m_pc_line; // Convert to zero based line number...
451444d93782SGreg Clayton                     // Update the selected line if the stop ID changed...
451544d93782SGreg Clayton                     if (context_changed)
451644d93782SGreg Clayton                         m_selected_line = m_pc_line;
451744d93782SGreg Clayton 
451844d93782SGreg Clayton                     if (m_file_sp && m_file_sp->FileSpecMatches(m_sc.line_entry.file))
451944d93782SGreg Clayton                     {
452044d93782SGreg Clayton                         // Same file, nothing to do, we should either have the
452144d93782SGreg Clayton                         // lines or not (source file missing)
452244d93782SGreg Clayton                         if (m_selected_line >= m_first_visible_line)
452344d93782SGreg Clayton                         {
452444d93782SGreg Clayton                             if (m_selected_line >= m_first_visible_line + num_visible_lines)
452544d93782SGreg Clayton                                 m_first_visible_line = m_selected_line - 10;
452644d93782SGreg Clayton                         }
452744d93782SGreg Clayton                         else
452844d93782SGreg Clayton                         {
452944d93782SGreg Clayton                             if (m_selected_line > 10)
453044d93782SGreg Clayton                                 m_first_visible_line = m_selected_line - 10;
453144d93782SGreg Clayton                             else
453244d93782SGreg Clayton                                 m_first_visible_line = 0;
453344d93782SGreg Clayton                         }
453444d93782SGreg Clayton                     }
453544d93782SGreg Clayton                     else
453644d93782SGreg Clayton                     {
453744d93782SGreg Clayton                         // File changed, set selected line to the line with the PC
453844d93782SGreg Clayton                         m_selected_line = m_pc_line;
453944d93782SGreg Clayton                         m_file_sp = m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file);
454044d93782SGreg Clayton                         if (m_file_sp)
454144d93782SGreg Clayton                         {
454244d93782SGreg Clayton                             const size_t num_lines = m_file_sp->GetNumLines();
454344d93782SGreg Clayton                             int m_line_width = 1;
454444d93782SGreg Clayton                             for (size_t n = num_lines; n >= 10; n = n / 10)
454544d93782SGreg Clayton                                 ++m_line_width;
454644d93782SGreg Clayton 
454744d93782SGreg Clayton                             snprintf (m_line_format, sizeof(m_line_format), " %%%iu ", m_line_width);
454844d93782SGreg Clayton                             if (num_lines < num_visible_lines || m_selected_line < num_visible_lines)
454944d93782SGreg Clayton                                 m_first_visible_line = 0;
455044d93782SGreg Clayton                             else
455144d93782SGreg Clayton                                 m_first_visible_line = m_selected_line - 10;
455244d93782SGreg Clayton                         }
455344d93782SGreg Clayton                     }
455444d93782SGreg Clayton                 }
455544d93782SGreg Clayton                 else
455644d93782SGreg Clayton                 {
455744d93782SGreg Clayton                     m_file_sp.reset();
455844d93782SGreg Clayton                 }
455944d93782SGreg Clayton 
456044d93782SGreg Clayton                 if (!m_file_sp || m_file_sp->GetNumLines() == 0)
456144d93782SGreg Clayton                 {
456244d93782SGreg Clayton                     // Show disassembly
456344d93782SGreg Clayton                     bool prefer_file_cache = false;
456444d93782SGreg Clayton                     if (m_sc.function)
456544d93782SGreg Clayton                     {
456644d93782SGreg Clayton                         if (m_disassembly_scope != m_sc.function)
456744d93782SGreg Clayton                         {
456844d93782SGreg Clayton                             m_disassembly_scope = m_sc.function;
456944d93782SGreg Clayton                             m_disassembly_sp = m_sc.function->GetInstructions (exe_ctx, NULL, prefer_file_cache);
457044d93782SGreg Clayton                             if (m_disassembly_sp)
457144d93782SGreg Clayton                             {
457244d93782SGreg Clayton                                 set_selected_line_to_pc = true;
457344d93782SGreg Clayton                                 m_disassembly_range = m_sc.function->GetAddressRange();
457444d93782SGreg Clayton                             }
457544d93782SGreg Clayton                             else
457644d93782SGreg Clayton                             {
457744d93782SGreg Clayton                                 m_disassembly_range.Clear();
457844d93782SGreg Clayton                             }
457944d93782SGreg Clayton                         }
458044d93782SGreg Clayton                         else
458144d93782SGreg Clayton                         {
458244d93782SGreg Clayton                             set_selected_line_to_pc = context_changed;
458344d93782SGreg Clayton                         }
458444d93782SGreg Clayton                     }
458544d93782SGreg Clayton                     else if (m_sc.symbol)
458644d93782SGreg Clayton                     {
458744d93782SGreg Clayton                         if (m_disassembly_scope != m_sc.symbol)
458844d93782SGreg Clayton                         {
458944d93782SGreg Clayton                             m_disassembly_scope = m_sc.symbol;
459044d93782SGreg Clayton                             m_disassembly_sp = m_sc.symbol->GetInstructions (exe_ctx, NULL, prefer_file_cache);
459144d93782SGreg Clayton                             if (m_disassembly_sp)
459244d93782SGreg Clayton                             {
459344d93782SGreg Clayton                                 set_selected_line_to_pc = true;
459444d93782SGreg Clayton                                 m_disassembly_range.GetBaseAddress() = m_sc.symbol->GetAddress();
459544d93782SGreg Clayton                                 m_disassembly_range.SetByteSize(m_sc.symbol->GetByteSize());
459644d93782SGreg Clayton                             }
459744d93782SGreg Clayton                             else
459844d93782SGreg Clayton                             {
459944d93782SGreg Clayton                                 m_disassembly_range.Clear();
460044d93782SGreg Clayton                             }
460144d93782SGreg Clayton                         }
460244d93782SGreg Clayton                         else
460344d93782SGreg Clayton                         {
460444d93782SGreg Clayton                             set_selected_line_to_pc = context_changed;
460544d93782SGreg Clayton                         }
460644d93782SGreg Clayton                     }
460744d93782SGreg Clayton                 }
460844d93782SGreg Clayton             }
460944d93782SGreg Clayton             else
461044d93782SGreg Clayton             {
461144d93782SGreg Clayton                 m_pc_line = UINT32_MAX;
461244d93782SGreg Clayton             }
461344d93782SGreg Clayton         }
461444d93782SGreg Clayton 
461544d93782SGreg Clayton 
461644d93782SGreg Clayton         window.Erase();
461744d93782SGreg Clayton         window.DrawTitleBox ("Sources");
461844d93782SGreg Clayton 
461944d93782SGreg Clayton 
462044d93782SGreg Clayton         Target *target = exe_ctx.GetTargetPtr();
462144d93782SGreg Clayton         const size_t num_source_lines = GetNumSourceLines();
462244d93782SGreg Clayton         if (num_source_lines > 0)
462344d93782SGreg Clayton         {
462444d93782SGreg Clayton             // Display source
462544d93782SGreg Clayton             BreakpointLines bp_lines;
462644d93782SGreg Clayton             if (target)
462744d93782SGreg Clayton             {
462844d93782SGreg Clayton                 BreakpointList &bp_list = target->GetBreakpointList();
462944d93782SGreg Clayton                 const size_t num_bps = bp_list.GetSize();
463044d93782SGreg Clayton                 for (size_t bp_idx=0; bp_idx<num_bps; ++bp_idx)
463144d93782SGreg Clayton                 {
463244d93782SGreg Clayton                     BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx);
463344d93782SGreg Clayton                     const size_t num_bps_locs = bp_sp->GetNumLocations();
463444d93782SGreg Clayton                     for (size_t bp_loc_idx=0; bp_loc_idx<num_bps_locs; ++bp_loc_idx)
463544d93782SGreg Clayton                     {
463644d93782SGreg Clayton                         BreakpointLocationSP bp_loc_sp = bp_sp->GetLocationAtIndex(bp_loc_idx);
463744d93782SGreg Clayton                         LineEntry bp_loc_line_entry;
463844d93782SGreg Clayton                         if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry (bp_loc_line_entry))
463944d93782SGreg Clayton                         {
464044d93782SGreg Clayton                             if (m_file_sp->GetFileSpec() == bp_loc_line_entry.file)
464144d93782SGreg Clayton                             {
464244d93782SGreg Clayton                                 bp_lines.insert(bp_loc_line_entry.line);
464344d93782SGreg Clayton                             }
464444d93782SGreg Clayton                         }
464544d93782SGreg Clayton                     }
464644d93782SGreg Clayton                 }
464744d93782SGreg Clayton             }
464844d93782SGreg Clayton 
464944d93782SGreg Clayton 
465044d93782SGreg Clayton             const attr_t selected_highlight_attr = A_REVERSE;
465144d93782SGreg Clayton             const attr_t pc_highlight_attr = COLOR_PAIR(1);
465244d93782SGreg Clayton 
465344d93782SGreg Clayton             for (int i=0; i<num_visible_lines; ++i)
465444d93782SGreg Clayton             {
465544d93782SGreg Clayton                 const uint32_t curr_line = m_first_visible_line + i;
465644d93782SGreg Clayton                 if (curr_line < num_source_lines)
465744d93782SGreg Clayton                 {
465844d93782SGreg Clayton                     const int line_y = 1+i;
465944d93782SGreg Clayton                     window.MoveCursor(1, line_y);
466044d93782SGreg Clayton                     const bool is_pc_line = curr_line == m_pc_line;
466144d93782SGreg Clayton                     const bool line_is_selected = m_selected_line == curr_line;
466244d93782SGreg Clayton                     // Highlight the line as the PC line first, then if the selected line
466344d93782SGreg Clayton                     // isn't the same as the PC line, highlight it differently
466444d93782SGreg Clayton                     attr_t highlight_attr = 0;
466544d93782SGreg Clayton                     attr_t bp_attr = 0;
466644d93782SGreg Clayton                     if (is_pc_line)
466744d93782SGreg Clayton                         highlight_attr = pc_highlight_attr;
466844d93782SGreg Clayton                     else if (line_is_selected)
466944d93782SGreg Clayton                         highlight_attr = selected_highlight_attr;
467044d93782SGreg Clayton 
467144d93782SGreg Clayton                     if (bp_lines.find(curr_line+1) != bp_lines.end())
467244d93782SGreg Clayton                         bp_attr = COLOR_PAIR(2);
467344d93782SGreg Clayton 
467444d93782SGreg Clayton                     if (bp_attr)
467544d93782SGreg Clayton                         window.AttributeOn(bp_attr);
467644d93782SGreg Clayton 
467744d93782SGreg Clayton                     window.Printf (m_line_format, curr_line + 1);
467844d93782SGreg Clayton 
467944d93782SGreg Clayton                     if (bp_attr)
468044d93782SGreg Clayton                         window.AttributeOff(bp_attr);
468144d93782SGreg Clayton 
468244d93782SGreg Clayton                     window.PutChar(ACS_VLINE);
468344d93782SGreg Clayton                     // Mark the line with the PC with a diamond
468444d93782SGreg Clayton                     if (is_pc_line)
468544d93782SGreg Clayton                         window.PutChar(ACS_DIAMOND);
468644d93782SGreg Clayton                     else
468744d93782SGreg Clayton                         window.PutChar(' ');
468844d93782SGreg Clayton 
468944d93782SGreg Clayton                     if (highlight_attr)
469044d93782SGreg Clayton                         window.AttributeOn(highlight_attr);
469144d93782SGreg Clayton                     const uint32_t line_len = m_file_sp->GetLineLength(curr_line + 1, false);
469244d93782SGreg Clayton                     if (line_len > 0)
469344d93782SGreg Clayton                         window.PutCString(m_file_sp->PeekLineData(curr_line + 1), line_len);
469444d93782SGreg Clayton 
469544d93782SGreg Clayton                     if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0)
469644d93782SGreg Clayton                     {
469744d93782SGreg Clayton                         StopInfoSP stop_info_sp;
469844d93782SGreg Clayton                         if (thread)
469944d93782SGreg Clayton                             stop_info_sp = thread->GetStopInfo();
470044d93782SGreg Clayton                         if (stop_info_sp)
470144d93782SGreg Clayton                         {
470244d93782SGreg Clayton                             const char *stop_description = stop_info_sp->GetDescription();
470344d93782SGreg Clayton                             if (stop_description && stop_description[0])
470444d93782SGreg Clayton                             {
470544d93782SGreg Clayton                                 size_t stop_description_len = strlen(stop_description);
470644d93782SGreg Clayton                                 int desc_x = window.GetWidth() - stop_description_len - 16;
470744d93782SGreg Clayton                                 window.Printf ("%*s", desc_x - window.GetCursorX(), "");
470844d93782SGreg Clayton                                 //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y);
470944d93782SGreg Clayton                                 window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description);
471044d93782SGreg Clayton                             }
471144d93782SGreg Clayton                         }
471244d93782SGreg Clayton                         else
471344d93782SGreg Clayton                         {
471444d93782SGreg Clayton                             window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, "");
471544d93782SGreg Clayton                         }
471644d93782SGreg Clayton                     }
471744d93782SGreg Clayton                     if (highlight_attr)
471844d93782SGreg Clayton                         window.AttributeOff(highlight_attr);
471944d93782SGreg Clayton 
472044d93782SGreg Clayton                 }
472144d93782SGreg Clayton                 else
472244d93782SGreg Clayton                 {
472344d93782SGreg Clayton                     break;
472444d93782SGreg Clayton                 }
472544d93782SGreg Clayton             }
472644d93782SGreg Clayton         }
472744d93782SGreg Clayton         else
472844d93782SGreg Clayton         {
472944d93782SGreg Clayton             size_t num_disassembly_lines = GetNumDisassemblyLines();
473044d93782SGreg Clayton             if (num_disassembly_lines > 0)
473144d93782SGreg Clayton             {
473244d93782SGreg Clayton                 // Display disassembly
473344d93782SGreg Clayton                 BreakpointAddrs bp_file_addrs;
473444d93782SGreg Clayton                 Target *target = exe_ctx.GetTargetPtr();
473544d93782SGreg Clayton                 if (target)
473644d93782SGreg Clayton                 {
473744d93782SGreg Clayton                     BreakpointList &bp_list = target->GetBreakpointList();
473844d93782SGreg Clayton                     const size_t num_bps = bp_list.GetSize();
473944d93782SGreg Clayton                     for (size_t bp_idx=0; bp_idx<num_bps; ++bp_idx)
474044d93782SGreg Clayton                     {
474144d93782SGreg Clayton                         BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx);
474244d93782SGreg Clayton                         const size_t num_bps_locs = bp_sp->GetNumLocations();
474344d93782SGreg Clayton                         for (size_t bp_loc_idx=0; bp_loc_idx<num_bps_locs; ++bp_loc_idx)
474444d93782SGreg Clayton                         {
474544d93782SGreg Clayton                             BreakpointLocationSP bp_loc_sp = bp_sp->GetLocationAtIndex(bp_loc_idx);
474644d93782SGreg Clayton                             LineEntry bp_loc_line_entry;
474744d93782SGreg Clayton                             const lldb::addr_t file_addr = bp_loc_sp->GetAddress().GetFileAddress();
474844d93782SGreg Clayton                             if (file_addr != LLDB_INVALID_ADDRESS)
474944d93782SGreg Clayton                             {
475044d93782SGreg Clayton                                 if (m_disassembly_range.ContainsFileAddress(file_addr))
475144d93782SGreg Clayton                                     bp_file_addrs.insert(file_addr);
475244d93782SGreg Clayton                             }
475344d93782SGreg Clayton                         }
475444d93782SGreg Clayton                     }
475544d93782SGreg Clayton                 }
475644d93782SGreg Clayton 
475744d93782SGreg Clayton 
475844d93782SGreg Clayton                 const attr_t selected_highlight_attr = A_REVERSE;
475944d93782SGreg Clayton                 const attr_t pc_highlight_attr = COLOR_PAIR(1);
476044d93782SGreg Clayton 
476144d93782SGreg Clayton                 StreamString strm;
476244d93782SGreg Clayton 
476344d93782SGreg Clayton                 InstructionList &insts = m_disassembly_sp->GetInstructionList();
476444d93782SGreg Clayton                 Address pc_address;
476544d93782SGreg Clayton 
476644d93782SGreg Clayton                 if (frame_sp)
476744d93782SGreg Clayton                     pc_address = frame_sp->GetFrameCodeAddress();
476844d93782SGreg Clayton                 const uint32_t pc_idx = pc_address.IsValid() ? insts.GetIndexOfInstructionAtAddress (pc_address) : UINT32_MAX;
476944d93782SGreg Clayton                 if (set_selected_line_to_pc)
477044d93782SGreg Clayton                 {
477144d93782SGreg Clayton                     m_selected_line = pc_idx;
477244d93782SGreg Clayton                 }
477344d93782SGreg Clayton 
477444d93782SGreg Clayton                 const uint32_t non_visible_pc_offset = (num_visible_lines / 5);
477544d93782SGreg Clayton                 if (m_first_visible_line >= num_disassembly_lines)
477644d93782SGreg Clayton                     m_first_visible_line = 0;
477744d93782SGreg Clayton 
477844d93782SGreg Clayton                 if (pc_idx < num_disassembly_lines)
477944d93782SGreg Clayton                 {
478044d93782SGreg Clayton                     if (pc_idx < m_first_visible_line ||
478144d93782SGreg Clayton                         pc_idx >= m_first_visible_line + num_visible_lines)
478244d93782SGreg Clayton                         m_first_visible_line = pc_idx - non_visible_pc_offset;
478344d93782SGreg Clayton                 }
478444d93782SGreg Clayton 
478544d93782SGreg Clayton                 for (size_t i=0; i<num_visible_lines; ++i)
478644d93782SGreg Clayton                 {
478744d93782SGreg Clayton                     const uint32_t inst_idx = m_first_visible_line + i;
478844d93782SGreg Clayton                     Instruction *inst = insts.GetInstructionAtIndex(inst_idx).get();
478944d93782SGreg Clayton                     if (!inst)
479044d93782SGreg Clayton                         break;
479144d93782SGreg Clayton 
479244d93782SGreg Clayton                     window.MoveCursor(1, i+1);
479344d93782SGreg Clayton                     const bool is_pc_line = frame_sp && inst_idx == pc_idx;
479444d93782SGreg Clayton                     const bool line_is_selected = m_selected_line == inst_idx;
479544d93782SGreg Clayton                     // Highlight the line as the PC line first, then if the selected line
479644d93782SGreg Clayton                     // isn't the same as the PC line, highlight it differently
479744d93782SGreg Clayton                     attr_t highlight_attr = 0;
479844d93782SGreg Clayton                     attr_t bp_attr = 0;
479944d93782SGreg Clayton                     if (is_pc_line)
480044d93782SGreg Clayton                         highlight_attr = pc_highlight_attr;
480144d93782SGreg Clayton                     else if (line_is_selected)
480244d93782SGreg Clayton                         highlight_attr = selected_highlight_attr;
480344d93782SGreg Clayton 
480444d93782SGreg Clayton                     if (bp_file_addrs.find(inst->GetAddress().GetFileAddress()) != bp_file_addrs.end())
480544d93782SGreg Clayton                         bp_attr = COLOR_PAIR(2);
480644d93782SGreg Clayton 
480744d93782SGreg Clayton                     if (bp_attr)
480844d93782SGreg Clayton                         window.AttributeOn(bp_attr);
480944d93782SGreg Clayton 
481044d93782SGreg Clayton                     window.Printf (" 0x%16.16llx ", inst->GetAddress().GetLoadAddress(target));
481144d93782SGreg Clayton 
481244d93782SGreg Clayton                     if (bp_attr)
481344d93782SGreg Clayton                         window.AttributeOff(bp_attr);
481444d93782SGreg Clayton 
481544d93782SGreg Clayton                     window.PutChar(ACS_VLINE);
481644d93782SGreg Clayton                     // Mark the line with the PC with a diamond
481744d93782SGreg Clayton                     if (is_pc_line)
481844d93782SGreg Clayton                         window.PutChar(ACS_DIAMOND);
481944d93782SGreg Clayton                     else
482044d93782SGreg Clayton                         window.PutChar(' ');
482144d93782SGreg Clayton 
482244d93782SGreg Clayton                     if (highlight_attr)
482344d93782SGreg Clayton                         window.AttributeOn(highlight_attr);
482444d93782SGreg Clayton 
482544d93782SGreg Clayton                     const char *mnemonic = inst->GetMnemonic(&exe_ctx);
482644d93782SGreg Clayton                     const char *operands = inst->GetOperands(&exe_ctx);
482744d93782SGreg Clayton                     const char *comment = inst->GetComment(&exe_ctx);
482844d93782SGreg Clayton 
482944d93782SGreg Clayton                     if (mnemonic && mnemonic[0] == '\0')
483044d93782SGreg Clayton                         mnemonic = NULL;
483144d93782SGreg Clayton                     if (operands && operands[0] == '\0')
483244d93782SGreg Clayton                         operands = NULL;
483344d93782SGreg Clayton                     if (comment && comment[0] == '\0')
483444d93782SGreg Clayton                         comment = NULL;
483544d93782SGreg Clayton 
483644d93782SGreg Clayton                     strm.Clear();
483744d93782SGreg Clayton 
483844d93782SGreg Clayton                     if (mnemonic && operands && comment)
483944d93782SGreg Clayton                         strm.Printf ("%-8s %-25s ; %s", mnemonic, operands, comment);
484044d93782SGreg Clayton                     else if (mnemonic && operands)
484144d93782SGreg Clayton                         strm.Printf ("%-8s %s", mnemonic, operands);
484244d93782SGreg Clayton                     else if (mnemonic)
484344d93782SGreg Clayton                         strm.Printf ("%s", mnemonic);
484444d93782SGreg Clayton 
484544d93782SGreg Clayton                     int right_pad = 1;
484644d93782SGreg Clayton                     window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
484744d93782SGreg Clayton 
484844d93782SGreg Clayton                     if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0)
484944d93782SGreg Clayton                     {
485044d93782SGreg Clayton                         StopInfoSP stop_info_sp;
485144d93782SGreg Clayton                         if (thread)
485244d93782SGreg Clayton                             stop_info_sp = thread->GetStopInfo();
485344d93782SGreg Clayton                         if (stop_info_sp)
485444d93782SGreg Clayton                         {
485544d93782SGreg Clayton                             const char *stop_description = stop_info_sp->GetDescription();
485644d93782SGreg Clayton                             if (stop_description && stop_description[0])
485744d93782SGreg Clayton                             {
485844d93782SGreg Clayton                                 size_t stop_description_len = strlen(stop_description);
485944d93782SGreg Clayton                                 int desc_x = window.GetWidth() - stop_description_len - 16;
486044d93782SGreg Clayton                                 window.Printf ("%*s", desc_x - window.GetCursorX(), "");
486144d93782SGreg Clayton                                 //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y);
486244d93782SGreg Clayton                                 window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description);
486344d93782SGreg Clayton                             }
486444d93782SGreg Clayton                         }
486544d93782SGreg Clayton                         else
486644d93782SGreg Clayton                         {
486744d93782SGreg Clayton                             window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, "");
486844d93782SGreg Clayton                         }
486944d93782SGreg Clayton                     }
487044d93782SGreg Clayton                     if (highlight_attr)
487144d93782SGreg Clayton                         window.AttributeOff(highlight_attr);
487244d93782SGreg Clayton                 }
487344d93782SGreg Clayton             }
487444d93782SGreg Clayton         }
487544d93782SGreg Clayton         window.DeferredRefresh();
487644d93782SGreg Clayton         return true; // Drawing handled
487744d93782SGreg Clayton     }
487844d93782SGreg Clayton 
487944d93782SGreg Clayton     size_t
488044d93782SGreg Clayton     GetNumLines ()
488144d93782SGreg Clayton     {
488244d93782SGreg Clayton         size_t num_lines = GetNumSourceLines();
488344d93782SGreg Clayton         if (num_lines == 0)
488444d93782SGreg Clayton             num_lines = GetNumDisassemblyLines();
488544d93782SGreg Clayton         return num_lines;
488644d93782SGreg Clayton     }
488744d93782SGreg Clayton 
488844d93782SGreg Clayton     size_t
488944d93782SGreg Clayton     GetNumSourceLines () const
489044d93782SGreg Clayton     {
489144d93782SGreg Clayton         if (m_file_sp)
489244d93782SGreg Clayton             return m_file_sp->GetNumLines();
489344d93782SGreg Clayton         return 0;
489444d93782SGreg Clayton     }
489544d93782SGreg Clayton     size_t
489644d93782SGreg Clayton     GetNumDisassemblyLines () const
489744d93782SGreg Clayton     {
489844d93782SGreg Clayton         if (m_disassembly_sp)
489944d93782SGreg Clayton             return m_disassembly_sp->GetInstructionList().GetSize();
490044d93782SGreg Clayton         return 0;
490144d93782SGreg Clayton     }
490244d93782SGreg Clayton 
490344d93782SGreg Clayton     virtual HandleCharResult
490444d93782SGreg Clayton     WindowDelegateHandleChar (Window &window, int c)
490544d93782SGreg Clayton     {
490644d93782SGreg Clayton         const uint32_t num_visible_lines = NumVisibleLines();
490744d93782SGreg Clayton         const size_t num_lines = GetNumLines ();
490844d93782SGreg Clayton 
490944d93782SGreg Clayton         switch (c)
491044d93782SGreg Clayton         {
491144d93782SGreg Clayton             case ',':
491244d93782SGreg Clayton             case KEY_PPAGE:
491344d93782SGreg Clayton                 // Page up key
491444d93782SGreg Clayton                 if (m_first_visible_line > num_visible_lines)
491544d93782SGreg Clayton                     m_first_visible_line -= num_visible_lines;
491644d93782SGreg Clayton                 else
491744d93782SGreg Clayton                     m_first_visible_line = 0;
491844d93782SGreg Clayton                 m_selected_line = m_first_visible_line;
491944d93782SGreg Clayton                 return eKeyHandled;
492044d93782SGreg Clayton 
492144d93782SGreg Clayton             case '.':
492244d93782SGreg Clayton             case KEY_NPAGE:
492344d93782SGreg Clayton                 // Page down key
492444d93782SGreg Clayton                 {
492544d93782SGreg Clayton                     if (m_first_visible_line + num_visible_lines < num_lines)
492644d93782SGreg Clayton                         m_first_visible_line += num_visible_lines;
492744d93782SGreg Clayton                     else if (num_lines < num_visible_lines)
492844d93782SGreg Clayton                         m_first_visible_line = 0;
492944d93782SGreg Clayton                     else
493044d93782SGreg Clayton                         m_first_visible_line = num_lines - num_visible_lines;
493144d93782SGreg Clayton                     m_selected_line = m_first_visible_line;
493244d93782SGreg Clayton                 }
493344d93782SGreg Clayton                 return eKeyHandled;
493444d93782SGreg Clayton 
493544d93782SGreg Clayton             case KEY_UP:
493644d93782SGreg Clayton                 if (m_selected_line > 0)
493744d93782SGreg Clayton                 {
493844d93782SGreg Clayton                     m_selected_line--;
493944d93782SGreg Clayton                     if (m_first_visible_line > m_selected_line)
494044d93782SGreg Clayton                         m_first_visible_line = m_selected_line;
494144d93782SGreg Clayton                 }
494244d93782SGreg Clayton                 return eKeyHandled;
494344d93782SGreg Clayton 
494444d93782SGreg Clayton             case KEY_DOWN:
494544d93782SGreg Clayton                 if (m_selected_line + 1 < num_lines)
494644d93782SGreg Clayton                 {
494744d93782SGreg Clayton                     m_selected_line++;
494844d93782SGreg Clayton                     if (m_first_visible_line + num_visible_lines < m_selected_line)
494944d93782SGreg Clayton                         m_first_visible_line++;
495044d93782SGreg Clayton                 }
495144d93782SGreg Clayton                 return eKeyHandled;
495244d93782SGreg Clayton 
495344d93782SGreg Clayton             case '\r':
495444d93782SGreg Clayton             case '\n':
495544d93782SGreg Clayton             case KEY_ENTER:
495644d93782SGreg Clayton                 // Set a breakpoint and run to the line using a one shot breakpoint
495744d93782SGreg Clayton                 if (GetNumSourceLines() > 0)
495844d93782SGreg Clayton                 {
495944d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
496044d93782SGreg Clayton                     if (exe_ctx.HasProcessScope() && exe_ctx.GetProcessRef().IsAlive())
496144d93782SGreg Clayton                     {
496244d93782SGreg Clayton                         BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (NULL,                      // Don't limit the breakpoint to certain modules
496344d93782SGreg Clayton                                                                                       m_file_sp->GetFileSpec(),  // Source file
496444d93782SGreg Clayton                                                                                       m_selected_line + 1,       // Source line number (m_selected_line is zero based)
496544d93782SGreg Clayton                                                                                       eLazyBoolCalculate,        // Check inlines using global setting
496644d93782SGreg Clayton                                                                                       eLazyBoolCalculate,        // Skip prologue using global setting,
496744d93782SGreg Clayton                                                                                       false,                     // internal
496844d93782SGreg Clayton                                                                                       false);                    // request_hardware
496944d93782SGreg Clayton                         // Make breakpoint one shot
497044d93782SGreg Clayton                         bp_sp->GetOptions()->SetOneShot(true);
497144d93782SGreg Clayton                         exe_ctx.GetProcessRef().Resume();
497244d93782SGreg Clayton                     }
497344d93782SGreg Clayton                 }
497444d93782SGreg Clayton                 else if (m_selected_line < GetNumDisassemblyLines())
497544d93782SGreg Clayton                 {
497644d93782SGreg Clayton                     const Instruction *inst = m_disassembly_sp->GetInstructionList().GetInstructionAtIndex(m_selected_line).get();
497744d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
497844d93782SGreg Clayton                     if (exe_ctx.HasTargetScope())
497944d93782SGreg Clayton                     {
498044d93782SGreg Clayton                         Address addr = inst->GetAddress();
498144d93782SGreg Clayton                         BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (addr,     // lldb_private::Address
498244d93782SGreg Clayton                                                                                       false,    // internal
498344d93782SGreg Clayton                                                                                       false);   // request_hardware
498444d93782SGreg Clayton                         // Make breakpoint one shot
498544d93782SGreg Clayton                         bp_sp->GetOptions()->SetOneShot(true);
498644d93782SGreg Clayton                         exe_ctx.GetProcessRef().Resume();
498744d93782SGreg Clayton                     }
498844d93782SGreg Clayton                 }
498944d93782SGreg Clayton                 return eKeyHandled;
499044d93782SGreg Clayton 
499144d93782SGreg Clayton             case 'b':   // 'b' == toggle breakpoint on currently selected line
499244d93782SGreg Clayton                 if (m_selected_line < GetNumSourceLines())
499344d93782SGreg Clayton                 {
499444d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
499544d93782SGreg Clayton                     if (exe_ctx.HasTargetScope())
499644d93782SGreg Clayton                     {
499744d93782SGreg Clayton                         BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (NULL,                      // Don't limit the breakpoint to certain modules
499844d93782SGreg Clayton                                                                                       m_file_sp->GetFileSpec(),  // Source file
499944d93782SGreg Clayton                                                                                       m_selected_line + 1,       // Source line number (m_selected_line is zero based)
500044d93782SGreg Clayton                                                                                       eLazyBoolCalculate,        // Check inlines using global setting
500144d93782SGreg Clayton                                                                                       eLazyBoolCalculate,        // Skip prologue using global setting,
500244d93782SGreg Clayton                                                                                       false,                     // internal
500344d93782SGreg Clayton                                                                                       false);                    // request_hardware
500444d93782SGreg Clayton                     }
500544d93782SGreg Clayton                 }
500644d93782SGreg Clayton                 else if (m_selected_line < GetNumDisassemblyLines())
500744d93782SGreg Clayton                 {
500844d93782SGreg Clayton                     const Instruction *inst = m_disassembly_sp->GetInstructionList().GetInstructionAtIndex(m_selected_line).get();
500944d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
501044d93782SGreg Clayton                     if (exe_ctx.HasTargetScope())
501144d93782SGreg Clayton                     {
501244d93782SGreg Clayton                         Address addr = inst->GetAddress();
501344d93782SGreg Clayton                         BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (addr,     // lldb_private::Address
501444d93782SGreg Clayton                                                                                       false,    // internal
501544d93782SGreg Clayton                                                                                       false);   // request_hardware
501644d93782SGreg Clayton                     }
501744d93782SGreg Clayton                 }
501844d93782SGreg Clayton                 return eKeyHandled;
501944d93782SGreg Clayton 
502044d93782SGreg Clayton             case 'd':   // 'd' == detach and let run
502144d93782SGreg Clayton             case 'D':   // 'D' == detach and keep stopped
502244d93782SGreg Clayton                 {
502344d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
502444d93782SGreg Clayton                     if (exe_ctx.HasProcessScope())
502544d93782SGreg Clayton                         exe_ctx.GetProcessRef().Detach(c == 'D');
502644d93782SGreg Clayton                 }
502744d93782SGreg Clayton                 return eKeyHandled;
502844d93782SGreg Clayton 
502944d93782SGreg Clayton             case 'k':
503044d93782SGreg Clayton                 // 'k' == kill
503144d93782SGreg Clayton                 {
503244d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
503344d93782SGreg Clayton                     if (exe_ctx.HasProcessScope())
503444d93782SGreg Clayton                         exe_ctx.GetProcessRef().Destroy();
503544d93782SGreg Clayton                 }
503644d93782SGreg Clayton                 return eKeyHandled;
503744d93782SGreg Clayton 
503844d93782SGreg Clayton             case 'c':
503944d93782SGreg Clayton                 // 'c' == continue
504044d93782SGreg Clayton                 {
504144d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
504244d93782SGreg Clayton                     if (exe_ctx.HasProcessScope())
504344d93782SGreg Clayton                         exe_ctx.GetProcessRef().Resume();
504444d93782SGreg Clayton                 }
504544d93782SGreg Clayton                 return eKeyHandled;
504644d93782SGreg Clayton 
504744d93782SGreg Clayton             case 'o':
504844d93782SGreg Clayton                 // 'o' == step out
504944d93782SGreg Clayton                 {
505044d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
505144d93782SGreg Clayton                     if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
505244d93782SGreg Clayton                     {
505344d93782SGreg Clayton                         exe_ctx.GetThreadRef().StepOut();
505444d93782SGreg Clayton                     }
505544d93782SGreg Clayton                 }
505644d93782SGreg Clayton                 return eKeyHandled;
505744d93782SGreg Clayton             case 'n':   // 'n' == step over
505844d93782SGreg Clayton             case 'N':   // 'N' == step over instruction
505944d93782SGreg Clayton                 {
506044d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
506144d93782SGreg Clayton                     if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
506244d93782SGreg Clayton                     {
506344d93782SGreg Clayton                         bool source_step = (c == 'n');
506444d93782SGreg Clayton                         exe_ctx.GetThreadRef().StepOver(source_step);
506544d93782SGreg Clayton                     }
506644d93782SGreg Clayton                 }
506744d93782SGreg Clayton                 return eKeyHandled;
506844d93782SGreg Clayton             case 's':   // 's' == step into
506944d93782SGreg Clayton             case 'S':   // 'S' == step into instruction
507044d93782SGreg Clayton                 {
507144d93782SGreg Clayton                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
507244d93782SGreg Clayton                     if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
507344d93782SGreg Clayton                     {
507444d93782SGreg Clayton                         bool source_step = (c == 's');
507544d93782SGreg Clayton                         bool avoid_code_without_debug_info = true;
507644d93782SGreg Clayton                         exe_ctx.GetThreadRef().StepIn(source_step, avoid_code_without_debug_info);
507744d93782SGreg Clayton                     }
507844d93782SGreg Clayton                 }
507944d93782SGreg Clayton                 return eKeyHandled;
508044d93782SGreg Clayton 
508144d93782SGreg Clayton             case 'h':
508244d93782SGreg Clayton                 window.CreateHelpSubwindow ();
508344d93782SGreg Clayton                 return eKeyHandled;
508444d93782SGreg Clayton 
508544d93782SGreg Clayton             default:
508644d93782SGreg Clayton                 break;
508744d93782SGreg Clayton         }
508844d93782SGreg Clayton         return eKeyNotHandled;
508944d93782SGreg Clayton     }
509044d93782SGreg Clayton 
509144d93782SGreg Clayton protected:
509244d93782SGreg Clayton     typedef std::set<uint32_t> BreakpointLines;
509344d93782SGreg Clayton     typedef std::set<lldb::addr_t> BreakpointAddrs;
509444d93782SGreg Clayton 
509544d93782SGreg Clayton     Debugger &m_debugger;
509644d93782SGreg Clayton     SymbolContext m_sc;
509744d93782SGreg Clayton     SourceManager::FileSP m_file_sp;
509844d93782SGreg Clayton     SymbolContextScope *m_disassembly_scope;
509944d93782SGreg Clayton     lldb::DisassemblerSP m_disassembly_sp;
510044d93782SGreg Clayton     AddressRange m_disassembly_range;
510144d93782SGreg Clayton     lldb::user_id_t m_tid;
510244d93782SGreg Clayton     char m_line_format[8];
510344d93782SGreg Clayton     int m_line_width;
510444d93782SGreg Clayton     uint32_t m_selected_line;       // The selected line
510544d93782SGreg Clayton     uint32_t m_pc_line;             // The line with the PC
510644d93782SGreg Clayton     uint32_t m_stop_id;
510744d93782SGreg Clayton     uint32_t m_frame_idx;
510844d93782SGreg Clayton     int m_first_visible_line;
510944d93782SGreg Clayton     int m_min_x;
511044d93782SGreg Clayton     int m_min_y;
511144d93782SGreg Clayton     int m_max_x;
511244d93782SGreg Clayton     int m_max_y;
511344d93782SGreg Clayton 
511444d93782SGreg Clayton };
511544d93782SGreg Clayton 
511644d93782SGreg Clayton DisplayOptions ValueObjectListDelegate::g_options = { true };
511744d93782SGreg Clayton 
511844d93782SGreg Clayton IOHandlerCursesGUI::IOHandlerCursesGUI (Debugger &debugger) :
511944d93782SGreg Clayton     IOHandler (debugger)
512044d93782SGreg Clayton {
512144d93782SGreg Clayton }
512244d93782SGreg Clayton 
512344d93782SGreg Clayton void
512444d93782SGreg Clayton IOHandlerCursesGUI::Activate ()
512544d93782SGreg Clayton {
512644d93782SGreg Clayton     IOHandler::Activate();
512744d93782SGreg Clayton     if (!m_app_ap)
512844d93782SGreg Clayton     {
512944d93782SGreg Clayton         m_app_ap.reset (new Application (GetInputFILE(), GetOutputFILE()));
513044d93782SGreg Clayton 
513144d93782SGreg Clayton 
513244d93782SGreg Clayton         // This is both a window and a menu delegate
513344d93782SGreg Clayton         std::shared_ptr<ApplicationDelegate> app_delegate_sp(new ApplicationDelegate(*m_app_ap, m_debugger));
513444d93782SGreg Clayton 
513544d93782SGreg Clayton         MenuDelegateSP app_menu_delegate_sp = std::static_pointer_cast<MenuDelegate>(app_delegate_sp);
513644d93782SGreg Clayton         MenuSP lldb_menu_sp(new Menu("LLDB" , "F1", KEY_F(1), ApplicationDelegate::eMenuID_LLDB));
513744d93782SGreg Clayton         MenuSP exit_menuitem_sp(new Menu("Exit", NULL, 'x', ApplicationDelegate::eMenuID_LLDBExit));
513844d93782SGreg Clayton         exit_menuitem_sp->SetCannedResult(MenuActionResult::Quit);
513944d93782SGreg Clayton         lldb_menu_sp->AddSubmenu (MenuSP (new Menu("About LLDB", NULL, 'a', ApplicationDelegate::eMenuID_LLDBAbout)));
514044d93782SGreg Clayton         lldb_menu_sp->AddSubmenu (MenuSP (new Menu(Menu::Type::Separator)));
514144d93782SGreg Clayton         lldb_menu_sp->AddSubmenu (exit_menuitem_sp);
514244d93782SGreg Clayton 
514344d93782SGreg Clayton         MenuSP target_menu_sp(new Menu("Target" ,"F2", KEY_F(2), ApplicationDelegate::eMenuID_Target));
514444d93782SGreg Clayton         target_menu_sp->AddSubmenu (MenuSP (new Menu("Create", NULL, 'c', ApplicationDelegate::eMenuID_TargetCreate)));
514544d93782SGreg Clayton         target_menu_sp->AddSubmenu (MenuSP (new Menu("Delete", NULL, 'd', ApplicationDelegate::eMenuID_TargetDelete)));
514644d93782SGreg Clayton 
514744d93782SGreg Clayton         MenuSP process_menu_sp(new Menu("Process", "F3", KEY_F(3), ApplicationDelegate::eMenuID_Process));
514844d93782SGreg Clayton         process_menu_sp->AddSubmenu (MenuSP (new Menu("Attach"  , NULL, 'a', ApplicationDelegate::eMenuID_ProcessAttach)));
514944d93782SGreg Clayton         process_menu_sp->AddSubmenu (MenuSP (new Menu("Detach"  , NULL, 'd', ApplicationDelegate::eMenuID_ProcessDetach)));
515044d93782SGreg Clayton         process_menu_sp->AddSubmenu (MenuSP (new Menu("Launch"  , NULL, 'l', ApplicationDelegate::eMenuID_ProcessLaunch)));
515144d93782SGreg Clayton         process_menu_sp->AddSubmenu (MenuSP (new Menu(Menu::Type::Separator)));
515244d93782SGreg Clayton         process_menu_sp->AddSubmenu (MenuSP (new Menu("Continue", NULL, 'c', ApplicationDelegate::eMenuID_ProcessContinue)));
515344d93782SGreg Clayton         process_menu_sp->AddSubmenu (MenuSP (new Menu("Halt"    , NULL, 'h', ApplicationDelegate::eMenuID_ProcessHalt)));
515444d93782SGreg Clayton         process_menu_sp->AddSubmenu (MenuSP (new Menu("Kill"    , NULL, 'k', ApplicationDelegate::eMenuID_ProcessKill)));
515544d93782SGreg Clayton 
515644d93782SGreg Clayton         MenuSP thread_menu_sp(new Menu("Thread", "F4", KEY_F(4), ApplicationDelegate::eMenuID_Thread));
515744d93782SGreg Clayton         thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step In"  , NULL, 'i', ApplicationDelegate::eMenuID_ThreadStepIn)));
515844d93782SGreg Clayton         thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step Over", NULL, 'v', ApplicationDelegate::eMenuID_ThreadStepOver)));
515944d93782SGreg Clayton         thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step Out" , NULL, 'o', ApplicationDelegate::eMenuID_ThreadStepOut)));
516044d93782SGreg Clayton 
516144d93782SGreg Clayton         MenuSP view_menu_sp(new Menu("View", "F5", KEY_F(5), ApplicationDelegate::eMenuID_View));
516244d93782SGreg Clayton         view_menu_sp->AddSubmenu (MenuSP (new Menu("Backtrace", NULL, 'b', ApplicationDelegate::eMenuID_ViewBacktrace)));
516344d93782SGreg Clayton         view_menu_sp->AddSubmenu (MenuSP (new Menu("Registers", NULL, 'r', ApplicationDelegate::eMenuID_ViewRegisters)));
516444d93782SGreg Clayton         view_menu_sp->AddSubmenu (MenuSP (new Menu("Source"   , NULL, 's', ApplicationDelegate::eMenuID_ViewSource)));
516544d93782SGreg Clayton         view_menu_sp->AddSubmenu (MenuSP (new Menu("Variables", NULL, 'v', ApplicationDelegate::eMenuID_ViewVariables)));
516644d93782SGreg Clayton 
516744d93782SGreg Clayton         MenuSP help_menu_sp(new Menu("Help", "F6", KEY_F(6), ApplicationDelegate::eMenuID_Help));
516844d93782SGreg Clayton         help_menu_sp->AddSubmenu (MenuSP (new Menu("GUI Help", NULL, 'g', ApplicationDelegate::eMenuID_HelpGUIHelp)));
516944d93782SGreg Clayton 
517044d93782SGreg Clayton         m_app_ap->Initialize();
517144d93782SGreg Clayton         WindowSP &main_window_sp = m_app_ap->GetMainWindow();
517244d93782SGreg Clayton 
517344d93782SGreg Clayton         MenuSP menubar_sp(new Menu(Menu::Type::Bar));
517444d93782SGreg Clayton         menubar_sp->AddSubmenu (lldb_menu_sp);
517544d93782SGreg Clayton         menubar_sp->AddSubmenu (target_menu_sp);
517644d93782SGreg Clayton         menubar_sp->AddSubmenu (process_menu_sp);
517744d93782SGreg Clayton         menubar_sp->AddSubmenu (thread_menu_sp);
517844d93782SGreg Clayton         menubar_sp->AddSubmenu (view_menu_sp);
517944d93782SGreg Clayton         menubar_sp->AddSubmenu (help_menu_sp);
518044d93782SGreg Clayton         menubar_sp->SetDelegate(app_menu_delegate_sp);
518144d93782SGreg Clayton 
518244d93782SGreg Clayton         Rect content_bounds = main_window_sp->GetFrame();
518344d93782SGreg Clayton         Rect menubar_bounds = content_bounds.MakeMenuBar();
518444d93782SGreg Clayton         Rect status_bounds = content_bounds.MakeStatusBar();
518544d93782SGreg Clayton         Rect source_bounds;
518644d93782SGreg Clayton         Rect variables_bounds;
518744d93782SGreg Clayton         Rect threads_bounds;
518844d93782SGreg Clayton         Rect source_variables_bounds;
518944d93782SGreg Clayton         content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds, threads_bounds);
519044d93782SGreg Clayton         source_variables_bounds.HorizontalSplitPercentage(0.70, source_bounds, variables_bounds);
519144d93782SGreg Clayton 
519244d93782SGreg Clayton         WindowSP menubar_window_sp = main_window_sp->CreateSubWindow("Menubar", menubar_bounds, false);
519344d93782SGreg Clayton         // Let the menubar get keys if the active window doesn't handle the
519444d93782SGreg Clayton         // keys that are typed so it can respond to menubar key presses.
519544d93782SGreg Clayton         menubar_window_sp->SetCanBeActive(false); // Don't let the menubar become the active window
519644d93782SGreg Clayton         menubar_window_sp->SetDelegate(menubar_sp);
519744d93782SGreg Clayton 
519844d93782SGreg Clayton         WindowSP source_window_sp (main_window_sp->CreateSubWindow("Source",
519944d93782SGreg Clayton                                                                    source_bounds,
520044d93782SGreg Clayton                                                                    true));
520144d93782SGreg Clayton         WindowSP variables_window_sp (main_window_sp->CreateSubWindow("Variables",
520244d93782SGreg Clayton                                                                       variables_bounds,
520344d93782SGreg Clayton                                                                       false));
520444d93782SGreg Clayton         WindowSP threads_window_sp (main_window_sp->CreateSubWindow("Threads",
520544d93782SGreg Clayton                                                                       threads_bounds,
520644d93782SGreg Clayton                                                                       false));
520744d93782SGreg Clayton         WindowSP status_window_sp (main_window_sp->CreateSubWindow("Status",
520844d93782SGreg Clayton                                                                    status_bounds,
520944d93782SGreg Clayton                                                                    false));
521044d93782SGreg Clayton         status_window_sp->SetCanBeActive(false); // Don't let the status bar become the active window
521144d93782SGreg Clayton         main_window_sp->SetDelegate (std::static_pointer_cast<WindowDelegate>(app_delegate_sp));
521244d93782SGreg Clayton         source_window_sp->SetDelegate (WindowDelegateSP(new SourceFileWindowDelegate(m_debugger)));
521344d93782SGreg Clayton         variables_window_sp->SetDelegate (WindowDelegateSP(new FrameVariablesWindowDelegate(m_debugger)));
521444d93782SGreg Clayton         TreeDelegateSP thread_delegate_sp (new ThreadTreeDelegate(m_debugger));
521544d93782SGreg Clayton         threads_window_sp->SetDelegate (WindowDelegateSP(new TreeWindowDelegate(m_debugger, thread_delegate_sp)));
521644d93782SGreg Clayton         status_window_sp->SetDelegate (WindowDelegateSP(new StatusBarWindowDelegate(m_debugger)));
521744d93782SGreg Clayton 
5218*5fdb09bbSGreg Clayton         // Show the main help window once the first time the curses GUI is launched
5219*5fdb09bbSGreg Clayton         static bool g_showed_help = false;
5220*5fdb09bbSGreg Clayton         if (!g_showed_help)
5221*5fdb09bbSGreg Clayton         {
5222*5fdb09bbSGreg Clayton             g_showed_help = true;
5223*5fdb09bbSGreg Clayton             main_window_sp->CreateHelpSubwindow();
5224*5fdb09bbSGreg Clayton         }
5225*5fdb09bbSGreg Clayton 
522644d93782SGreg Clayton         init_pair (1, COLOR_WHITE   , COLOR_BLUE  );
522744d93782SGreg Clayton         init_pair (2, COLOR_BLACK   , COLOR_WHITE );
522844d93782SGreg Clayton         init_pair (3, COLOR_MAGENTA , COLOR_WHITE );
522944d93782SGreg Clayton         init_pair (4, COLOR_MAGENTA , COLOR_BLACK );
523044d93782SGreg Clayton         init_pair (5, COLOR_RED     , COLOR_BLACK );
523144d93782SGreg Clayton 
523244d93782SGreg Clayton     }
523344d93782SGreg Clayton }
523444d93782SGreg Clayton 
523544d93782SGreg Clayton void
523644d93782SGreg Clayton IOHandlerCursesGUI::Deactivate ()
523744d93782SGreg Clayton {
523844d93782SGreg Clayton     m_app_ap->Terminate();
523944d93782SGreg Clayton }
524044d93782SGreg Clayton 
524144d93782SGreg Clayton void
524244d93782SGreg Clayton IOHandlerCursesGUI::Run ()
524344d93782SGreg Clayton {
524444d93782SGreg Clayton     m_app_ap->Run(m_debugger);
524544d93782SGreg Clayton     SetIsDone(true);
524644d93782SGreg Clayton }
524744d93782SGreg Clayton 
524844d93782SGreg Clayton 
524944d93782SGreg Clayton IOHandlerCursesGUI::~IOHandlerCursesGUI ()
525044d93782SGreg Clayton {
525144d93782SGreg Clayton 
525244d93782SGreg Clayton }
525344d93782SGreg Clayton 
525444d93782SGreg Clayton void
525544d93782SGreg Clayton IOHandlerCursesGUI::Hide ()
525644d93782SGreg Clayton {
525744d93782SGreg Clayton }
525844d93782SGreg Clayton 
525944d93782SGreg Clayton 
526044d93782SGreg Clayton void
526144d93782SGreg Clayton IOHandlerCursesGUI::Refresh ()
526244d93782SGreg Clayton {
526344d93782SGreg Clayton }
526444d93782SGreg Clayton 
526544d93782SGreg Clayton 
526644d93782SGreg Clayton void
526744d93782SGreg Clayton IOHandlerCursesGUI::Interrupt ()
526844d93782SGreg Clayton {
526944d93782SGreg Clayton }
527044d93782SGreg Clayton 
527144d93782SGreg Clayton 
527244d93782SGreg Clayton void
527344d93782SGreg Clayton IOHandlerCursesGUI::GotEOF()
527444d93782SGreg Clayton {
527544d93782SGreg Clayton }
527644d93782SGreg Clayton 
5277