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