1262182Semaste//===-- IOHandler.cpp -------------------------------------------*- C++ -*-===//
2262182Semaste//
3262182Semaste//                     The LLVM Compiler Infrastructure
4262182Semaste//
5262182Semaste// This file is distributed under the University of Illinois Open Source
6262182Semaste// License. See LICENSE.TXT for details.
7262182Semaste//
8262182Semaste//===----------------------------------------------------------------------===//
9262182Semaste
10262182Semaste
11262182Semaste#include "lldb/lldb-python.h"
12262182Semaste
13262182Semaste#include <string>
14262182Semaste
15262182Semaste#include "lldb/Breakpoint/BreakpointLocation.h"
16262182Semaste#include "lldb/Core/IOHandler.h"
17262182Semaste#include "lldb/Core/Debugger.h"
18262182Semaste#include "lldb/Core/State.h"
19262182Semaste#include "lldb/Core/StreamFile.h"
20262182Semaste#include "lldb/Core/ValueObjectRegister.h"
21262182Semaste#include "lldb/Host/Editline.h"
22262182Semaste#include "lldb/Interpreter/CommandCompletions.h"
23262182Semaste#include "lldb/Interpreter/CommandInterpreter.h"
24262182Semaste#include "lldb/Symbol/Block.h"
25262182Semaste#include "lldb/Symbol/Function.h"
26262182Semaste#include "lldb/Symbol/Symbol.h"
27262182Semaste#include "lldb/Target/RegisterContext.h"
28262182Semaste#include "lldb/Target/ThreadPlan.h"
29262182Semaste
30262182Semaste#ifndef LLDB_DISABLE_CURSES
31262182Semaste#include <ncurses.h>
32262182Semaste#include <panel.h>
33262182Semaste#endif
34262182Semaste
35262182Semasteusing namespace lldb;
36262182Semasteusing namespace lldb_private;
37262182Semaste
38262182SemasteIOHandler::IOHandler (Debugger &debugger) :
39262182Semaste    IOHandler (debugger,
40262182Semaste               StreamFileSP(),  // Adopt STDIN from top input reader
41262182Semaste               StreamFileSP(),  // Adopt STDOUT from top input reader
42262182Semaste               StreamFileSP(),  // Adopt STDERR from top input reader
43262182Semaste               0)               // Flags
44262182Semaste{
45262182Semaste}
46262182Semaste
47262182Semaste
48262182SemasteIOHandler::IOHandler (Debugger &debugger,
49262182Semaste                      const lldb::StreamFileSP &input_sp,
50262182Semaste                      const lldb::StreamFileSP &output_sp,
51262182Semaste                      const lldb::StreamFileSP &error_sp,
52262182Semaste                      uint32_t flags) :
53262182Semaste    m_debugger (debugger),
54262182Semaste    m_input_sp (input_sp),
55262182Semaste    m_output_sp (output_sp),
56262182Semaste    m_error_sp (error_sp),
57262182Semaste    m_flags (flags),
58262182Semaste    m_user_data (NULL),
59262182Semaste    m_done (false),
60262182Semaste    m_active (false)
61262182Semaste{
62262182Semaste    // If any files are not specified, then adopt them from the top input reader.
63262182Semaste    if (!m_input_sp || !m_output_sp || !m_error_sp)
64262182Semaste        debugger.AdoptTopIOHandlerFilesIfInvalid (m_input_sp,
65262182Semaste                                                  m_output_sp,
66262182Semaste                                                  m_error_sp);
67262182Semaste}
68262182Semaste
69262182SemasteIOHandler::~IOHandler()
70262182Semaste{
71262182Semaste}
72262182Semaste
73262182Semaste
74262182Semasteint
75262182SemasteIOHandler::GetInputFD()
76262182Semaste{
77262182Semaste    if (m_input_sp)
78262182Semaste        return m_input_sp->GetFile().GetDescriptor();
79262182Semaste    return -1;
80262182Semaste}
81262182Semaste
82262182Semasteint
83262182SemasteIOHandler::GetOutputFD()
84262182Semaste{
85262182Semaste    if (m_output_sp)
86262182Semaste        return m_output_sp->GetFile().GetDescriptor();
87262182Semaste    return -1;
88262182Semaste}
89262182Semaste
90262182Semasteint
91262182SemasteIOHandler::GetErrorFD()
92262182Semaste{
93262182Semaste    if (m_error_sp)
94262182Semaste        return m_error_sp->GetFile().GetDescriptor();
95262182Semaste    return -1;
96262182Semaste}
97262182Semaste
98262182SemasteFILE *
99262182SemasteIOHandler::GetInputFILE()
100262182Semaste{
101262182Semaste    if (m_input_sp)
102262182Semaste        return m_input_sp->GetFile().GetStream();
103262182Semaste    return NULL;
104262182Semaste}
105262182Semaste
106262182SemasteFILE *
107262182SemasteIOHandler::GetOutputFILE()
108262182Semaste{
109262182Semaste    if (m_output_sp)
110262182Semaste        return m_output_sp->GetFile().GetStream();
111262182Semaste    return NULL;
112262182Semaste}
113262182Semaste
114262182SemasteFILE *
115262182SemasteIOHandler::GetErrorFILE()
116262182Semaste{
117262182Semaste    if (m_error_sp)
118262182Semaste        return m_error_sp->GetFile().GetStream();
119262182Semaste    return NULL;
120262182Semaste}
121262182Semaste
122262182SemasteStreamFileSP &
123262182SemasteIOHandler::GetInputStreamFile()
124262182Semaste{
125262182Semaste    return m_input_sp;
126262182Semaste}
127262182Semaste
128262182SemasteStreamFileSP &
129262182SemasteIOHandler::GetOutputStreamFile()
130262182Semaste{
131262182Semaste    return m_output_sp;
132262182Semaste}
133262182Semaste
134262182Semaste
135262182SemasteStreamFileSP &
136262182SemasteIOHandler::GetErrorStreamFile()
137262182Semaste{
138262182Semaste    return m_error_sp;
139262182Semaste}
140262182Semaste
141262182Semastebool
142262182SemasteIOHandler::GetIsInteractive ()
143262182Semaste{
144262182Semaste    return GetInputStreamFile()->GetFile().GetIsInteractive ();
145262182Semaste}
146262182Semaste
147262182Semastebool
148262182SemasteIOHandler::GetIsRealTerminal ()
149262182Semaste{
150262182Semaste    return GetInputStreamFile()->GetFile().GetIsRealTerminal();
151262182Semaste}
152262182Semaste
153262182SemasteIOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
154262182Semaste                                    const char *prompt,
155262182Semaste                                    bool default_response) :
156262182Semaste    IOHandlerEditline(debugger,
157262182Semaste                      NULL,     // NULL editline_name means no history loaded/saved
158262182Semaste                      NULL,
159262182Semaste                      false,    // Multi-line
160262182Semaste                      *this),
161262182Semaste    m_default_response (default_response),
162262182Semaste    m_user_response (default_response)
163262182Semaste{
164262182Semaste    StreamString prompt_stream;
165262182Semaste    prompt_stream.PutCString(prompt);
166262182Semaste    if (m_default_response)
167262182Semaste        prompt_stream.Printf(": [Y/n] ");
168262182Semaste    else
169262182Semaste        prompt_stream.Printf(": [y/N] ");
170262182Semaste
171262182Semaste    SetPrompt (prompt_stream.GetString().c_str());
172262182Semaste
173262182Semaste}
174262182Semaste
175262182Semaste
176262182SemasteIOHandlerConfirm::~IOHandlerConfirm ()
177262182Semaste{
178262182Semaste}
179262182Semaste
180262182Semasteint
181262182SemasteIOHandlerConfirm::IOHandlerComplete (IOHandler &io_handler,
182262182Semaste                                     const char *current_line,
183262182Semaste                                     const char *cursor,
184262182Semaste                                     const char *last_char,
185262182Semaste                                     int skip_first_n_matches,
186262182Semaste                                     int max_matches,
187262182Semaste                                     StringList &matches)
188262182Semaste{
189262182Semaste    if (current_line == cursor)
190262182Semaste    {
191262182Semaste        if (m_default_response)
192262182Semaste        {
193262182Semaste            matches.AppendString("y");
194262182Semaste        }
195262182Semaste        else
196262182Semaste        {
197262182Semaste            matches.AppendString("n");
198262182Semaste        }
199262182Semaste    }
200262182Semaste    return matches.GetSize();
201262182Semaste}
202262182Semaste
203262182Semastevoid
204262182SemasteIOHandlerConfirm::IOHandlerInputComplete (IOHandler &io_handler, std::string &line)
205262182Semaste{
206262182Semaste    if (line.empty())
207262182Semaste    {
208262182Semaste        // User just hit enter, set the response to the default
209262182Semaste        m_user_response = m_default_response;
210262182Semaste        io_handler.SetIsDone(true);
211262182Semaste        return;
212262182Semaste    }
213262182Semaste
214262182Semaste    if (line.size() == 1)
215262182Semaste    {
216262182Semaste        switch (line[0])
217262182Semaste        {
218262182Semaste            case 'y':
219262182Semaste            case 'Y':
220262182Semaste                m_user_response = true;
221262182Semaste                io_handler.SetIsDone(true);
222262182Semaste                return;
223262182Semaste            case 'n':
224262182Semaste            case 'N':
225262182Semaste                m_user_response = false;
226262182Semaste                io_handler.SetIsDone(true);
227262182Semaste                return;
228262182Semaste            default:
229262182Semaste                break;
230262182Semaste        }
231262182Semaste    }
232262182Semaste
233262182Semaste    if (line == "yes" || line == "YES" || line == "Yes")
234262182Semaste    {
235262182Semaste        m_user_response = true;
236262182Semaste        io_handler.SetIsDone(true);
237262182Semaste    }
238262182Semaste    else if (line == "no" || line == "NO" || line == "No")
239262182Semaste    {
240262182Semaste        m_user_response = false;
241262182Semaste        io_handler.SetIsDone(true);
242262182Semaste    }
243262182Semaste}
244262182Semaste
245262182Semasteint
246262182SemasteIOHandlerDelegate::IOHandlerComplete (IOHandler &io_handler,
247262182Semaste                                      const char *current_line,
248262182Semaste                                      const char *cursor,
249262182Semaste                                      const char *last_char,
250262182Semaste                                      int skip_first_n_matches,
251262182Semaste                                      int max_matches,
252262182Semaste                                      StringList &matches)
253262182Semaste{
254262182Semaste    switch (m_completion)
255262182Semaste    {
256262182Semaste    case Completion::None:
257262182Semaste        break;
258262182Semaste
259262182Semaste    case Completion::LLDBCommand:
260262182Semaste        return io_handler.GetDebugger().GetCommandInterpreter().HandleCompletion (current_line,
261262182Semaste                                                                                  cursor,
262262182Semaste                                                                                  last_char,
263262182Semaste                                                                                  skip_first_n_matches,
264262182Semaste                                                                                  max_matches,
265262182Semaste                                                                                  matches);
266262182Semaste
267262182Semaste    case Completion::Expression:
268262182Semaste        {
269262182Semaste            bool word_complete = false;
270262182Semaste            const char *word_start = cursor;
271262182Semaste            if (cursor > current_line)
272262182Semaste                --word_start;
273262182Semaste            while (word_start > current_line && !isspace(*word_start))
274262182Semaste                --word_start;
275262182Semaste            CommandCompletions::InvokeCommonCompletionCallbacks (io_handler.GetDebugger().GetCommandInterpreter(),
276262182Semaste                                                                 CommandCompletions::eVariablePathCompletion,
277262182Semaste                                                                 word_start,
278262182Semaste                                                                 skip_first_n_matches,
279262182Semaste                                                                 max_matches,
280262182Semaste                                                                 NULL,
281262182Semaste                                                                 word_complete,
282262182Semaste                                                                 matches);
283262182Semaste
284262182Semaste            size_t num_matches = matches.GetSize();
285262182Semaste            if (num_matches > 0)
286262182Semaste            {
287262182Semaste                std::string common_prefix;
288262182Semaste                matches.LongestCommonPrefix (common_prefix);
289262182Semaste                const size_t partial_name_len = strlen(word_start);
290262182Semaste
291262182Semaste                // If we matched a unique single command, add a space...
292262182Semaste                // Only do this if the completer told us this was a complete word, however...
293262182Semaste                if (num_matches == 1 && word_complete)
294262182Semaste                {
295262182Semaste                    common_prefix.push_back(' ');
296262182Semaste                }
297262182Semaste                common_prefix.erase (0, partial_name_len);
298262182Semaste                matches.InsertStringAtIndex(0, std::move(common_prefix));
299262182Semaste            }
300262182Semaste            return num_matches;
301262182Semaste        }
302262182Semaste        break;
303262182Semaste    }
304262182Semaste
305262182Semaste
306262182Semaste    return 0;
307262182Semaste}
308262182Semaste
309262182Semaste
310262182SemasteIOHandlerEditline::IOHandlerEditline (Debugger &debugger,
311262182Semaste                                      const char *editline_name, // Used for saving history files
312262182Semaste                                      const char *prompt,
313262182Semaste                                      bool multi_line,
314262182Semaste                                      IOHandlerDelegate &delegate) :
315262182Semaste    IOHandlerEditline(debugger,
316262182Semaste                      StreamFileSP(), // Inherit input from top input reader
317262182Semaste                      StreamFileSP(), // Inherit output from top input reader
318262182Semaste                      StreamFileSP(), // Inherit error from top input reader
319262182Semaste                      0,              // Flags
320262182Semaste                      editline_name,  // Used for saving history files
321262182Semaste                      prompt,
322262182Semaste                      multi_line,
323262182Semaste                      delegate)
324262182Semaste{
325262182Semaste}
326262182Semaste
327262182SemasteIOHandlerEditline::IOHandlerEditline (Debugger &debugger,
328262182Semaste                                      const lldb::StreamFileSP &input_sp,
329262182Semaste                                      const lldb::StreamFileSP &output_sp,
330262182Semaste                                      const lldb::StreamFileSP &error_sp,
331262182Semaste                                      uint32_t flags,
332262182Semaste                                      const char *editline_name, // Used for saving history files
333262182Semaste                                      const char *prompt,
334262182Semaste                                      bool multi_line,
335262182Semaste                                      IOHandlerDelegate &delegate) :
336262182Semaste    IOHandler (debugger, input_sp, output_sp, error_sp, flags),
337262182Semaste    m_editline_ap (),
338262182Semaste    m_delegate (delegate),
339262182Semaste    m_prompt (),
340262182Semaste    m_multi_line (multi_line)
341262182Semaste{
342262182Semaste    SetPrompt(prompt);
343262182Semaste
344262182Semaste    bool use_editline = false;
345262182Semaste
346262182Semaste#ifndef _MSC_VER
347262182Semaste    use_editline = m_input_sp->GetFile().GetIsRealTerminal();
348262182Semaste#else
349262182Semaste    use_editline = true;
350262182Semaste#endif
351262182Semaste
352262182Semaste    if (use_editline)
353262182Semaste    {
354262182Semaste        m_editline_ap.reset(new Editline (editline_name,
355262182Semaste                                          prompt ? prompt : "",
356262182Semaste                                          GetInputFILE (),
357262182Semaste                                          GetOutputFILE (),
358262182Semaste                                          GetErrorFILE ()));
359262182Semaste        m_editline_ap->SetLineCompleteCallback (LineCompletedCallback, this);
360262182Semaste        m_editline_ap->SetAutoCompleteCallback (AutoCompleteCallback, this);
361262182Semaste    }
362262182Semaste
363262182Semaste}
364262182Semaste
365262182SemasteIOHandlerEditline::~IOHandlerEditline ()
366262182Semaste{
367262182Semaste    m_editline_ap.reset();
368262182Semaste}
369262182Semaste
370262182Semaste
371262182Semastebool
372262182SemasteIOHandlerEditline::GetLine (std::string &line)
373262182Semaste{
374262182Semaste    if (m_editline_ap)
375262182Semaste    {
376262182Semaste        return m_editline_ap->GetLine(line).Success();
377262182Semaste    }
378262182Semaste    else
379262182Semaste    {
380262182Semaste        line.clear();
381262182Semaste
382262182Semaste        FILE *in = GetInputFILE();
383262182Semaste        if (in)
384262182Semaste        {
385262182Semaste            if (GetIsInteractive())
386262182Semaste            {
387262182Semaste                const char *prompt = GetPrompt();
388262182Semaste                if (prompt && prompt[0])
389262182Semaste                {
390262182Semaste                    FILE *out = GetOutputFILE();
391262182Semaste                    if (out)
392262182Semaste                    {
393262182Semaste                        ::fprintf(out, "%s", prompt);
394262182Semaste                        ::fflush(out);
395262182Semaste                    }
396262182Semaste                }
397262182Semaste            }
398262182Semaste            char buffer[256];
399262182Semaste            bool done = false;
400262182Semaste            bool got_line = false;
401262182Semaste            while (!done)
402262182Semaste            {
403262182Semaste                if (fgets(buffer, sizeof(buffer), in) == NULL)
404262182Semaste                    done = true;
405262182Semaste                else
406262182Semaste                {
407262182Semaste                    got_line = true;
408262182Semaste                    size_t buffer_len = strlen(buffer);
409262182Semaste                    assert (buffer[buffer_len] == '\0');
410262182Semaste                    char last_char = buffer[buffer_len-1];
411262182Semaste                    if (last_char == '\r' || last_char == '\n')
412262182Semaste                    {
413262182Semaste                        done = true;
414262182Semaste                        // Strip trailing newlines
415262182Semaste                        while (last_char == '\r' || last_char == '\n')
416262182Semaste                        {
417262182Semaste                            --buffer_len;
418262182Semaste                            if (buffer_len == 0)
419262182Semaste                                break;
420262182Semaste                            last_char = buffer[buffer_len-1];
421262182Semaste                        }
422262182Semaste                    }
423262182Semaste                    line.append(buffer, buffer_len);
424262182Semaste                }
425262182Semaste            }
426262182Semaste            // We might have gotten a newline on a line by itself
427262182Semaste            // make sure to return true in this case.
428262182Semaste            return got_line;
429262182Semaste        }
430262182Semaste        else
431262182Semaste        {
432262182Semaste            // No more input file, we are done...
433262182Semaste            SetIsDone(true);
434262182Semaste        }
435262182Semaste        return false;
436262182Semaste    }
437262182Semaste}
438262182Semaste
439262182Semaste
440262182SemasteLineStatus
441262182SemasteIOHandlerEditline::LineCompletedCallback (Editline *editline,
442262182Semaste                                          StringList &lines,
443262182Semaste                                          uint32_t line_idx,
444262182Semaste                                          Error &error,
445262182Semaste                                          void *baton)
446262182Semaste{
447262182Semaste    IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
448262182Semaste    return editline_reader->m_delegate.IOHandlerLinesUpdated(*editline_reader, lines, line_idx, error);
449262182Semaste}
450262182Semaste
451262182Semasteint
452262182SemasteIOHandlerEditline::AutoCompleteCallback (const char *current_line,
453262182Semaste                                         const char *cursor,
454262182Semaste                                         const char *last_char,
455262182Semaste                                         int skip_first_n_matches,
456262182Semaste                                         int max_matches,
457262182Semaste                                         StringList &matches,
458262182Semaste                                         void *baton)
459262182Semaste{
460262182Semaste    IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
461262182Semaste    if (editline_reader)
462262182Semaste        return editline_reader->m_delegate.IOHandlerComplete (*editline_reader,
463262182Semaste                                                              current_line,
464262182Semaste                                                              cursor,
465262182Semaste                                                              last_char,
466262182Semaste                                                              skip_first_n_matches,
467262182Semaste                                                              max_matches,
468262182Semaste                                                              matches);
469262182Semaste    return 0;
470262182Semaste}
471262182Semaste
472262182Semasteconst char *
473262182SemasteIOHandlerEditline::GetPrompt ()
474262182Semaste{
475262182Semaste    if (m_editline_ap)
476262182Semaste        return m_editline_ap->GetPrompt ();
477262182Semaste    else if (m_prompt.empty())
478262182Semaste        return NULL;
479262182Semaste    return m_prompt.c_str();
480262182Semaste}
481262182Semaste
482262182Semastebool
483262182SemasteIOHandlerEditline::SetPrompt (const char *p)
484262182Semaste{
485262182Semaste    if (p && p[0])
486262182Semaste        m_prompt = p;
487262182Semaste    else
488262182Semaste        m_prompt.clear();
489262182Semaste    if (m_editline_ap)
490262182Semaste        m_editline_ap->SetPrompt (m_prompt.empty() ? NULL : m_prompt.c_str());
491262182Semaste    return true;
492262182Semaste}
493262182Semaste
494262182Semastebool
495262182SemasteIOHandlerEditline::GetLines (StringList &lines)
496262182Semaste{
497262182Semaste    bool success = false;
498262182Semaste    if (m_editline_ap)
499262182Semaste    {
500262182Semaste        std::string end_token;
501262182Semaste        success = m_editline_ap->GetLines(end_token, lines).Success();
502262182Semaste    }
503262182Semaste    else
504262182Semaste    {
505262182Semaste        LineStatus lines_status = LineStatus::Success;
506262182Semaste
507262182Semaste        while (lines_status == LineStatus::Success)
508262182Semaste        {
509262182Semaste            std::string line;
510262182Semaste            if (GetLine(line))
511262182Semaste            {
512262182Semaste                lines.AppendString(line);
513262182Semaste                Error error;
514262182Semaste                lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error);
515262182Semaste            }
516262182Semaste            else
517262182Semaste            {
518262182Semaste                lines_status = LineStatus::Done;
519262182Semaste            }
520262182Semaste        }
521262182Semaste        success = lines.GetSize() > 0;
522262182Semaste    }
523262182Semaste    return success;
524262182Semaste}
525262182Semaste
526262182Semaste// Each IOHandler gets to run until it is done. It should read data
527262182Semaste// from the "in" and place output into "out" and "err and return
528262182Semaste// when done.
529262182Semastevoid
530262182SemasteIOHandlerEditline::Run ()
531262182Semaste{
532262182Semaste    std::string line;
533262182Semaste    while (IsActive())
534262182Semaste    {
535262182Semaste        if (m_multi_line)
536262182Semaste        {
537262182Semaste            StringList lines;
538262182Semaste            if (GetLines (lines))
539262182Semaste            {
540262182Semaste                line = lines.CopyList();
541262182Semaste                m_delegate.IOHandlerInputComplete(*this, line);
542262182Semaste            }
543262182Semaste            else
544262182Semaste            {
545262182Semaste                m_done = true;
546262182Semaste            }
547262182Semaste        }
548262182Semaste        else
549262182Semaste        {
550262182Semaste            if (GetLine(line))
551262182Semaste            {
552262182Semaste                m_delegate.IOHandlerInputComplete(*this, line);
553262182Semaste            }
554262182Semaste            else
555262182Semaste            {
556262182Semaste                m_done = true;
557262182Semaste            }
558262182Semaste        }
559262182Semaste    }
560262182Semaste}
561262182Semaste
562262182Semastevoid
563262182SemasteIOHandlerEditline::Hide ()
564262182Semaste{
565262182Semaste    if (m_editline_ap && m_editline_ap->GettingLine())
566262182Semaste        m_editline_ap->Hide();
567262182Semaste}
568262182Semaste
569262182Semaste
570262182Semastevoid
571262182SemasteIOHandlerEditline::Refresh ()
572262182Semaste{
573262182Semaste    if (m_editline_ap && m_editline_ap->GettingLine())
574262182Semaste        m_editline_ap->Refresh();
575262182Semaste    else
576262182Semaste    {
577262182Semaste        const char *prompt = GetPrompt();
578262182Semaste        if (prompt && prompt[0])
579262182Semaste        {
580262182Semaste            FILE *out = GetOutputFILE();
581262182Semaste            if (out)
582262182Semaste            {
583262182Semaste                ::fprintf(out, "%s", prompt);
584262182Semaste                ::fflush(out);
585262182Semaste            }
586262182Semaste        }
587262182Semaste    }
588262182Semaste}
589262182Semaste
590262182Semastevoid
591262500SemasteIOHandlerEditline::Cancel ()
592262500Semaste{
593262500Semaste    if (m_editline_ap)
594262500Semaste        m_editline_ap->Interrupt ();
595262500Semaste}
596262500Semaste
597262500Semastevoid
598262182SemasteIOHandlerEditline::Interrupt ()
599262182Semaste{
600262182Semaste    if (m_editline_ap)
601262182Semaste        m_editline_ap->Interrupt();
602262182Semaste}
603262182Semaste
604262182Semastevoid
605262182SemasteIOHandlerEditline::GotEOF()
606262182Semaste{
607262182Semaste    if (m_editline_ap)
608262182Semaste        m_editline_ap->Interrupt();
609262182Semaste}
610262182Semaste
611262182Semaste// we may want curses to be disabled for some builds
612262182Semaste// for instance, windows
613262182Semaste#ifndef LLDB_DISABLE_CURSES
614262182Semaste
615262182Semaste#include "lldb/Core/ValueObject.h"
616262182Semaste#include "lldb/Symbol/VariableList.h"
617262182Semaste#include "lldb/Target/Target.h"
618262182Semaste#include "lldb/Target/Process.h"
619262182Semaste#include "lldb/Target/Thread.h"
620262182Semaste#include "lldb/Target/StackFrame.h"
621262182Semaste
622262182Semaste#define KEY_RETURN   10
623262182Semaste#define KEY_ESCAPE  27
624262182Semaste
625262182Semastenamespace curses
626262182Semaste{
627262182Semaste    class Menu;
628262182Semaste    class MenuDelegate;
629262182Semaste    class Window;
630262182Semaste    class WindowDelegate;
631262182Semaste    typedef std::shared_ptr<Menu> MenuSP;
632262182Semaste    typedef std::shared_ptr<MenuDelegate> MenuDelegateSP;
633262182Semaste    typedef std::shared_ptr<Window> WindowSP;
634262182Semaste    typedef std::shared_ptr<WindowDelegate> WindowDelegateSP;
635262182Semaste    typedef std::vector<MenuSP> Menus;
636262182Semaste    typedef std::vector<WindowSP> Windows;
637262182Semaste    typedef std::vector<WindowDelegateSP> WindowDelegates;
638262182Semaste
639262182Semaste#if 0
640262182Semastetype summary add -s "x=${var.x}, y=${var.y}" curses::Point
641262182Semastetype summary add -s "w=${var.width}, h=${var.height}" curses::Size
642262182Semastetype summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
643262182Semaste#endif
644262182Semaste    struct Point
645262182Semaste    {
646262182Semaste        int x;
647262182Semaste        int y;
648262182Semaste
649262182Semaste        Point (int _x = 0, int _y = 0) :
650262182Semaste            x(_x),
651262182Semaste            y(_y)
652262182Semaste        {
653262182Semaste        }
654262182Semaste
655262182Semaste        void
656262182Semaste        Clear ()
657262182Semaste        {
658262182Semaste            x = 0;
659262182Semaste            y = 0;
660262182Semaste        }
661262182Semaste
662262182Semaste        Point &
663262182Semaste        operator += (const Point &rhs)
664262182Semaste        {
665262182Semaste            x += rhs.x;
666262182Semaste            y += rhs.y;
667262182Semaste            return *this;
668262182Semaste        }
669262182Semaste
670262182Semaste        void
671262182Semaste        Dump ()
672262182Semaste        {
673262182Semaste            printf ("(x=%i, y=%i)\n", x, y);
674262182Semaste        }
675262182Semaste
676262182Semaste    };
677262182Semaste
678262182Semaste    bool operator == (const Point &lhs, const Point &rhs)
679262182Semaste    {
680262182Semaste        return lhs.x == rhs.x && lhs.y == rhs.y;
681262182Semaste    }
682262182Semaste    bool operator != (const Point &lhs, const Point &rhs)
683262182Semaste    {
684262182Semaste        return lhs.x != rhs.x || lhs.y != rhs.y;
685262182Semaste    }
686262182Semaste
687262182Semaste    struct Size
688262182Semaste    {
689262182Semaste        int width;
690262182Semaste        int height;
691262182Semaste        Size (int w = 0, int h = 0) :
692262182Semaste            width (w),
693262182Semaste            height (h)
694262182Semaste        {
695262182Semaste        }
696262182Semaste
697262182Semaste        void
698262182Semaste        Clear ()
699262182Semaste        {
700262182Semaste            width = 0;
701262182Semaste            height = 0;
702262182Semaste        }
703262182Semaste
704262182Semaste        void
705262182Semaste        Dump ()
706262182Semaste        {
707262182Semaste            printf ("(w=%i, h=%i)\n", width, height);
708262182Semaste        }
709262182Semaste
710262182Semaste    };
711262182Semaste
712262182Semaste    bool operator == (const Size &lhs, const Size &rhs)
713262182Semaste    {
714262182Semaste        return lhs.width == rhs.width && lhs.height == rhs.height;
715262182Semaste    }
716262182Semaste    bool operator != (const Size &lhs, const Size &rhs)
717262182Semaste    {
718262182Semaste        return lhs.width != rhs.width || lhs.height != rhs.height;
719262182Semaste    }
720262182Semaste
721262182Semaste    struct Rect
722262182Semaste    {
723262182Semaste        Point origin;
724262182Semaste        Size size;
725262182Semaste
726262182Semaste        Rect () :
727262182Semaste            origin(),
728262182Semaste            size()
729262182Semaste        {
730262182Semaste        }
731262182Semaste
732262182Semaste        Rect (const Point &p, const Size &s) :
733262182Semaste            origin (p),
734262182Semaste            size (s)
735262182Semaste        {
736262182Semaste        }
737262182Semaste
738262182Semaste        void
739262182Semaste        Clear ()
740262182Semaste        {
741262182Semaste            origin.Clear();
742262182Semaste            size.Clear();
743262182Semaste        }
744262182Semaste
745262182Semaste        void
746262182Semaste        Dump ()
747262182Semaste        {
748262182Semaste            printf ("(x=%i, y=%i), w=%i, h=%i)\n", origin.x, origin.y, size.width, size.height);
749262182Semaste        }
750262182Semaste
751262182Semaste        void
752262182Semaste        Inset (int w, int h)
753262182Semaste        {
754262182Semaste            if (size.width > w*2)
755262182Semaste                size.width -= w*2;
756262182Semaste            origin.x += w;
757262182Semaste
758262182Semaste            if (size.height > h*2)
759262182Semaste                size.height -= h*2;
760262182Semaste            origin.y += h;
761262182Semaste        }
762262182Semaste        // Return a status bar rectangle which is the last line of
763262182Semaste        // this rectangle. This rectangle will be modified to not
764262182Semaste        // include the status bar area.
765262182Semaste        Rect
766262182Semaste        MakeStatusBar ()
767262182Semaste        {
768262182Semaste            Rect status_bar;
769262182Semaste            if (size.height > 1)
770262182Semaste            {
771262182Semaste                status_bar.origin.x = origin.x;
772262182Semaste                status_bar.origin.y = size.height;
773262182Semaste                status_bar.size.width = size.width;
774262182Semaste                status_bar.size.height = 1;
775262182Semaste                --size.height;
776262182Semaste            }
777262182Semaste            return status_bar;
778262182Semaste        }
779262182Semaste
780262182Semaste        // Return a menubar rectangle which is the first line of
781262182Semaste        // this rectangle. This rectangle will be modified to not
782262182Semaste        // include the menubar area.
783262182Semaste        Rect
784262182Semaste        MakeMenuBar ()
785262182Semaste        {
786262182Semaste            Rect menubar;
787262182Semaste            if (size.height > 1)
788262182Semaste            {
789262182Semaste                menubar.origin.x = origin.x;
790262182Semaste                menubar.origin.y = origin.y;
791262182Semaste                menubar.size.width = size.width;
792262182Semaste                menubar.size.height = 1;
793262182Semaste                ++origin.y;
794262182Semaste                --size.height;
795262182Semaste            }
796262182Semaste            return menubar;
797262182Semaste        }
798262182Semaste
799262182Semaste        void
800262182Semaste        HorizontalSplitPercentage (float top_percentage, Rect &top, Rect &bottom) const
801262182Semaste        {
802262182Semaste            float top_height = top_percentage * size.height;
803262182Semaste            HorizontalSplit (top_height, top, bottom);
804262182Semaste        }
805262182Semaste
806262182Semaste        void
807262182Semaste        HorizontalSplit (int top_height, Rect &top, Rect &bottom) const
808262182Semaste        {
809262182Semaste            top = *this;
810262182Semaste            if (top_height < size.height)
811262182Semaste            {
812262182Semaste                top.size.height = top_height;
813262182Semaste                bottom.origin.x = origin.x;
814262182Semaste                bottom.origin.y = origin.y + top.size.height;
815262182Semaste                bottom.size.width = size.width;
816262182Semaste                bottom.size.height = size.height - top.size.height;
817262182Semaste            }
818262182Semaste            else
819262182Semaste            {
820262182Semaste                bottom.Clear();
821262182Semaste            }
822262182Semaste        }
823262182Semaste
824262182Semaste        void
825262182Semaste        VerticalSplitPercentage (float left_percentage, Rect &left, Rect &right) const
826262182Semaste        {
827262182Semaste            float left_width = left_percentage * size.width;
828262182Semaste            VerticalSplit (left_width, left, right);
829262182Semaste        }
830262182Semaste
831262182Semaste
832262182Semaste        void
833262182Semaste        VerticalSplit (int left_width, Rect &left, Rect &right) const
834262182Semaste        {
835262182Semaste            left = *this;
836262182Semaste            if (left_width < size.width)
837262182Semaste            {
838262182Semaste                left.size.width = left_width;
839262182Semaste                right.origin.x = origin.x + left.size.width;
840262182Semaste                right.origin.y = origin.y;
841262182Semaste                right.size.width = size.width - left.size.width;
842262182Semaste                right.size.height = size.height;
843262182Semaste            }
844262182Semaste            else
845262182Semaste            {
846262182Semaste                right.Clear();
847262182Semaste            }
848262182Semaste        }
849262182Semaste    };
850262182Semaste
851262182Semaste    bool operator == (const Rect &lhs, const Rect &rhs)
852262182Semaste    {
853262182Semaste        return lhs.origin == rhs.origin && lhs.size == rhs.size;
854262182Semaste    }
855262182Semaste    bool operator != (const Rect &lhs, const Rect &rhs)
856262182Semaste    {
857262182Semaste        return lhs.origin != rhs.origin || lhs.size != rhs.size;
858262182Semaste    }
859262182Semaste
860262182Semaste    enum HandleCharResult
861262182Semaste    {
862262182Semaste        eKeyNotHandled      = 0,
863262182Semaste        eKeyHandled         = 1,
864262182Semaste        eQuitApplication    = 2
865262182Semaste    };
866262182Semaste
867262182Semaste    enum class MenuActionResult
868262182Semaste    {
869262182Semaste        Handled,
870262182Semaste        NotHandled,
871262182Semaste        Quit    // Exit all menus and quit
872262182Semaste    };
873262182Semaste
874262182Semaste    struct KeyHelp
875262182Semaste    {
876262182Semaste        int ch;
877262182Semaste        const char *description;
878262182Semaste    };
879262182Semaste
880262182Semaste    class WindowDelegate
881262182Semaste    {
882262182Semaste    public:
883262182Semaste        virtual
884262182Semaste        ~WindowDelegate()
885262182Semaste        {
886262182Semaste        }
887262182Semaste
888262182Semaste        virtual bool
889262182Semaste        WindowDelegateDraw (Window &window, bool force)
890262182Semaste        {
891262182Semaste            return false; // Drawing not handled
892262182Semaste        }
893262182Semaste
894262182Semaste        virtual HandleCharResult
895262182Semaste        WindowDelegateHandleChar (Window &window, int key)
896262182Semaste        {
897262182Semaste            return eKeyNotHandled;
898262182Semaste        }
899262182Semaste
900262182Semaste        virtual const char *
901262182Semaste        WindowDelegateGetHelpText ()
902262182Semaste        {
903262182Semaste            return NULL;
904262182Semaste        }
905262182Semaste
906262182Semaste        virtual KeyHelp *
907262182Semaste        WindowDelegateGetKeyHelp ()
908262182Semaste        {
909262182Semaste            return NULL;
910262182Semaste        }
911262182Semaste    };
912262182Semaste
913262182Semaste    class HelpDialogDelegate :
914262182Semaste        public WindowDelegate
915262182Semaste    {
916262182Semaste    public:
917262182Semaste        HelpDialogDelegate (const char *text, KeyHelp *key_help_array);
918262182Semaste
919262182Semaste        virtual
920262182Semaste        ~HelpDialogDelegate();
921262182Semaste
922262182Semaste        virtual bool
923262182Semaste        WindowDelegateDraw (Window &window, bool force);
924262182Semaste
925262182Semaste        virtual HandleCharResult
926262182Semaste        WindowDelegateHandleChar (Window &window, int key);
927262182Semaste
928262182Semaste        size_t
929262182Semaste        GetNumLines() const
930262182Semaste        {
931262182Semaste            return m_text.GetSize();
932262182Semaste        }
933262182Semaste
934262182Semaste        size_t
935262182Semaste        GetMaxLineLength () const
936262182Semaste        {
937262182Semaste            return m_text.GetMaxStringLength();
938262182Semaste        }
939262182Semaste
940262182Semaste    protected:
941262182Semaste        StringList m_text;
942262182Semaste        int m_first_visible_line;
943262182Semaste    };
944262182Semaste
945262182Semaste
946262182Semaste    class Window
947262182Semaste    {
948262182Semaste    public:
949262182Semaste
950262182Semaste        Window (const char *name) :
951262182Semaste            m_name (name),
952262182Semaste            m_window (NULL),
953262182Semaste            m_panel (NULL),
954262182Semaste            m_parent (NULL),
955262182Semaste            m_subwindows (),
956262182Semaste            m_delegate_sp (),
957262182Semaste            m_curr_active_window_idx (UINT32_MAX),
958262182Semaste            m_prev_active_window_idx (UINT32_MAX),
959262182Semaste            m_delete (false),
960262182Semaste            m_needs_update (true),
961262182Semaste            m_can_activate (true),
962262182Semaste            m_is_subwin (false)
963262182Semaste        {
964262182Semaste        }
965262182Semaste
966262182Semaste        Window (const char *name, WINDOW *w, bool del = true) :
967262182Semaste            m_name (name),
968262182Semaste            m_window (NULL),
969262182Semaste            m_panel (NULL),
970262182Semaste            m_parent (NULL),
971262182Semaste            m_subwindows (),
972262182Semaste            m_delegate_sp (),
973262182Semaste            m_curr_active_window_idx (UINT32_MAX),
974262182Semaste            m_prev_active_window_idx (UINT32_MAX),
975262182Semaste            m_delete (del),
976262182Semaste            m_needs_update (true),
977262182Semaste            m_can_activate (true),
978262182Semaste            m_is_subwin (false)
979262182Semaste        {
980262182Semaste            if (w)
981262182Semaste                Reset(w);
982262182Semaste        }
983262182Semaste
984262182Semaste        Window (const char *name, const Rect &bounds) :
985262182Semaste            m_name (name),
986262182Semaste            m_window (NULL),
987262182Semaste            m_parent (NULL),
988262182Semaste            m_subwindows (),
989262182Semaste            m_delegate_sp (),
990262182Semaste            m_curr_active_window_idx (UINT32_MAX),
991262182Semaste            m_prev_active_window_idx (UINT32_MAX),
992262182Semaste            m_delete (true),
993262182Semaste            m_needs_update (true),
994262182Semaste            m_can_activate (true),
995262182Semaste            m_is_subwin (false)
996262182Semaste        {
997262182Semaste            Reset (::newwin (bounds.size.height, bounds.size.width, bounds.origin.y, bounds.origin.y));
998262182Semaste        }
999262182Semaste
1000262182Semaste        virtual
1001262182Semaste        ~Window ()
1002262182Semaste        {
1003262182Semaste            RemoveSubWindows ();
1004262182Semaste            Reset ();
1005262182Semaste        }
1006262182Semaste
1007262182Semaste        void
1008262182Semaste        Reset (WINDOW *w = NULL, bool del = true)
1009262182Semaste        {
1010262182Semaste            if (m_window == w)
1011262182Semaste                return;
1012262182Semaste
1013262182Semaste            if (m_panel)
1014262182Semaste            {
1015262182Semaste                ::del_panel (m_panel);
1016262182Semaste                m_panel = NULL;
1017262182Semaste            }
1018262182Semaste            if (m_window && m_delete)
1019262182Semaste            {
1020262182Semaste                ::delwin (m_window);
1021262182Semaste                m_window = NULL;
1022262182Semaste                m_delete = false;
1023262182Semaste            }
1024262182Semaste            if (w)
1025262182Semaste            {
1026262182Semaste                m_window = w;
1027262182Semaste                m_panel = ::new_panel (m_window);
1028262182Semaste                m_delete = del;
1029262182Semaste            }
1030262182Semaste        }
1031262182Semaste
1032262182Semaste        void    AttributeOn (attr_t attr)   { ::wattron (m_window, attr); }
1033262182Semaste        void    AttributeOff (attr_t attr)  { ::wattroff (m_window, attr); }
1034262182Semaste        void    Box (chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) { ::box(m_window, v_char, h_char); }
1035262182Semaste        void    Clear ()    { ::wclear (m_window); }
1036262182Semaste        void    Erase ()    { ::werase (m_window); }
1037262182Semaste        Rect    GetBounds () { return Rect (GetParentOrigin(), GetSize()); } // Get the rectangle in our parent window
1038262182Semaste        int     GetChar ()  { return ::wgetch (m_window); }
1039262182Semaste        int     GetCursorX ()     { return getcurx (m_window); }
1040262182Semaste        int     GetCursorY ()     { return getcury (m_window); }
1041262182Semaste        Rect    GetFrame ()    { return Rect (Point(), GetSize()); } // Get our rectangle in our own coordinate system
1042262182Semaste        Point   GetParentOrigin() { return Point (GetParentX(), GetParentY()); }
1043262182Semaste        Size    GetSize()         { return Size (GetWidth(), GetHeight()); }
1044262182Semaste        int     GetParentX ()     { return getparx (m_window); }
1045262182Semaste        int     GetParentY ()     { return getpary (m_window); }
1046262182Semaste        int     GetMaxX()   { return getmaxx (m_window); }
1047262182Semaste        int     GetMaxY()   { return getmaxy (m_window); }
1048262182Semaste        int     GetWidth()  { return GetMaxX(); }
1049262182Semaste        int     GetHeight() { return GetMaxY(); }
1050262182Semaste        void    MoveCursor (int x, int y) {  ::wmove (m_window, y, x); }
1051262182Semaste        void    MoveWindow (int x, int y) {  MoveWindow(Point(x,y)); }
1052262182Semaste        void    Resize (int w, int h) { ::wresize(m_window, h, w); }
1053262182Semaste        void    Resize (const Size &size) { ::wresize(m_window, size.height, size.width); }
1054262182Semaste        void    PutChar (int ch)    { ::waddch (m_window, ch); }
1055262182Semaste        void    PutCString (const char *s, int len = -1) { ::waddnstr (m_window, s, len); }
1056262182Semaste        void    Refresh ()  { ::wrefresh (m_window); }
1057262182Semaste        void    DeferredRefresh ()
1058262182Semaste        {
1059262182Semaste            // We are using panels, so we don't need to call this...
1060262182Semaste            //::wnoutrefresh(m_window);
1061262182Semaste        }
1062262182Semaste        void    SetBackground (int color_pair_idx) { ::wbkgd (m_window,COLOR_PAIR(color_pair_idx)); }
1063262182Semaste        void    UnderlineOn ()  { AttributeOn(A_UNDERLINE); }
1064262182Semaste        void    UnderlineOff () { AttributeOff(A_UNDERLINE); }
1065262182Semaste
1066262182Semaste        void    PutCStringTruncated (const char *s, int right_pad)
1067262182Semaste        {
1068262182Semaste            int bytes_left = GetWidth() - GetCursorX();
1069262182Semaste            if (bytes_left > right_pad)
1070262182Semaste            {
1071262182Semaste                bytes_left -= right_pad;
1072262182Semaste                ::waddnstr (m_window, s, bytes_left);
1073262182Semaste            }
1074262182Semaste        }
1075262182Semaste
1076262182Semaste        void
1077262182Semaste        MoveWindow (const Point &origin)
1078262182Semaste        {
1079262182Semaste            const bool moving_window = origin != GetParentOrigin();
1080262182Semaste            if (m_is_subwin && moving_window)
1081262182Semaste            {
1082262182Semaste                // Can't move subwindows, must delete and re-create
1083262182Semaste                Size size = GetSize();
1084262182Semaste                Reset (::subwin (m_parent->m_window,
1085262182Semaste                                 size.height,
1086262182Semaste                                 size.width,
1087262182Semaste                                 origin.y,
1088262182Semaste                                 origin.x), true);
1089262182Semaste            }
1090262182Semaste            else
1091262182Semaste            {
1092262182Semaste                ::mvwin (m_window, origin.y, origin.x);
1093262182Semaste            }
1094262182Semaste        }
1095262182Semaste
1096262182Semaste        void
1097262182Semaste        SetBounds (const Rect &bounds)
1098262182Semaste        {
1099262182Semaste            const bool moving_window = bounds.origin != GetParentOrigin();
1100262182Semaste            if (m_is_subwin && moving_window)
1101262182Semaste            {
1102262182Semaste                // Can't move subwindows, must delete and re-create
1103262182Semaste                Reset (::subwin (m_parent->m_window,
1104262182Semaste                                 bounds.size.height,
1105262182Semaste                                 bounds.size.width,
1106262182Semaste                                 bounds.origin.y,
1107262182Semaste                                 bounds.origin.x), true);
1108262182Semaste            }
1109262182Semaste            else
1110262182Semaste            {
1111262182Semaste                if (moving_window)
1112262182Semaste                    MoveWindow(bounds.origin);
1113262182Semaste                Resize (bounds.size);
1114262182Semaste            }
1115262182Semaste        }
1116262182Semaste
1117262182Semaste        void
1118262182Semaste        Printf (const char *format, ...)  __attribute__ ((format (printf, 2, 3)))
1119262182Semaste        {
1120262182Semaste            va_list args;
1121262182Semaste            va_start (args, format);
1122262182Semaste            vwprintw(m_window, format, args);
1123262182Semaste            va_end (args);
1124262182Semaste        }
1125262182Semaste
1126262182Semaste        void
1127262182Semaste        Touch ()
1128262182Semaste        {
1129262182Semaste            ::touchwin (m_window);
1130262182Semaste            if (m_parent)
1131262182Semaste                m_parent->Touch();
1132262182Semaste        }
1133262182Semaste
1134262182Semaste        WindowSP
1135262182Semaste        CreateSubWindow (const char *name, const Rect &bounds, bool make_active)
1136262182Semaste        {
1137262182Semaste            WindowSP subwindow_sp;
1138262182Semaste            if (m_window)
1139262182Semaste            {
1140262182Semaste                subwindow_sp.reset(new Window(name, ::subwin (m_window,
1141262182Semaste                                                              bounds.size.height,
1142262182Semaste                                                              bounds.size.width,
1143262182Semaste                                                              bounds.origin.y,
1144262182Semaste                                                              bounds.origin.x), true));
1145262182Semaste                subwindow_sp->m_is_subwin = true;
1146262182Semaste            }
1147262182Semaste            else
1148262182Semaste            {
1149262182Semaste                subwindow_sp.reset(new Window(name, ::newwin (bounds.size.height,
1150262182Semaste                                                              bounds.size.width,
1151262182Semaste                                                              bounds.origin.y,
1152262182Semaste                                                              bounds.origin.x), true));
1153262182Semaste                subwindow_sp->m_is_subwin = false;
1154262182Semaste            }
1155262182Semaste            subwindow_sp->m_parent = this;
1156262182Semaste            if (make_active)
1157262182Semaste            {
1158262182Semaste                m_prev_active_window_idx = m_curr_active_window_idx;
1159262182Semaste                m_curr_active_window_idx = m_subwindows.size();
1160262182Semaste            }
1161262182Semaste            m_subwindows.push_back(subwindow_sp);
1162262182Semaste            ::top_panel (subwindow_sp->m_panel);
1163262182Semaste            m_needs_update = true;
1164262182Semaste            return subwindow_sp;
1165262182Semaste        }
1166262182Semaste
1167262182Semaste        bool
1168262182Semaste        RemoveSubWindow (Window *window)
1169262182Semaste        {
1170262182Semaste            Windows::iterator pos, end = m_subwindows.end();
1171262182Semaste            size_t i = 0;
1172262182Semaste            for (pos = m_subwindows.begin(); pos != end; ++pos, ++i)
1173262182Semaste            {
1174262182Semaste                if ((*pos).get() == window)
1175262182Semaste                {
1176262182Semaste                    if (m_prev_active_window_idx == i)
1177262182Semaste                        m_prev_active_window_idx = UINT32_MAX;
1178262182Semaste                    else if (m_prev_active_window_idx != UINT32_MAX && m_prev_active_window_idx > i)
1179262182Semaste                        --m_prev_active_window_idx;
1180262182Semaste
1181262182Semaste                    if (m_curr_active_window_idx == i)
1182262182Semaste                        m_curr_active_window_idx = UINT32_MAX;
1183262182Semaste                    else if (m_curr_active_window_idx != UINT32_MAX && m_curr_active_window_idx > i)
1184262182Semaste                        --m_curr_active_window_idx;
1185262182Semaste                    window->Erase();
1186262182Semaste                    m_subwindows.erase(pos);
1187262182Semaste                    m_needs_update = true;
1188262182Semaste                    if (m_parent)
1189262182Semaste                        m_parent->Touch();
1190262182Semaste                    else
1191262182Semaste                        ::touchwin (stdscr);
1192262182Semaste                    return true;
1193262182Semaste                }
1194262182Semaste            }
1195262182Semaste            return false;
1196262182Semaste        }
1197262182Semaste
1198262182Semaste        WindowSP
1199262182Semaste        FindSubWindow (const char *name)
1200262182Semaste        {
1201262182Semaste            Windows::iterator pos, end = m_subwindows.end();
1202262182Semaste            size_t i = 0;
1203262182Semaste            for (pos = m_subwindows.begin(); pos != end; ++pos, ++i)
1204262182Semaste            {
1205262182Semaste                if ((*pos)->m_name.compare(name) == 0)
1206262182Semaste                    return *pos;
1207262182Semaste            }
1208262182Semaste            return WindowSP();
1209262182Semaste        }
1210262182Semaste
1211262182Semaste        void
1212262182Semaste        RemoveSubWindows ()
1213262182Semaste        {
1214262182Semaste            m_curr_active_window_idx = UINT32_MAX;
1215262182Semaste            m_prev_active_window_idx = UINT32_MAX;
1216262182Semaste            for (Windows::iterator pos = m_subwindows.begin();
1217262182Semaste                 pos != m_subwindows.end();
1218262182Semaste                 pos = m_subwindows.erase(pos))
1219262182Semaste            {
1220262182Semaste                (*pos)->Erase();
1221262182Semaste            }
1222262182Semaste            if (m_parent)
1223262182Semaste                m_parent->Touch();
1224262182Semaste            else
1225262182Semaste                ::touchwin (stdscr);
1226262182Semaste        }
1227262182Semaste
1228262182Semaste        WINDOW *
1229262182Semaste        get()
1230262182Semaste        {
1231262182Semaste            return m_window;
1232262182Semaste        }
1233262182Semaste
1234262182Semaste        operator WINDOW *()
1235262182Semaste        {
1236262182Semaste            return m_window;
1237262182Semaste        }
1238262182Semaste
1239262182Semaste        //----------------------------------------------------------------------
1240262182Semaste        // Window drawing utilities
1241262182Semaste        //----------------------------------------------------------------------
1242262182Semaste        void
1243262182Semaste        DrawTitleBox (const char *title, const char *bottom_message = NULL)
1244262182Semaste        {
1245262182Semaste            attr_t attr = 0;
1246262182Semaste            if (IsActive())
1247262182Semaste                attr = A_BOLD | COLOR_PAIR(2);
1248262182Semaste            else
1249262182Semaste                attr = 0;
1250262182Semaste            if (attr)
1251262182Semaste                AttributeOn(attr);
1252262182Semaste
1253262182Semaste            Box();
1254262182Semaste            MoveCursor(3, 0);
1255262182Semaste
1256262182Semaste            if (title && title[0])
1257262182Semaste            {
1258262182Semaste                PutChar ('<');
1259262182Semaste                PutCString (title);
1260262182Semaste                PutChar ('>');
1261262182Semaste            }
1262262182Semaste
1263262182Semaste            if (bottom_message && bottom_message[0])
1264262182Semaste            {
1265262182Semaste                int bottom_message_length = strlen(bottom_message);
1266262182Semaste                int x = GetWidth() - 3 - (bottom_message_length + 2);
1267262182Semaste
1268262182Semaste                if (x > 0)
1269262182Semaste                {
1270262182Semaste                    MoveCursor (x, GetHeight() - 1);
1271262182Semaste                    PutChar ('[');
1272262182Semaste                    PutCString(bottom_message);
1273262182Semaste                    PutChar (']');
1274262182Semaste                }
1275262182Semaste                else
1276262182Semaste                {
1277262182Semaste                    MoveCursor (1, GetHeight() - 1);
1278262182Semaste                    PutChar ('[');
1279262182Semaste                    PutCStringTruncated (bottom_message, 1);
1280262182Semaste                }
1281262182Semaste            }
1282262182Semaste            if (attr)
1283262182Semaste                AttributeOff(attr);
1284262182Semaste
1285262182Semaste        }
1286262182Semaste
1287262182Semaste        virtual void
1288262182Semaste        Draw (bool force)
1289262182Semaste        {
1290262182Semaste            if (m_delegate_sp && m_delegate_sp->WindowDelegateDraw (*this, force))
1291262182Semaste                return;
1292262182Semaste
1293262182Semaste            for (auto &subwindow_sp : m_subwindows)
1294262182Semaste                subwindow_sp->Draw(force);
1295262182Semaste        }
1296262182Semaste
1297262182Semaste        bool
1298262182Semaste        CreateHelpSubwindow ()
1299262182Semaste        {
1300262182Semaste            if (m_delegate_sp)
1301262182Semaste            {
1302262182Semaste                const char *text = m_delegate_sp->WindowDelegateGetHelpText ();
1303262182Semaste                KeyHelp *key_help = m_delegate_sp->WindowDelegateGetKeyHelp ();
1304262182Semaste                if ((text && text[0]) || key_help)
1305262182Semaste                {
1306262182Semaste                    std::auto_ptr<HelpDialogDelegate> help_delegate_ap(new HelpDialogDelegate(text, key_help));
1307262182Semaste                    const size_t num_lines = help_delegate_ap->GetNumLines();
1308262182Semaste                    const size_t max_length = help_delegate_ap->GetMaxLineLength();
1309262182Semaste                    Rect bounds = GetBounds();
1310262182Semaste                    bounds.Inset(1, 1);
1311262182Semaste                    if (max_length + 4 < bounds.size.width)
1312262182Semaste                    {
1313262182Semaste                        bounds.origin.x += (bounds.size.width - max_length + 4)/2;
1314262182Semaste                        bounds.size.width = max_length + 4;
1315262182Semaste                    }
1316262182Semaste                    else
1317262182Semaste                    {
1318262182Semaste                        if (bounds.size.width > 100)
1319262182Semaste                        {
1320262182Semaste                            const int inset_w = bounds.size.width / 4;
1321262182Semaste                            bounds.origin.x += inset_w;
1322262182Semaste                            bounds.size.width -= 2*inset_w;
1323262182Semaste                        }
1324262182Semaste                    }
1325262182Semaste
1326262182Semaste                    if (num_lines + 2 < bounds.size.height)
1327262182Semaste                    {
1328262182Semaste                        bounds.origin.y += (bounds.size.height - num_lines + 2)/2;
1329262182Semaste                        bounds.size.height = num_lines + 2;
1330262182Semaste                    }
1331262182Semaste                    else
1332262182Semaste                    {
1333262182Semaste                        if (bounds.size.height > 100)
1334262182Semaste                        {
1335262182Semaste                            const int inset_h = bounds.size.height / 4;
1336262182Semaste                            bounds.origin.y += inset_h;
1337262182Semaste                            bounds.size.height -= 2*inset_h;
1338262182Semaste                        }
1339262182Semaste                    }
1340262182Semaste                    WindowSP help_window_sp;
1341262182Semaste                    Window *parent_window = GetParent();
1342262182Semaste                    if (parent_window)
1343262182Semaste                        help_window_sp = parent_window->CreateSubWindow("Help", bounds, true);
1344262182Semaste                    else
1345262182Semaste                        help_window_sp = CreateSubWindow("Help", bounds, true);
1346262182Semaste                    help_window_sp->SetDelegate(WindowDelegateSP(help_delegate_ap.release()));
1347262182Semaste                    return true;
1348262182Semaste                }
1349262182Semaste            }
1350262182Semaste            return false;
1351262182Semaste        }
1352262182Semaste
1353262182Semaste        virtual HandleCharResult
1354262182Semaste        HandleChar (int key)
1355262182Semaste        {
1356262182Semaste            // Always check the active window first
1357262182Semaste            HandleCharResult result = eKeyNotHandled;
1358262182Semaste            WindowSP active_window_sp = GetActiveWindow ();
1359262182Semaste            if (active_window_sp)
1360262182Semaste            {
1361262182Semaste                result = active_window_sp->HandleChar (key);
1362262182Semaste                if (result != eKeyNotHandled)
1363262182Semaste                    return result;
1364262182Semaste            }
1365262182Semaste
1366262182Semaste            if (m_delegate_sp)
1367262182Semaste            {
1368262182Semaste                result = m_delegate_sp->WindowDelegateHandleChar (*this, key);
1369262182Semaste                if (result != eKeyNotHandled)
1370262182Semaste                    return result;
1371262182Semaste            }
1372262182Semaste
1373262182Semaste            // Then check for any windows that want any keys
1374262182Semaste            // that weren't handled. This is typically only
1375262182Semaste            // for a menubar.
1376262182Semaste            // Make a copy of the subwindows in case any HandleChar()
1377262182Semaste            // functions muck with the subwindows. If we don't do this,
1378262182Semaste            // we can crash when iterating over the subwindows.
1379262182Semaste            Windows subwindows (m_subwindows);
1380262182Semaste            for (auto subwindow_sp : subwindows)
1381262182Semaste            {
1382262182Semaste                if (subwindow_sp->m_can_activate == false)
1383262182Semaste                {
1384262182Semaste                    HandleCharResult result = subwindow_sp->HandleChar(key);
1385262182Semaste                    if (result != eKeyNotHandled)
1386262182Semaste                        return result;
1387262182Semaste                }
1388262182Semaste            }
1389262182Semaste
1390262182Semaste            return eKeyNotHandled;
1391262182Semaste        }
1392262182Semaste
1393262182Semaste        bool
1394262182Semaste        SetActiveWindow (Window *window)
1395262182Semaste        {
1396262182Semaste            const size_t num_subwindows = m_subwindows.size();
1397262182Semaste            for (size_t i=0; i<num_subwindows; ++i)
1398262182Semaste            {
1399262182Semaste                if (m_subwindows[i].get() == window)
1400262182Semaste                {
1401262182Semaste                    m_prev_active_window_idx = m_curr_active_window_idx;
1402262182Semaste                    ::top_panel (window->m_panel);
1403262182Semaste                    m_curr_active_window_idx = i;
1404262182Semaste                    return true;
1405262182Semaste                }
1406262182Semaste            }
1407262182Semaste            return false;
1408262182Semaste        }
1409262182Semaste
1410262182Semaste        WindowSP
1411262182Semaste        GetActiveWindow ()
1412262182Semaste        {
1413262182Semaste            if (!m_subwindows.empty())
1414262182Semaste            {
1415262182Semaste                if (m_curr_active_window_idx >= m_subwindows.size())
1416262182Semaste                {
1417262182Semaste                    if (m_prev_active_window_idx < m_subwindows.size())
1418262182Semaste                    {
1419262182Semaste                        m_curr_active_window_idx = m_prev_active_window_idx;
1420262182Semaste                        m_prev_active_window_idx = UINT32_MAX;
1421262182Semaste                    }
1422262182Semaste                    else if (IsActive())
1423262182Semaste                    {
1424262182Semaste                        m_prev_active_window_idx = UINT32_MAX;
1425262182Semaste                        m_curr_active_window_idx = UINT32_MAX;
1426262182Semaste
1427262182Semaste                        // Find first window that wants to be active if this window is active
1428262182Semaste                        const size_t num_subwindows = m_subwindows.size();
1429262182Semaste                        for (size_t i=0; i<num_subwindows; ++i)
1430262182Semaste                        {
1431262182Semaste                            if (m_subwindows[i]->GetCanBeActive())
1432262182Semaste                            {
1433262182Semaste                                m_curr_active_window_idx = i;
1434262182Semaste                                break;
1435262182Semaste                            }
1436262182Semaste                        }
1437262182Semaste                    }
1438262182Semaste                }
1439262182Semaste
1440262182Semaste                if (m_curr_active_window_idx < m_subwindows.size())
1441262182Semaste                    return m_subwindows[m_curr_active_window_idx];
1442262182Semaste            }
1443262182Semaste            return WindowSP();
1444262182Semaste        }
1445262182Semaste
1446262182Semaste        bool
1447262182Semaste        GetCanBeActive () const
1448262182Semaste        {
1449262182Semaste            return m_can_activate;
1450262182Semaste        }
1451262182Semaste
1452262182Semaste        void
1453262182Semaste        SetCanBeActive (bool b)
1454262182Semaste        {
1455262182Semaste            m_can_activate = b;
1456262182Semaste        }
1457262182Semaste
1458262182Semaste        const WindowDelegateSP &
1459262182Semaste        GetDelegate () const
1460262182Semaste        {
1461262182Semaste            return m_delegate_sp;
1462262182Semaste        }
1463262182Semaste
1464262182Semaste        void
1465262182Semaste        SetDelegate (const WindowDelegateSP &delegate_sp)
1466262182Semaste        {
1467262182Semaste            m_delegate_sp = delegate_sp;
1468262182Semaste        }
1469262182Semaste
1470262182Semaste        Window *
1471262182Semaste        GetParent () const
1472262182Semaste        {
1473262182Semaste            return m_parent;
1474262182Semaste        }
1475262182Semaste
1476262182Semaste        bool
1477262182Semaste        IsActive () const
1478262182Semaste        {
1479262182Semaste            if (m_parent)
1480262182Semaste                return m_parent->GetActiveWindow().get() == this;
1481262182Semaste            else
1482262182Semaste                return true; // Top level window is always active
1483262182Semaste        }
1484262182Semaste
1485262182Semaste        void
1486262182Semaste        SelectNextWindowAsActive ()
1487262182Semaste        {
1488262182Semaste            // Move active focus to next window
1489262182Semaste            const size_t num_subwindows = m_subwindows.size();
1490262182Semaste            if (m_curr_active_window_idx == UINT32_MAX)
1491262182Semaste            {
1492262182Semaste                uint32_t idx = 0;
1493262182Semaste                for (auto subwindow_sp : m_subwindows)
1494262182Semaste                {
1495262182Semaste                    if (subwindow_sp->GetCanBeActive())
1496262182Semaste                    {
1497262182Semaste                        m_curr_active_window_idx = idx;
1498262182Semaste                        break;
1499262182Semaste                    }
1500262182Semaste                    ++idx;
1501262182Semaste                }
1502262182Semaste            }
1503262182Semaste            else if (m_curr_active_window_idx + 1 < num_subwindows)
1504262182Semaste            {
1505262182Semaste                bool handled = false;
1506262182Semaste                m_prev_active_window_idx = m_curr_active_window_idx;
1507262182Semaste                for (size_t idx=m_curr_active_window_idx + 1; idx<num_subwindows; ++idx)
1508262182Semaste                {
1509262182Semaste                    if (m_subwindows[idx]->GetCanBeActive())
1510262182Semaste                    {
1511262182Semaste                        m_curr_active_window_idx = idx;
1512262182Semaste                        handled = true;
1513262182Semaste                        break;
1514262182Semaste                    }
1515262182Semaste                }
1516262182Semaste                if (!handled)
1517262182Semaste                {
1518262182Semaste                    for (size_t idx=0; idx<=m_prev_active_window_idx; ++idx)
1519262182Semaste                    {
1520262182Semaste                        if (m_subwindows[idx]->GetCanBeActive())
1521262182Semaste                        {
1522262182Semaste                            m_curr_active_window_idx = idx;
1523262182Semaste                            break;
1524262182Semaste                        }
1525262182Semaste                    }
1526262182Semaste                }
1527262182Semaste            }
1528262182Semaste            else
1529262182Semaste            {
1530262182Semaste                m_prev_active_window_idx = m_curr_active_window_idx;
1531262182Semaste                for (size_t idx=0; idx<num_subwindows; ++idx)
1532262182Semaste                {
1533262182Semaste                    if (m_subwindows[idx]->GetCanBeActive())
1534262182Semaste                    {
1535262182Semaste                        m_curr_active_window_idx = idx;
1536262182Semaste                        break;
1537262182Semaste                    }
1538262182Semaste                }
1539262182Semaste            }
1540262182Semaste        }
1541262182Semaste
1542262182Semaste        const char *
1543262182Semaste        GetName () const
1544262182Semaste        {
1545262182Semaste            return m_name.c_str();
1546262182Semaste        }
1547262182Semaste    protected:
1548262182Semaste        std::string m_name;
1549262182Semaste        WINDOW *m_window;
1550262182Semaste        PANEL *m_panel;
1551262182Semaste        Window *m_parent;
1552262182Semaste        Windows m_subwindows;
1553262182Semaste        WindowDelegateSP m_delegate_sp;
1554262182Semaste        uint32_t m_curr_active_window_idx;
1555262182Semaste        uint32_t m_prev_active_window_idx;
1556262182Semaste        bool m_delete;
1557262182Semaste        bool m_needs_update;
1558262182Semaste        bool m_can_activate;
1559262182Semaste        bool m_is_subwin;
1560262182Semaste
1561262182Semaste    private:
1562262182Semaste        DISALLOW_COPY_AND_ASSIGN(Window);
1563262182Semaste    };
1564262182Semaste
1565262182Semaste    class MenuDelegate
1566262182Semaste    {
1567262182Semaste    public:
1568262182Semaste        virtual ~MenuDelegate() {}
1569262182Semaste
1570262182Semaste        virtual MenuActionResult
1571262182Semaste        MenuDelegateAction (Menu &menu) = 0;
1572262182Semaste    };
1573262182Semaste
1574262182Semaste    class Menu : public WindowDelegate
1575262182Semaste    {
1576262182Semaste    public:
1577262182Semaste        enum class Type
1578262182Semaste        {
1579262182Semaste            Invalid,
1580262182Semaste            Bar,
1581262182Semaste            Item,
1582262182Semaste            Separator
1583262182Semaste        };
1584262182Semaste
1585262182Semaste        // Menubar or separator constructor
1586262182Semaste        Menu (Type type);
1587262182Semaste
1588262182Semaste        // Menuitem constructor
1589262182Semaste        Menu (const char *name,
1590262182Semaste              const char *key_name,
1591262182Semaste              int key_value,
1592262182Semaste              uint64_t identifier);
1593262182Semaste
1594262182Semaste        virtual ~
1595262182Semaste        Menu ()
1596262182Semaste        {
1597262182Semaste        }
1598262182Semaste
1599262182Semaste        const MenuDelegateSP &
1600262182Semaste        GetDelegate () const
1601262182Semaste        {
1602262182Semaste            return m_delegate_sp;
1603262182Semaste        }
1604262182Semaste
1605262182Semaste        void
1606262182Semaste        SetDelegate (const MenuDelegateSP &delegate_sp)
1607262182Semaste        {
1608262182Semaste            m_delegate_sp = delegate_sp;
1609262182Semaste        }
1610262182Semaste
1611262182Semaste        void
1612262182Semaste        RecalculateNameLengths();
1613262182Semaste
1614262182Semaste        void
1615262182Semaste        AddSubmenu (const MenuSP &menu_sp);
1616262182Semaste
1617262182Semaste        int
1618262182Semaste        DrawAndRunMenu (Window &window);
1619262182Semaste
1620262182Semaste        void
1621262182Semaste        DrawMenuTitle (Window &window, bool highlight);
1622262182Semaste
1623262182Semaste        virtual bool
1624262182Semaste        WindowDelegateDraw (Window &window, bool force);
1625262182Semaste
1626262182Semaste        virtual HandleCharResult
1627262182Semaste        WindowDelegateHandleChar (Window &window, int key);
1628262182Semaste
1629262182Semaste        MenuActionResult
1630262182Semaste        ActionPrivate (Menu &menu)
1631262182Semaste        {
1632262182Semaste            MenuActionResult result = MenuActionResult::NotHandled;
1633262182Semaste            if (m_delegate_sp)
1634262182Semaste            {
1635262182Semaste                result = m_delegate_sp->MenuDelegateAction (menu);
1636262182Semaste                if (result != MenuActionResult::NotHandled)
1637262182Semaste                    return result;
1638262182Semaste            }
1639262182Semaste            else if (m_parent)
1640262182Semaste            {
1641262182Semaste                result = m_parent->ActionPrivate(menu);
1642262182Semaste                if (result != MenuActionResult::NotHandled)
1643262182Semaste                    return result;
1644262182Semaste            }
1645262182Semaste            return m_canned_result;
1646262182Semaste        }
1647262182Semaste
1648262182Semaste        MenuActionResult
1649262182Semaste        Action ()
1650262182Semaste        {
1651262182Semaste            // Call the recursive action so it can try to handle it
1652262182Semaste            // with the menu delegate, and if not, try our parent menu
1653262182Semaste            return ActionPrivate (*this);
1654262182Semaste        }
1655262182Semaste
1656262182Semaste        void
1657262182Semaste        SetCannedResult (MenuActionResult result)
1658262182Semaste        {
1659262182Semaste            m_canned_result = result;
1660262182Semaste        }
1661262182Semaste
1662262182Semaste        Menus &
1663262182Semaste        GetSubmenus()
1664262182Semaste        {
1665262182Semaste            return m_submenus;
1666262182Semaste        }
1667262182Semaste
1668262182Semaste        const Menus &
1669262182Semaste        GetSubmenus() const
1670262182Semaste        {
1671262182Semaste            return m_submenus;
1672262182Semaste        }
1673262182Semaste
1674262182Semaste        int
1675262182Semaste        GetSelectedSubmenuIndex () const
1676262182Semaste        {
1677262182Semaste            return m_selected;
1678262182Semaste        }
1679262182Semaste
1680262182Semaste        void
1681262182Semaste        SetSelectedSubmenuIndex (int idx)
1682262182Semaste        {
1683262182Semaste            m_selected = idx;
1684262182Semaste        }
1685262182Semaste
1686262182Semaste        Type
1687262182Semaste        GetType () const
1688262182Semaste        {
1689262182Semaste            return m_type;
1690262182Semaste        }
1691262182Semaste
1692262182Semaste        int
1693262182Semaste        GetStartingColumn() const
1694262182Semaste        {
1695262182Semaste            return m_start_col;
1696262182Semaste        }
1697262182Semaste
1698262182Semaste        void
1699262182Semaste        SetStartingColumn(int col)
1700262182Semaste        {
1701262182Semaste            m_start_col = col;
1702262182Semaste        }
1703262182Semaste
1704262182Semaste        int
1705262182Semaste        GetKeyValue() const
1706262182Semaste        {
1707262182Semaste            return m_key_value;
1708262182Semaste        }
1709262182Semaste
1710262182Semaste        void
1711262182Semaste        SetKeyValue(int key_value)
1712262182Semaste        {
1713262182Semaste            m_key_value = key_value;
1714262182Semaste        }
1715262182Semaste
1716262182Semaste        std::string &
1717262182Semaste        GetName()
1718262182Semaste        {
1719262182Semaste            return m_name;
1720262182Semaste        }
1721262182Semaste
1722262182Semaste        std::string &
1723262182Semaste        GetKeyName()
1724262182Semaste        {
1725262182Semaste            return m_key_name;
1726262182Semaste        }
1727262182Semaste
1728262182Semaste        int
1729262182Semaste        GetDrawWidth () const
1730262182Semaste        {
1731262182Semaste            return m_max_submenu_name_length + m_max_submenu_key_name_length + 8;
1732262182Semaste        }
1733262182Semaste
1734262182Semaste
1735262182Semaste        uint64_t
1736262182Semaste        GetIdentifier() const
1737262182Semaste        {
1738262182Semaste            return m_identifier;
1739262182Semaste        }
1740262182Semaste
1741262182Semaste        void
1742262182Semaste        SetIdentifier (uint64_t identifier)
1743262182Semaste        {
1744262182Semaste            m_identifier = identifier;
1745262182Semaste        }
1746262182Semaste
1747262182Semaste    protected:
1748262182Semaste        std::string m_name;
1749262182Semaste        std::string m_key_name;
1750262182Semaste        uint64_t m_identifier;
1751262182Semaste        Type m_type;
1752262182Semaste        int m_key_value;
1753262182Semaste        int m_start_col;
1754262182Semaste        int m_max_submenu_name_length;
1755262182Semaste        int m_max_submenu_key_name_length;
1756262182Semaste        int m_selected;
1757262182Semaste        Menu *m_parent;
1758262182Semaste        Menus m_submenus;
1759262182Semaste        WindowSP m_menu_window_sp;
1760262182Semaste        MenuActionResult m_canned_result;
1761262182Semaste        MenuDelegateSP m_delegate_sp;
1762262182Semaste    };
1763262182Semaste
1764262182Semaste    // Menubar or separator constructor
1765262182Semaste    Menu::Menu (Type type) :
1766262182Semaste        m_name (),
1767262182Semaste        m_key_name (),
1768262182Semaste        m_identifier (0),
1769262182Semaste        m_type (type),
1770262182Semaste        m_key_value (0),
1771262182Semaste        m_start_col (0),
1772262182Semaste        m_max_submenu_name_length (0),
1773262182Semaste        m_max_submenu_key_name_length (0),
1774262182Semaste        m_selected (0),
1775262182Semaste        m_parent (NULL),
1776262182Semaste        m_submenus (),
1777262182Semaste        m_canned_result (MenuActionResult::NotHandled),
1778262182Semaste        m_delegate_sp()
1779262182Semaste    {
1780262182Semaste    }
1781262182Semaste
1782262182Semaste    // Menuitem constructor
1783262182Semaste    Menu::Menu (const char *name,
1784262182Semaste                const char *key_name,
1785262182Semaste                int key_value,
1786262182Semaste                uint64_t identifier) :
1787262182Semaste        m_name (),
1788262182Semaste        m_key_name (),
1789262182Semaste        m_identifier (identifier),
1790262182Semaste        m_type (Type::Invalid),
1791262182Semaste        m_key_value (key_value),
1792262182Semaste        m_start_col (0),
1793262182Semaste        m_max_submenu_name_length (0),
1794262182Semaste        m_max_submenu_key_name_length (0),
1795262182Semaste        m_selected (0),
1796262182Semaste        m_parent (NULL),
1797262182Semaste        m_submenus (),
1798262182Semaste        m_canned_result (MenuActionResult::NotHandled),
1799262182Semaste        m_delegate_sp()
1800262182Semaste    {
1801262182Semaste        if (name && name[0])
1802262182Semaste        {
1803262182Semaste            m_name = name;
1804262182Semaste            m_type = Type::Item;
1805262182Semaste            if (key_name && key_name[0])
1806262182Semaste                m_key_name = key_name;
1807262182Semaste        }
1808262182Semaste        else
1809262182Semaste        {
1810262182Semaste            m_type = Type::Separator;
1811262182Semaste        }
1812262182Semaste    }
1813262182Semaste
1814262182Semaste    void
1815262182Semaste    Menu::RecalculateNameLengths()
1816262182Semaste    {
1817262182Semaste        m_max_submenu_name_length = 0;
1818262182Semaste        m_max_submenu_key_name_length = 0;
1819262182Semaste        Menus &submenus = GetSubmenus();
1820262182Semaste        const size_t num_submenus = submenus.size();
1821262182Semaste        for (size_t i=0; i<num_submenus; ++i)
1822262182Semaste        {
1823262182Semaste            Menu *submenu = submenus[i].get();
1824262182Semaste            if (m_max_submenu_name_length < submenu->m_name.size())
1825262182Semaste                m_max_submenu_name_length = submenu->m_name.size();
1826262182Semaste            if (m_max_submenu_key_name_length < submenu->m_key_name.size())
1827262182Semaste                m_max_submenu_key_name_length = submenu->m_key_name.size();
1828262182Semaste        }
1829262182Semaste    }
1830262182Semaste
1831262182Semaste    void
1832262182Semaste    Menu::AddSubmenu (const MenuSP &menu_sp)
1833262182Semaste    {
1834262182Semaste        menu_sp->m_parent = this;
1835262182Semaste        if (m_max_submenu_name_length < menu_sp->m_name.size())
1836262182Semaste            m_max_submenu_name_length = menu_sp->m_name.size();
1837262182Semaste        if (m_max_submenu_key_name_length < menu_sp->m_key_name.size())
1838262182Semaste            m_max_submenu_key_name_length = menu_sp->m_key_name.size();
1839262182Semaste        m_submenus.push_back(menu_sp);
1840262182Semaste    }
1841262182Semaste
1842262182Semaste    void
1843262182Semaste    Menu::DrawMenuTitle (Window &window, bool highlight)
1844262182Semaste    {
1845262182Semaste        if (m_type == Type::Separator)
1846262182Semaste        {
1847262182Semaste            window.MoveCursor(0, window.GetCursorY());
1848262182Semaste            window.PutChar(ACS_LTEE);
1849262182Semaste            int width = window.GetWidth();
1850262182Semaste            if (width > 2)
1851262182Semaste            {
1852262182Semaste                width -= 2;
1853262182Semaste                for (size_t i=0; i< width; ++i)
1854262182Semaste                    window.PutChar(ACS_HLINE);
1855262182Semaste            }
1856262182Semaste            window.PutChar(ACS_RTEE);
1857262182Semaste        }
1858262182Semaste        else
1859262182Semaste        {
1860262182Semaste            const int shortcut_key = m_key_value;
1861262182Semaste            bool underlined_shortcut = false;
1862262182Semaste            const attr_t hilgight_attr = A_REVERSE;
1863262182Semaste            if (highlight)
1864262182Semaste                window.AttributeOn(hilgight_attr);
1865262182Semaste            if (isprint(shortcut_key))
1866262182Semaste            {
1867262182Semaste                size_t lower_pos = m_name.find(tolower(shortcut_key));
1868262182Semaste                size_t upper_pos = m_name.find(toupper(shortcut_key));
1869262182Semaste                const char *name = m_name.c_str();
1870262182Semaste                size_t pos = std::min<size_t>(lower_pos, upper_pos);
1871262182Semaste                if (pos != std::string::npos)
1872262182Semaste                {
1873262182Semaste                    underlined_shortcut = true;
1874262182Semaste                    if (pos > 0)
1875262182Semaste                    {
1876262182Semaste                        window.PutCString(name, pos);
1877262182Semaste                        name += pos;
1878262182Semaste                    }
1879262182Semaste                    const attr_t shortcut_attr = A_UNDERLINE|A_BOLD;
1880262182Semaste                    window.AttributeOn (shortcut_attr);
1881262182Semaste                    window.PutChar(name[0]);
1882262182Semaste                    window.AttributeOff(shortcut_attr);
1883262182Semaste                    name++;
1884262182Semaste                    if (name[0])
1885262182Semaste                        window.PutCString(name);
1886262182Semaste                }
1887262182Semaste            }
1888262182Semaste
1889262182Semaste            if (!underlined_shortcut)
1890262182Semaste            {
1891262182Semaste                window.PutCString(m_name.c_str());
1892262182Semaste            }
1893262182Semaste
1894262182Semaste            if (highlight)
1895262182Semaste                window.AttributeOff(hilgight_attr);
1896262182Semaste
1897262182Semaste            if (m_key_name.empty())
1898262182Semaste            {
1899262182Semaste                if (!underlined_shortcut && isprint(m_key_value))
1900262182Semaste                {
1901262182Semaste                    window.AttributeOn (COLOR_PAIR(3));
1902262182Semaste                    window.Printf (" (%c)", m_key_value);
1903262182Semaste                    window.AttributeOff (COLOR_PAIR(3));
1904262182Semaste                }
1905262182Semaste            }
1906262182Semaste            else
1907262182Semaste            {
1908262182Semaste                window.AttributeOn (COLOR_PAIR(3));
1909262182Semaste                window.Printf (" (%s)", m_key_name.c_str());
1910262182Semaste                window.AttributeOff (COLOR_PAIR(3));
1911262182Semaste            }
1912262182Semaste        }
1913262182Semaste    }
1914262182Semaste
1915262182Semaste    bool
1916262182Semaste    Menu::WindowDelegateDraw (Window &window, bool force)
1917262182Semaste    {
1918262182Semaste        Menus &submenus = GetSubmenus();
1919262182Semaste        const size_t num_submenus = submenus.size();
1920262182Semaste        const int selected_idx = GetSelectedSubmenuIndex();
1921262182Semaste        Menu::Type menu_type = GetType ();
1922262182Semaste        switch (menu_type)
1923262182Semaste        {
1924262182Semaste        case  Menu::Type::Bar:
1925262182Semaste            {
1926262182Semaste                window.SetBackground(2);
1927262182Semaste                window.MoveCursor(0, 0);
1928262182Semaste                for (size_t i=0; i<num_submenus; ++i)
1929262182Semaste                {
1930262182Semaste                    Menu *menu = submenus[i].get();
1931262182Semaste                    if (i > 0)
1932262182Semaste                        window.PutChar(' ');
1933262182Semaste                    menu->SetStartingColumn (window.GetCursorX());
1934262182Semaste                    window.PutCString("| ");
1935262182Semaste                    menu->DrawMenuTitle (window, false);
1936262182Semaste                }
1937262182Semaste                window.PutCString(" |");
1938262182Semaste                window.DeferredRefresh();
1939262182Semaste            }
1940262182Semaste            break;
1941262182Semaste
1942262182Semaste        case Menu::Type::Item:
1943262182Semaste            {
1944262182Semaste                int y = 1;
1945262182Semaste                int x = 3;
1946262182Semaste                // Draw the menu
1947262182Semaste                int cursor_x = 0;
1948262182Semaste                int cursor_y = 0;
1949262182Semaste                window.Erase();
1950262182Semaste                window.SetBackground(2);
1951262182Semaste                window.Box();
1952262182Semaste                for (size_t i=0; i<num_submenus; ++i)
1953262182Semaste                {
1954262182Semaste                    const bool is_selected = i == selected_idx;
1955262182Semaste                    window.MoveCursor(x, y + i);
1956262182Semaste                    if (is_selected)
1957262182Semaste                    {
1958262182Semaste                        // Remember where we want the cursor to be
1959262182Semaste                        cursor_x = x-1;
1960262182Semaste                        cursor_y = y+i;
1961262182Semaste                    }
1962262182Semaste                    submenus[i]->DrawMenuTitle (window, is_selected);
1963262182Semaste                }
1964262182Semaste                window.MoveCursor(cursor_x, cursor_y);
1965262182Semaste                window.DeferredRefresh();
1966262182Semaste            }
1967262182Semaste            break;
1968262182Semaste
1969262182Semaste        default:
1970262182Semaste        case Menu::Type::Separator:
1971262182Semaste            break;
1972262182Semaste        }
1973262182Semaste        return true; // Drawing handled...
1974262182Semaste    }
1975262182Semaste
1976262182Semaste    HandleCharResult
1977262182Semaste    Menu::WindowDelegateHandleChar (Window &window, int key)
1978262182Semaste    {
1979262182Semaste        HandleCharResult result = eKeyNotHandled;
1980262182Semaste
1981262182Semaste        Menus &submenus = GetSubmenus();
1982262182Semaste        const size_t num_submenus = submenus.size();
1983262182Semaste        const int selected_idx = GetSelectedSubmenuIndex();
1984262182Semaste        Menu::Type menu_type = GetType ();
1985262182Semaste        if (menu_type == Menu::Type::Bar)
1986262182Semaste        {
1987262182Semaste            MenuSP run_menu_sp;
1988262182Semaste            switch (key)
1989262182Semaste            {
1990262182Semaste                case KEY_DOWN:
1991262182Semaste                case KEY_UP:
1992262182Semaste                    // Show last menu or first menu
1993262182Semaste                    if (selected_idx < num_submenus)
1994262182Semaste                        run_menu_sp = submenus[selected_idx];
1995262182Semaste                    else if (!submenus.empty())
1996262182Semaste                        run_menu_sp = submenus.front();
1997262182Semaste                    result = eKeyHandled;
1998262182Semaste                    break;
1999262182Semaste
2000262182Semaste                case KEY_RIGHT:
2001262182Semaste                {
2002262182Semaste                    ++m_selected;
2003262182Semaste                    if (m_selected >= num_submenus)
2004262182Semaste                        m_selected = 0;
2005262182Semaste                    if (m_selected < num_submenus)
2006262182Semaste                        run_menu_sp = submenus[m_selected];
2007262182Semaste                    else if (!submenus.empty())
2008262182Semaste                        run_menu_sp = submenus.front();
2009262182Semaste                    result = eKeyHandled;
2010262182Semaste                }
2011262182Semaste                    break;
2012262182Semaste
2013262182Semaste                case KEY_LEFT:
2014262182Semaste                {
2015262182Semaste                    --m_selected;
2016262182Semaste                    if (m_selected < 0)
2017262182Semaste                        m_selected = num_submenus - 1;
2018262182Semaste                    if (m_selected < num_submenus)
2019262182Semaste                        run_menu_sp = submenus[m_selected];
2020262182Semaste                    else if (!submenus.empty())
2021262182Semaste                        run_menu_sp = submenus.front();
2022262182Semaste                    result = eKeyHandled;
2023262182Semaste                }
2024262182Semaste                    break;
2025262182Semaste
2026262182Semaste                default:
2027262182Semaste                    for (size_t i=0; i<num_submenus; ++i)
2028262182Semaste                    {
2029262182Semaste                        if (submenus[i]->GetKeyValue() == key)
2030262182Semaste                        {
2031262182Semaste                            SetSelectedSubmenuIndex(i);
2032262182Semaste                            run_menu_sp = submenus[i];
2033262182Semaste                            result = eKeyHandled;
2034262182Semaste                            break;
2035262182Semaste                        }
2036262182Semaste                    }
2037262182Semaste                    break;
2038262182Semaste            }
2039262182Semaste
2040262182Semaste            if (run_menu_sp)
2041262182Semaste            {
2042262182Semaste                // Run the action on this menu in case we need to populate the
2043262182Semaste                // menu with dynamic content and also in case check marks, and
2044262182Semaste                // any other menu decorations need to be caclulated
2045262182Semaste                if (run_menu_sp->Action() == MenuActionResult::Quit)
2046262182Semaste                    return eQuitApplication;
2047262182Semaste
2048262182Semaste                Rect menu_bounds;
2049262182Semaste                menu_bounds.origin.x = run_menu_sp->GetStartingColumn();
2050262182Semaste                menu_bounds.origin.y = 1;
2051262182Semaste                menu_bounds.size.width = run_menu_sp->GetDrawWidth();
2052262182Semaste                menu_bounds.size.height = run_menu_sp->GetSubmenus().size() + 2;
2053262182Semaste                if (m_menu_window_sp)
2054262182Semaste                    window.GetParent()->RemoveSubWindow(m_menu_window_sp.get());
2055262182Semaste
2056262182Semaste                m_menu_window_sp = window.GetParent()->CreateSubWindow (run_menu_sp->GetName().c_str(),
2057262182Semaste                                                                        menu_bounds,
2058262182Semaste                                                                        true);
2059262182Semaste                m_menu_window_sp->SetDelegate (run_menu_sp);
2060262182Semaste            }
2061262182Semaste        }
2062262182Semaste        else if (menu_type == Menu::Type::Item)
2063262182Semaste        {
2064262182Semaste            switch (key)
2065262182Semaste            {
2066262182Semaste                case KEY_DOWN:
2067262182Semaste                    if (m_submenus.size() > 1)
2068262182Semaste                    {
2069262182Semaste                        const int start_select = m_selected;
2070262182Semaste                        while (++m_selected != start_select)
2071262182Semaste                        {
2072262182Semaste                            if (m_selected >= num_submenus)
2073262182Semaste                                m_selected = 0;
2074262182Semaste                            if (m_submenus[m_selected]->GetType() == Type::Separator)
2075262182Semaste                                continue;
2076262182Semaste                            else
2077262182Semaste                                break;
2078262182Semaste                        }
2079262182Semaste                        return eKeyHandled;
2080262182Semaste                    }
2081262182Semaste                    break;
2082262182Semaste
2083262182Semaste                case KEY_UP:
2084262182Semaste                    if (m_submenus.size() > 1)
2085262182Semaste                    {
2086262182Semaste                        const int start_select = m_selected;
2087262182Semaste                        while (--m_selected != start_select)
2088262182Semaste                        {
2089262182Semaste                            if (m_selected < 0)
2090262182Semaste                                m_selected = num_submenus - 1;
2091262182Semaste                            if (m_submenus[m_selected]->GetType() == Type::Separator)
2092262182Semaste                                continue;
2093262182Semaste                            else
2094262182Semaste                                break;
2095262182Semaste                        }
2096262182Semaste                        return eKeyHandled;
2097262182Semaste                    }
2098262182Semaste                    break;
2099262182Semaste
2100262182Semaste                case KEY_RETURN:
2101262182Semaste                    if (selected_idx < num_submenus)
2102262182Semaste                    {
2103262182Semaste                        if (submenus[selected_idx]->Action() == MenuActionResult::Quit)
2104262182Semaste                            return eQuitApplication;
2105262182Semaste                        window.GetParent()->RemoveSubWindow(&window);
2106262182Semaste                        return eKeyHandled;
2107262182Semaste                    }
2108262182Semaste                    break;
2109262182Semaste
2110262182Semaste                case KEY_ESCAPE: // Beware: pressing escape key has 1 to 2 second delay in case other chars are entered for escaped sequences
2111262182Semaste                    window.GetParent()->RemoveSubWindow(&window);
2112262182Semaste                    return eKeyHandled;
2113262182Semaste
2114262182Semaste                default:
2115262182Semaste                {
2116262182Semaste                    bool handled = false;
2117262182Semaste                    for (size_t i=0; i<num_submenus; ++i)
2118262182Semaste                    {
2119262182Semaste                        Menu *menu = submenus[i].get();
2120262182Semaste                        if (menu->GetKeyValue() == key)
2121262182Semaste                        {
2122262182Semaste                            handled = true;
2123262182Semaste                            SetSelectedSubmenuIndex(i);
2124262182Semaste                            window.GetParent()->RemoveSubWindow(&window);
2125262182Semaste                            if (menu->Action() == MenuActionResult::Quit)
2126262182Semaste                                return eQuitApplication;
2127262182Semaste                            return eKeyHandled;
2128262182Semaste                        }
2129262182Semaste                    }
2130262182Semaste                }
2131262182Semaste                    break;
2132262182Semaste
2133262182Semaste            }
2134262182Semaste        }
2135262182Semaste        else if (menu_type == Menu::Type::Separator)
2136262182Semaste        {
2137262182Semaste
2138262182Semaste        }
2139262182Semaste        return result;
2140262182Semaste    }
2141262182Semaste
2142262182Semaste
2143262182Semaste    class Application
2144262182Semaste    {
2145262182Semaste    public:
2146262182Semaste        Application (FILE *in, FILE *out) :
2147262182Semaste            m_window_sp(),
2148262182Semaste            m_screen (NULL),
2149262182Semaste            m_in (in),
2150262182Semaste            m_out (out)
2151262182Semaste        {
2152262182Semaste
2153262182Semaste        }
2154262182Semaste
2155262182Semaste        ~Application ()
2156262182Semaste        {
2157262182Semaste            m_window_delegates.clear();
2158262182Semaste            m_window_sp.reset();
2159262182Semaste            if (m_screen)
2160262182Semaste            {
2161262182Semaste                ::delscreen(m_screen);
2162262182Semaste                m_screen = NULL;
2163262182Semaste            }
2164262182Semaste        }
2165262182Semaste
2166262182Semaste        void
2167262182Semaste        Initialize ()
2168262182Semaste        {
2169262182Semaste            ::setlocale(LC_ALL, "");
2170262182Semaste            ::setlocale(LC_CTYPE, "");
2171262182Semaste#if 0
2172262182Semaste            ::initscr();
2173262182Semaste#else
2174262182Semaste            m_screen = ::newterm(NULL, m_out, m_in);
2175262182Semaste#endif
2176262182Semaste            ::start_color();
2177262182Semaste            ::curs_set(0);
2178262182Semaste            ::noecho();
2179262182Semaste            ::keypad(stdscr,TRUE);
2180262182Semaste        }
2181262182Semaste
2182262182Semaste        void
2183262182Semaste        Terminate ()
2184262182Semaste        {
2185262182Semaste            ::endwin();
2186262182Semaste        }
2187262182Semaste
2188262182Semaste        void
2189262182Semaste        Run (Debugger &debugger)
2190262182Semaste        {
2191262182Semaste            bool done = false;
2192262182Semaste            int delay_in_tenths_of_a_second = 1;
2193262182Semaste
2194262182Semaste            // Alas the threading model in curses is a bit lame so we need to
2195262182Semaste            // resort to polling every 0.5 seconds. We could poll for stdin
2196262182Semaste            // ourselves and then pass the keys down but then we need to
2197262182Semaste            // translate all of the escape sequences ourselves. So we resort to
2198262182Semaste            // polling for input because we need to receive async process events
2199262182Semaste            // while in this loop.
2200262182Semaste
2201262182Semaste            halfdelay(delay_in_tenths_of_a_second); // Poll using some number of tenths of seconds seconds when calling Window::GetChar()
2202262182Semaste
2203262182Semaste            ListenerSP listener_sp (new Listener ("lldb.IOHandler.curses.Application"));
2204262182Semaste            ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass());
2205262182Semaste            ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass());
2206262182Semaste            ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass());
2207262182Semaste            debugger.EnableForwardEvents (listener_sp);
2208262182Semaste
2209262182Semaste            bool update = true;
2210262182Semaste#if defined(__APPLE__)
2211262182Semaste            std::deque<int> escape_chars;
2212262182Semaste#endif
2213262182Semaste
2214262182Semaste            while (!done)
2215262182Semaste            {
2216262182Semaste                if (update)
2217262182Semaste                {
2218262182Semaste                    m_window_sp->Draw(false);
2219262182Semaste                    // All windows should be calling Window::DeferredRefresh() instead
2220262182Semaste                    // of Window::Refresh() so we can do a single update and avoid
2221262182Semaste                    // any screen blinking
2222262182Semaste                    update_panels();
2223262182Semaste
2224262182Semaste                    // Cursor hiding isn't working on MacOSX, so hide it in the top left corner
2225262182Semaste                    m_window_sp->MoveCursor(0, 0);
2226262182Semaste
2227262182Semaste                    doupdate();
2228262182Semaste                    update = false;
2229262182Semaste                }
2230262182Semaste
2231262182Semaste#if defined(__APPLE__)
2232262182Semaste                // Terminal.app doesn't map its function keys correctly, F1-F4 default to:
2233262182Semaste                // \033OP, \033OQ, \033OR, \033OS, so lets take care of this here if possible
2234262182Semaste                int ch;
2235262182Semaste                if (escape_chars.empty())
2236262182Semaste                    ch = m_window_sp->GetChar();
2237262182Semaste                else
2238262182Semaste                {
2239262182Semaste                    ch = escape_chars.front();
2240262182Semaste                    escape_chars.pop_front();
2241262182Semaste                }
2242262182Semaste                if (ch == KEY_ESCAPE)
2243262182Semaste                {
2244262182Semaste                    int ch2 = m_window_sp->GetChar();
2245262182Semaste                    if (ch2 == 'O')
2246262182Semaste                    {
2247262182Semaste                        int ch3 = m_window_sp->GetChar();
2248262182Semaste                        switch (ch3)
2249262182Semaste                        {
2250262182Semaste                            case 'P': ch = KEY_F(1); break;
2251262182Semaste                            case 'Q': ch = KEY_F(2); break;
2252262182Semaste                            case 'R': ch = KEY_F(3); break;
2253262182Semaste                            case 'S': ch = KEY_F(4); break;
2254262182Semaste                            default:
2255262182Semaste                                escape_chars.push_back(ch2);
2256262182Semaste                                if (ch3 != -1)
2257262182Semaste                                    escape_chars.push_back(ch3);
2258262182Semaste                                break;
2259262182Semaste                        }
2260262182Semaste                    }
2261262182Semaste                    else if (ch2 != -1)
2262262182Semaste                        escape_chars.push_back(ch2);
2263262182Semaste                }
2264262182Semaste#else
2265262182Semaste                int ch = m_window_sp->GetChar();
2266262182Semaste
2267262182Semaste#endif
2268262182Semaste                if (ch == -1)
2269262182Semaste                {
2270262182Semaste                    if (feof(m_in) || ferror(m_in))
2271262182Semaste                    {
2272262182Semaste                        done = true;
2273262182Semaste                    }
2274262182Semaste                    else
2275262182Semaste                    {
2276262182Semaste                        // Just a timeout from using halfdelay(), check for events
2277262182Semaste                        EventSP event_sp;
2278262182Semaste                        while (listener_sp->PeekAtNextEvent())
2279262182Semaste                        {
2280262182Semaste                            listener_sp->GetNextEvent(event_sp);
2281262182Semaste
2282262182Semaste                            if (event_sp)
2283262182Semaste                            {
2284262182Semaste                                Broadcaster *broadcaster = event_sp->GetBroadcaster();
2285262182Semaste                                if (broadcaster)
2286262182Semaste                                {
2287262182Semaste                                    //uint32_t event_type = event_sp->GetType();
2288262182Semaste                                    ConstString broadcaster_class (broadcaster->GetBroadcasterClass());
2289262182Semaste                                    if (broadcaster_class == broadcaster_class_process)
2290262182Semaste                                    {
2291262182Semaste                                        update = true;
2292262182Semaste                                        continue; // Don't get any key, just update our view
2293262182Semaste                                    }
2294262182Semaste                                }
2295262182Semaste                            }
2296262182Semaste                        }
2297262182Semaste                    }
2298262182Semaste                }
2299262182Semaste                else
2300262182Semaste                {
2301262182Semaste                    HandleCharResult key_result = m_window_sp->HandleChar(ch);
2302262182Semaste                    switch (key_result)
2303262182Semaste                    {
2304262182Semaste                        case eKeyHandled:
2305262182Semaste                            update = true;
2306262182Semaste                            break;
2307262182Semaste                        case eKeyNotHandled:
2308262182Semaste                            break;
2309262182Semaste                        case eQuitApplication:
2310262182Semaste                            done = true;
2311262182Semaste                            break;
2312262182Semaste                    }
2313262182Semaste                }
2314262182Semaste            }
2315262182Semaste
2316262182Semaste            debugger.CancelForwardEvents (listener_sp);
2317262182Semaste
2318262182Semaste        }
2319262182Semaste
2320262182Semaste        WindowSP &
2321262182Semaste        GetMainWindow ()
2322262182Semaste        {
2323262182Semaste            if (!m_window_sp)
2324262182Semaste                m_window_sp.reset (new Window ("main", stdscr, false));
2325262182Semaste            return m_window_sp;
2326262182Semaste        }
2327262182Semaste
2328262182Semaste        WindowDelegates &
2329262182Semaste        GetWindowDelegates ()
2330262182Semaste        {
2331262182Semaste            return m_window_delegates;
2332262182Semaste        }
2333262182Semaste
2334262182Semaste    protected:
2335262182Semaste        WindowSP m_window_sp;
2336262182Semaste        WindowDelegates m_window_delegates;
2337262182Semaste        SCREEN *m_screen;
2338262182Semaste        FILE *m_in;
2339262182Semaste        FILE *m_out;
2340262182Semaste    };
2341262182Semaste
2342262182Semaste
2343262182Semaste} // namespace curses
2344262182Semaste
2345262182Semaste
2346262182Semasteusing namespace curses;
2347262182Semaste
2348262182Semastestruct Row
2349262182Semaste{
2350262182Semaste    ValueObjectSP valobj;
2351262182Semaste    Row *parent;
2352262182Semaste    int row_idx;
2353262182Semaste    int x;
2354262182Semaste    int y;
2355262182Semaste    bool might_have_children;
2356262182Semaste    bool expanded;
2357262182Semaste    bool calculated_children;
2358262182Semaste    std::vector<Row> children;
2359262182Semaste
2360262182Semaste    Row (const ValueObjectSP &v, Row *p) :
2361262182Semaste    valobj (v),
2362262182Semaste    parent (p),
2363262182Semaste    row_idx(0),
2364262182Semaste    x(1),
2365262182Semaste    y(1),
2366262182Semaste    might_have_children (v ? v->MightHaveChildren() : false),
2367262182Semaste    expanded (false),
2368262182Semaste    calculated_children (false),
2369262182Semaste    children()
2370262182Semaste    {
2371262182Semaste    }
2372262182Semaste
2373262182Semaste    size_t
2374262182Semaste    GetDepth () const
2375262182Semaste    {
2376262182Semaste        if (parent)
2377262182Semaste            return 1 + parent->GetDepth();
2378262182Semaste        return 0;
2379262182Semaste    }
2380262182Semaste
2381262182Semaste    void
2382262182Semaste    Expand()
2383262182Semaste    {
2384262182Semaste        expanded = true;
2385262182Semaste        if (!calculated_children)
2386262182Semaste        {
2387262182Semaste            calculated_children = true;
2388262182Semaste            if (valobj)
2389262182Semaste            {
2390262182Semaste                const size_t num_children = valobj->GetNumChildren();
2391262182Semaste                for (size_t i=0; i<num_children; ++i)
2392262182Semaste                {
2393262182Semaste                    children.push_back(Row (valobj->GetChildAtIndex(i, true), this));
2394262182Semaste                }
2395262182Semaste            }
2396262182Semaste        }
2397262182Semaste    }
2398262182Semaste
2399262182Semaste    void
2400262182Semaste    Unexpand ()
2401262182Semaste    {
2402262182Semaste        expanded = false;
2403262182Semaste    }
2404262182Semaste
2405262182Semaste    void
2406262182Semaste    DrawTree (Window &window)
2407262182Semaste    {
2408262182Semaste        if (parent)
2409262182Semaste            parent->DrawTreeForChild (window, this, 0);
2410262182Semaste
2411262182Semaste        if (might_have_children)
2412262182Semaste        {
2413262182Semaste            // It we can get UTF8 characters to work we should try to use the "symbol"
2414262182Semaste            // UTF8 string below
2415262182Semaste//            const char *symbol = "";
2416262182Semaste//            if (row.expanded)
2417262182Semaste//                symbol = "\xe2\x96\xbd ";
2418262182Semaste//            else
2419262182Semaste//                symbol = "\xe2\x96\xb7 ";
2420262182Semaste//            window.PutCString (symbol);
2421262182Semaste
2422262182Semaste            // The ACS_DARROW and ACS_RARROW don't look very nice they are just a
2423262182Semaste            // 'v' or '>' character...
2424262182Semaste//            if (expanded)
2425262182Semaste//                window.PutChar (ACS_DARROW);
2426262182Semaste//            else
2427262182Semaste//                window.PutChar (ACS_RARROW);
2428262182Semaste            // Since we can't find any good looking right arrow/down arrow
2429262182Semaste            // symbols, just use a diamond...
2430262182Semaste            window.PutChar (ACS_DIAMOND);
2431262182Semaste            window.PutChar (ACS_HLINE);
2432262182Semaste        }
2433262182Semaste    }
2434262182Semaste
2435262182Semaste    void
2436262182Semaste    DrawTreeForChild (Window &window, Row *child, uint32_t reverse_depth)
2437262182Semaste    {
2438262182Semaste        if (parent)
2439262182Semaste            parent->DrawTreeForChild (window, this, reverse_depth + 1);
2440262182Semaste
2441262182Semaste        if (&children.back() == child)
2442262182Semaste        {
2443262182Semaste            // Last child
2444262182Semaste            if (reverse_depth == 0)
2445262182Semaste            {
2446262182Semaste                window.PutChar (ACS_LLCORNER);
2447262182Semaste                window.PutChar (ACS_HLINE);
2448262182Semaste            }
2449262182Semaste            else
2450262182Semaste            {
2451262182Semaste                window.PutChar (' ');
2452262182Semaste                window.PutChar (' ');
2453262182Semaste            }
2454262182Semaste        }
2455262182Semaste        else
2456262182Semaste        {
2457262182Semaste            if (reverse_depth == 0)
2458262182Semaste            {
2459262182Semaste                window.PutChar (ACS_LTEE);
2460262182Semaste                window.PutChar (ACS_HLINE);
2461262182Semaste            }
2462262182Semaste            else
2463262182Semaste            {
2464262182Semaste                window.PutChar (ACS_VLINE);
2465262182Semaste                window.PutChar (' ');
2466262182Semaste            }
2467262182Semaste        }
2468262182Semaste    }
2469262182Semaste};
2470262182Semaste
2471262182Semastestruct DisplayOptions
2472262182Semaste{
2473262182Semaste    bool show_types;
2474262182Semaste};
2475262182Semaste
2476262182Semasteclass TreeItem;
2477262182Semaste
2478262182Semasteclass TreeDelegate
2479262182Semaste{
2480262182Semastepublic:
2481262182Semaste    TreeDelegate() {}
2482262182Semaste    virtual ~TreeDelegate() {}
2483262182Semaste    virtual void TreeDelegateDrawTreeItem (TreeItem &item, Window &window) = 0;
2484262182Semaste    virtual void TreeDelegateGenerateChildren (TreeItem &item) = 0;
2485262182Semaste    virtual bool TreeDelegateItemSelected (TreeItem &item) = 0; // Return true if we need to update views
2486262182Semaste};
2487262182Semastetypedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
2488262182Semaste
2489262182Semasteclass TreeItem
2490262182Semaste{
2491262182Semastepublic:
2492262182Semaste
2493262182Semaste    TreeItem (TreeItem *parent, TreeDelegate &delegate, bool might_have_children) :
2494262182Semaste        m_parent (parent),
2495262182Semaste        m_delegate (delegate),
2496262182Semaste        m_identifier (0),
2497262182Semaste        m_row_idx (-1),
2498262182Semaste        m_children (),
2499262182Semaste        m_might_have_children (might_have_children),
2500262182Semaste        m_is_expanded (false)
2501262182Semaste    {
2502262182Semaste    }
2503262182Semaste
2504262182Semaste    TreeItem &
2505262182Semaste    operator=(const TreeItem &rhs)
2506262182Semaste    {
2507262182Semaste        if (this != &rhs)
2508262182Semaste        {
2509262182Semaste            m_parent = rhs.m_parent;
2510262182Semaste            m_delegate = rhs.m_delegate;
2511262182Semaste            m_identifier = rhs.m_identifier;
2512262182Semaste            m_row_idx = rhs.m_row_idx;
2513262182Semaste            m_children = rhs.m_children;
2514262182Semaste            m_might_have_children = rhs.m_might_have_children;
2515262182Semaste            m_is_expanded = rhs.m_is_expanded;
2516262182Semaste        }
2517262182Semaste        return *this;
2518262182Semaste    }
2519262182Semaste
2520262182Semaste    size_t
2521262182Semaste    GetDepth () const
2522262182Semaste    {
2523262182Semaste        if (m_parent)
2524262182Semaste            return 1 + m_parent->GetDepth();
2525262182Semaste        return 0;
2526262182Semaste    }
2527262182Semaste
2528262182Semaste    int
2529262182Semaste    GetRowIndex () const
2530262182Semaste    {
2531262182Semaste        return m_row_idx;
2532262182Semaste    }
2533262182Semaste
2534262182Semaste    void
2535262182Semaste    ClearChildren ()
2536262182Semaste    {
2537262182Semaste        m_children.clear();
2538262182Semaste    }
2539262182Semaste
2540262182Semaste    void
2541262182Semaste    Resize (size_t n, const TreeItem &t)
2542262182Semaste    {
2543262182Semaste        m_children.resize(n, t);
2544262182Semaste    }
2545262182Semaste
2546262182Semaste    TreeItem &
2547262182Semaste    operator [](size_t i)
2548262182Semaste    {
2549262182Semaste        return m_children[i];
2550262182Semaste    }
2551262182Semaste
2552262182Semaste    void
2553262182Semaste    SetRowIndex (int row_idx)
2554262182Semaste    {
2555262182Semaste        m_row_idx = row_idx;
2556262182Semaste    }
2557262182Semaste
2558262182Semaste    size_t
2559262182Semaste    GetNumChildren ()
2560262182Semaste    {
2561262182Semaste        m_delegate.TreeDelegateGenerateChildren (*this);
2562262182Semaste        return m_children.size();
2563262182Semaste    }
2564262182Semaste
2565262182Semaste    void
2566262182Semaste    ItemWasSelected ()
2567262182Semaste    {
2568262182Semaste        m_delegate.TreeDelegateItemSelected(*this);
2569262182Semaste    }
2570262182Semaste    void
2571262182Semaste    CalculateRowIndexes (int &row_idx)
2572262182Semaste    {
2573262182Semaste        SetRowIndex(row_idx);
2574262182Semaste        ++row_idx;
2575262182Semaste
2576262182Semaste        // The root item must calculate its children
2577262182Semaste        if (m_parent == NULL)
2578262182Semaste            GetNumChildren();
2579262182Semaste
2580262182Semaste        const bool expanded = IsExpanded();
2581262182Semaste        for (auto &item : m_children)
2582262182Semaste        {
2583262182Semaste            if (expanded)
2584262182Semaste                item.CalculateRowIndexes(row_idx);
2585262182Semaste            else
2586262182Semaste                item.SetRowIndex(-1);
2587262182Semaste        }
2588262182Semaste    }
2589262182Semaste
2590262182Semaste    TreeItem *
2591262182Semaste    GetParent ()
2592262182Semaste    {
2593262182Semaste        return m_parent;
2594262182Semaste    }
2595262182Semaste
2596262182Semaste    bool
2597262182Semaste    IsExpanded () const
2598262182Semaste    {
2599262182Semaste        return m_is_expanded;
2600262182Semaste    }
2601262182Semaste
2602262182Semaste    void
2603262182Semaste    Expand()
2604262182Semaste    {
2605262182Semaste        m_is_expanded = true;
2606262182Semaste    }
2607262182Semaste
2608262182Semaste    void
2609262182Semaste    Unexpand ()
2610262182Semaste    {
2611262182Semaste        m_is_expanded = false;
2612262182Semaste    }
2613262182Semaste
2614262182Semaste    bool
2615262182Semaste    Draw (Window &window,
2616262182Semaste          const int first_visible_row,
2617262182Semaste          const uint32_t selected_row_idx,
2618262182Semaste          int &row_idx,
2619262182Semaste          int &num_rows_left)
2620262182Semaste    {
2621262182Semaste        if (num_rows_left <= 0)
2622262182Semaste            return false;
2623262182Semaste
2624262182Semaste        if (m_row_idx >= first_visible_row)
2625262182Semaste        {
2626262182Semaste            window.MoveCursor(2, row_idx + 1);
2627262182Semaste
2628262182Semaste            if (m_parent)
2629262182Semaste                m_parent->DrawTreeForChild (window, this, 0);
2630262182Semaste
2631262182Semaste            if (m_might_have_children)
2632262182Semaste            {
2633262182Semaste                // It we can get UTF8 characters to work we should try to use the "symbol"
2634262182Semaste                // UTF8 string below
2635262182Semaste                //            const char *symbol = "";
2636262182Semaste                //            if (row.expanded)
2637262182Semaste                //                symbol = "\xe2\x96\xbd ";
2638262182Semaste                //            else
2639262182Semaste                //                symbol = "\xe2\x96\xb7 ";
2640262182Semaste                //            window.PutCString (symbol);
2641262182Semaste
2642262182Semaste                // The ACS_DARROW and ACS_RARROW don't look very nice they are just a
2643262182Semaste                // 'v' or '>' character...
2644262182Semaste                //            if (expanded)
2645262182Semaste                //                window.PutChar (ACS_DARROW);
2646262182Semaste                //            else
2647262182Semaste                //                window.PutChar (ACS_RARROW);
2648262182Semaste                // Since we can't find any good looking right arrow/down arrow
2649262182Semaste                // symbols, just use a diamond...
2650262182Semaste                window.PutChar (ACS_DIAMOND);
2651262182Semaste                window.PutChar (ACS_HLINE);
2652262182Semaste            }
2653262182Semaste            bool highlight = (selected_row_idx == m_row_idx) && window.IsActive();
2654262182Semaste
2655262182Semaste            if (highlight)
2656262182Semaste                window.AttributeOn(A_REVERSE);
2657262182Semaste
2658262182Semaste            m_delegate.TreeDelegateDrawTreeItem(*this, window);
2659262182Semaste
2660262182Semaste            if (highlight)
2661262182Semaste                window.AttributeOff(A_REVERSE);
2662262182Semaste            ++row_idx;
2663262182Semaste            --num_rows_left;
2664262182Semaste        }
2665262182Semaste
2666262182Semaste        if (num_rows_left <= 0)
2667262182Semaste            return false; // We are done drawing...
2668262182Semaste
2669262182Semaste        if (IsExpanded())
2670262182Semaste        {
2671262182Semaste            for (auto &item : m_children)
2672262182Semaste            {
2673262182Semaste                // If we displayed all the rows and item.Draw() returns
2674262182Semaste                // false we are done drawing and can exit this for loop
2675262182Semaste                if (item.Draw(window, first_visible_row, selected_row_idx, row_idx, num_rows_left) == false)
2676262182Semaste                    break;
2677262182Semaste            }
2678262182Semaste        }
2679262182Semaste        return num_rows_left >= 0; // Return true if not done drawing yet
2680262182Semaste    }
2681262182Semaste
2682262182Semaste    void
2683262182Semaste    DrawTreeForChild (Window &window, TreeItem *child, uint32_t reverse_depth)
2684262182Semaste    {
2685262182Semaste        if (m_parent)
2686262182Semaste            m_parent->DrawTreeForChild (window, this, reverse_depth + 1);
2687262182Semaste
2688262182Semaste        if (&m_children.back() == child)
2689262182Semaste        {
2690262182Semaste            // Last child
2691262182Semaste            if (reverse_depth == 0)
2692262182Semaste            {
2693262182Semaste                window.PutChar (ACS_LLCORNER);
2694262182Semaste                window.PutChar (ACS_HLINE);
2695262182Semaste            }
2696262182Semaste            else
2697262182Semaste            {
2698262182Semaste                window.PutChar (' ');
2699262182Semaste                window.PutChar (' ');
2700262182Semaste            }
2701262182Semaste        }
2702262182Semaste        else
2703262182Semaste        {
2704262182Semaste            if (reverse_depth == 0)
2705262182Semaste            {
2706262182Semaste                window.PutChar (ACS_LTEE);
2707262182Semaste                window.PutChar (ACS_HLINE);
2708262182Semaste            }
2709262182Semaste            else
2710262182Semaste            {
2711262182Semaste                window.PutChar (ACS_VLINE);
2712262182Semaste                window.PutChar (' ');
2713262182Semaste            }
2714262182Semaste        }
2715262182Semaste    }
2716262182Semaste
2717262182Semaste    TreeItem *
2718262182Semaste    GetItemForRowIndex (uint32_t row_idx)
2719262182Semaste    {
2720262182Semaste        if (m_row_idx == row_idx)
2721262182Semaste            return this;
2722262182Semaste        if (m_children.empty())
2723262182Semaste            return NULL;
2724262182Semaste        if (m_children.back().m_row_idx < row_idx)
2725262182Semaste            return NULL;
2726262182Semaste        if (IsExpanded())
2727262182Semaste        {
2728262182Semaste            for (auto &item : m_children)
2729262182Semaste            {
2730262182Semaste                TreeItem *selected_item_ptr = item.GetItemForRowIndex(row_idx);
2731262182Semaste                if (selected_item_ptr)
2732262182Semaste                    return selected_item_ptr;
2733262182Semaste            }
2734262182Semaste        }
2735262182Semaste        return NULL;
2736262182Semaste    }
2737262182Semaste
2738262182Semaste//    void *
2739262182Semaste//    GetUserData() const
2740262182Semaste//    {
2741262182Semaste//        return m_user_data;
2742262182Semaste//    }
2743262182Semaste//
2744262182Semaste//    void
2745262182Semaste//    SetUserData (void *user_data)
2746262182Semaste//    {
2747262182Semaste//        m_user_data = user_data;
2748262182Semaste//    }
2749262182Semaste    uint64_t
2750262182Semaste    GetIdentifier() const
2751262182Semaste    {
2752262182Semaste        return m_identifier;
2753262182Semaste    }
2754262182Semaste
2755262182Semaste    void
2756262182Semaste    SetIdentifier (uint64_t identifier)
2757262182Semaste    {
2758262182Semaste        m_identifier = identifier;
2759262182Semaste    }
2760262182Semaste
2761262182Semaste
2762262182Semasteprotected:
2763262182Semaste    TreeItem *m_parent;
2764262182Semaste    TreeDelegate &m_delegate;
2765262182Semaste    //void *m_user_data;
2766262182Semaste    uint64_t m_identifier;
2767262182Semaste    int m_row_idx; // Zero based visible row index, -1 if not visible or for the root item
2768262182Semaste    std::vector<TreeItem> m_children;
2769262182Semaste    bool m_might_have_children;
2770262182Semaste    bool m_is_expanded;
2771262182Semaste
2772262182Semaste};
2773262182Semaste
2774262182Semasteclass TreeWindowDelegate : public WindowDelegate
2775262182Semaste{
2776262182Semastepublic:
2777262182Semaste    TreeWindowDelegate (Debugger &debugger, const TreeDelegateSP &delegate_sp) :
2778262182Semaste        m_debugger (debugger),
2779262182Semaste        m_delegate_sp (delegate_sp),
2780262182Semaste        m_root (NULL, *delegate_sp, true),
2781262182Semaste        m_selected_item (NULL),
2782262182Semaste        m_num_rows (0),
2783262182Semaste        m_selected_row_idx (0),
2784262182Semaste        m_first_visible_row (0),
2785262182Semaste        m_min_x (0),
2786262182Semaste        m_min_y (0),
2787262182Semaste        m_max_x (0),
2788262182Semaste        m_max_y (0)
2789262182Semaste    {
2790262182Semaste    }
2791262182Semaste
2792262182Semaste    int
2793262182Semaste    NumVisibleRows () const
2794262182Semaste    {
2795262182Semaste        return m_max_y - m_min_y;
2796262182Semaste    }
2797262182Semaste
2798262182Semaste    virtual bool
2799262182Semaste    WindowDelegateDraw (Window &window, bool force)
2800262182Semaste    {
2801262182Semaste        ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
2802262182Semaste        Process *process = exe_ctx.GetProcessPtr();
2803262182Semaste
2804262182Semaste        bool display_content = false;
2805262182Semaste        if (process)
2806262182Semaste        {
2807262182Semaste            StateType state = process->GetState();
2808262182Semaste            if (StateIsStoppedState(state, true))
2809262182Semaste            {
2810262182Semaste                // We are stopped, so it is ok to
2811262182Semaste                display_content = true;
2812262182Semaste            }
2813262182Semaste            else if (StateIsRunningState(state))
2814262182Semaste            {
2815262182Semaste                return true; // Don't do any updating when we are running
2816262182Semaste            }
2817262182Semaste        }
2818262182Semaste
2819262182Semaste        m_min_x = 2;
2820262182Semaste        m_min_y = 1;
2821262182Semaste        m_max_x = window.GetWidth() - 1;
2822262182Semaste        m_max_y = window.GetHeight() - 1;
2823262182Semaste
2824262182Semaste        window.Erase();
2825262182Semaste        window.DrawTitleBox (window.GetName());
2826262182Semaste
2827262182Semaste        if (display_content)
2828262182Semaste        {
2829262182Semaste            const int num_visible_rows = NumVisibleRows();
2830262182Semaste            m_num_rows = 0;
2831262182Semaste            m_root.CalculateRowIndexes(m_num_rows);
2832262182Semaste
2833262182Semaste            // If we unexpanded while having something selected our
2834262182Semaste            // total number of rows is less than the num visible rows,
2835262182Semaste            // then make sure we show all the rows by setting the first
2836262182Semaste            // visible row accordingly.
2837262182Semaste            if (m_first_visible_row > 0 && m_num_rows < num_visible_rows)
2838262182Semaste                m_first_visible_row = 0;
2839262182Semaste
2840262182Semaste            // Make sure the selected row is always visible
2841262182Semaste            if (m_selected_row_idx < m_first_visible_row)
2842262182Semaste                m_first_visible_row = m_selected_row_idx;
2843262182Semaste            else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
2844262182Semaste                m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
2845262182Semaste
2846262182Semaste            int row_idx = 0;
2847262182Semaste            int num_rows_left = num_visible_rows;
2848262182Semaste            m_root.Draw (window, m_first_visible_row, m_selected_row_idx, row_idx, num_rows_left);
2849262182Semaste            // Get the selected row
2850262182Semaste            m_selected_item = m_root.GetItemForRowIndex (m_selected_row_idx);
2851262182Semaste        }
2852262182Semaste        else
2853262182Semaste        {
2854262182Semaste            m_selected_item = NULL;
2855262182Semaste        }
2856262182Semaste
2857262182Semaste        window.DeferredRefresh();
2858262182Semaste
2859262182Semaste
2860262182Semaste        return true; // Drawing handled
2861262182Semaste    }
2862262182Semaste
2863262182Semaste
2864262182Semaste    virtual const char *
2865262182Semaste    WindowDelegateGetHelpText ()
2866262182Semaste    {
2867262182Semaste        return "Thread window keyboard shortcuts:";
2868262182Semaste    }
2869262182Semaste
2870262182Semaste    virtual KeyHelp *
2871262182Semaste    WindowDelegateGetKeyHelp ()
2872262182Semaste    {
2873262182Semaste        static curses::KeyHelp g_source_view_key_help[] = {
2874262182Semaste            { KEY_UP, "Select previous item" },
2875262182Semaste            { KEY_DOWN, "Select next item" },
2876262182Semaste            { KEY_RIGHT, "Expand the selected item" },
2877262182Semaste            { KEY_LEFT, "Unexpand the selected item or select parent if not expanded" },
2878262182Semaste            { KEY_PPAGE, "Page up" },
2879262182Semaste            { KEY_NPAGE, "Page down" },
2880262182Semaste            { 'h', "Show help dialog" },
2881262182Semaste            { ' ', "Toggle item expansion" },
2882262182Semaste            { ',', "Page up" },
2883262182Semaste            { '.', "Page down" },
2884262182Semaste            { '\0', NULL }
2885262182Semaste        };
2886262182Semaste        return g_source_view_key_help;
2887262182Semaste    }
2888262182Semaste
2889262182Semaste    virtual HandleCharResult
2890262182Semaste    WindowDelegateHandleChar (Window &window, int c)
2891262182Semaste    {
2892262182Semaste        switch(c)
2893262182Semaste        {
2894262182Semaste            case ',':
2895262182Semaste            case KEY_PPAGE:
2896262182Semaste                // Page up key
2897262182Semaste                if (m_first_visible_row > 0)
2898262182Semaste                {
2899262182Semaste                    if (m_first_visible_row > m_max_y)
2900262182Semaste                        m_first_visible_row -= m_max_y;
2901262182Semaste                    else
2902262182Semaste                        m_first_visible_row = 0;
2903262182Semaste                    m_selected_row_idx = m_first_visible_row;
2904262182Semaste                    m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
2905262182Semaste                    if (m_selected_item)
2906262182Semaste                        m_selected_item->ItemWasSelected ();
2907262182Semaste                }
2908262182Semaste                return eKeyHandled;
2909262182Semaste
2910262182Semaste            case '.':
2911262182Semaste            case KEY_NPAGE:
2912262182Semaste                // Page down key
2913262182Semaste                if (m_num_rows > m_max_y)
2914262182Semaste                {
2915262182Semaste                    if (m_first_visible_row + m_max_y < m_num_rows)
2916262182Semaste                    {
2917262182Semaste                        m_first_visible_row += m_max_y;
2918262182Semaste                        m_selected_row_idx = m_first_visible_row;
2919262182Semaste                        m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
2920262182Semaste                        if (m_selected_item)
2921262182Semaste                            m_selected_item->ItemWasSelected ();
2922262182Semaste                    }
2923262182Semaste                }
2924262182Semaste                return eKeyHandled;
2925262182Semaste
2926262182Semaste            case KEY_UP:
2927262182Semaste                if (m_selected_row_idx > 0)
2928262182Semaste                {
2929262182Semaste                    --m_selected_row_idx;
2930262182Semaste                    m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
2931262182Semaste                    if (m_selected_item)
2932262182Semaste                        m_selected_item->ItemWasSelected ();
2933262182Semaste                }
2934262182Semaste                return eKeyHandled;
2935262182Semaste            case KEY_DOWN:
2936262182Semaste                if (m_selected_row_idx + 1 < m_num_rows)
2937262182Semaste                {
2938262182Semaste                    ++m_selected_row_idx;
2939262182Semaste                    m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
2940262182Semaste                    if (m_selected_item)
2941262182Semaste                        m_selected_item->ItemWasSelected ();
2942262182Semaste                }
2943262182Semaste                return eKeyHandled;
2944262182Semaste
2945262182Semaste            case KEY_RIGHT:
2946262182Semaste                if (m_selected_item)
2947262182Semaste                {
2948262182Semaste                    if (!m_selected_item->IsExpanded())
2949262182Semaste                        m_selected_item->Expand();
2950262182Semaste                }
2951262182Semaste                return eKeyHandled;
2952262182Semaste
2953262182Semaste            case KEY_LEFT:
2954262182Semaste                if (m_selected_item)
2955262182Semaste                {
2956262182Semaste                    if (m_selected_item->IsExpanded())
2957262182Semaste                        m_selected_item->Unexpand();
2958262182Semaste                    else if (m_selected_item->GetParent())
2959262182Semaste                    {
2960262182Semaste                        m_selected_row_idx = m_selected_item->GetParent()->GetRowIndex();
2961262182Semaste                        m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
2962262182Semaste                        if (m_selected_item)
2963262182Semaste                            m_selected_item->ItemWasSelected ();
2964262182Semaste                    }
2965262182Semaste                }
2966262182Semaste                return eKeyHandled;
2967262182Semaste
2968262182Semaste            case ' ':
2969262182Semaste                // Toggle expansion state when SPACE is pressed
2970262182Semaste                if (m_selected_item)
2971262182Semaste                {
2972262182Semaste                    if (m_selected_item->IsExpanded())
2973262182Semaste                        m_selected_item->Unexpand();
2974262182Semaste                    else
2975262182Semaste                        m_selected_item->Expand();
2976262182Semaste                }
2977262182Semaste                return eKeyHandled;
2978262182Semaste
2979262182Semaste            case 'h':
2980262182Semaste                window.CreateHelpSubwindow ();
2981262182Semaste                return eKeyHandled;
2982262182Semaste
2983262182Semaste            default:
2984262182Semaste                break;
2985262182Semaste        }
2986262182Semaste        return eKeyNotHandled;
2987262182Semaste    }
2988262182Semaste
2989262182Semasteprotected:
2990262182Semaste    Debugger &m_debugger;
2991262182Semaste    TreeDelegateSP m_delegate_sp;
2992262182Semaste    TreeItem m_root;
2993262182Semaste    TreeItem *m_selected_item;
2994262182Semaste    int m_num_rows;
2995262182Semaste    int m_selected_row_idx;
2996262182Semaste    int m_first_visible_row;
2997262182Semaste    int m_min_x;
2998262182Semaste    int m_min_y;
2999262182Semaste    int m_max_x;
3000262182Semaste    int m_max_y;
3001262182Semaste
3002262182Semaste};
3003262182Semaste
3004262182Semasteclass FrameTreeDelegate : public TreeDelegate
3005262182Semaste{
3006262182Semastepublic:
3007262182Semaste    FrameTreeDelegate (const ThreadSP &thread_sp) :
3008262182Semaste        TreeDelegate(),
3009262182Semaste        m_thread_wp()
3010262182Semaste    {
3011262182Semaste        if (thread_sp)
3012262182Semaste            m_thread_wp = thread_sp;
3013262182Semaste    }
3014262182Semaste
3015262182Semaste    virtual ~FrameTreeDelegate()
3016262182Semaste    {
3017262182Semaste    }
3018262182Semaste
3019262182Semaste    virtual void
3020262182Semaste    TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
3021262182Semaste    {
3022262182Semaste        ThreadSP thread_sp = m_thread_wp.lock();
3023262182Semaste        if (thread_sp)
3024262182Semaste        {
3025262182Semaste            const uint64_t frame_idx = item.GetIdentifier();
3026262182Semaste            StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(frame_idx);
3027262182Semaste            if (frame_sp)
3028262182Semaste            {
3029262182Semaste                StreamString strm;
3030262182Semaste                const SymbolContext &sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
3031262182Semaste                ExecutionContext exe_ctx (frame_sp);
3032262182Semaste                //const char *frame_format = "frame #${frame.index}: ${module.file.basename}{`${function.name}${function.pc-offset}}}";
3033262182Semaste                const char *frame_format = "frame #${frame.index}: {${function.name}${function.pc-offset}}}";
3034262182Semaste                if (Debugger::FormatPrompt (frame_format, &sc, &exe_ctx, NULL, strm))
3035262182Semaste                {
3036262182Semaste                    int right_pad = 1;
3037262182Semaste                    window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
3038262182Semaste                }
3039262182Semaste            }
3040262182Semaste        }
3041262182Semaste    }
3042262182Semaste    virtual void
3043262182Semaste    TreeDelegateGenerateChildren (TreeItem &item)
3044262182Semaste    {
3045262182Semaste        // No children for frames yet...
3046262182Semaste    }
3047262182Semaste
3048262182Semaste    virtual bool
3049262182Semaste    TreeDelegateItemSelected (TreeItem &item)
3050262182Semaste    {
3051262182Semaste        ThreadSP thread_sp = m_thread_wp.lock();
3052262182Semaste        if (thread_sp)
3053262182Semaste        {
3054262182Semaste            const uint64_t frame_idx = item.GetIdentifier();
3055262182Semaste            thread_sp->SetSelectedFrameByIndex(frame_idx);
3056262182Semaste            return true;
3057262182Semaste        }
3058262182Semaste        return false;
3059262182Semaste    }
3060262182Semaste    void
3061262182Semaste    SetThread (ThreadSP thread_sp)
3062262182Semaste    {
3063262182Semaste        m_thread_wp = thread_sp;
3064262182Semaste    }
3065262182Semaste
3066262182Semasteprotected:
3067262182Semaste    ThreadWP m_thread_wp;
3068262182Semaste};
3069262182Semaste
3070262182Semasteclass ThreadTreeDelegate : public TreeDelegate
3071262182Semaste{
3072262182Semastepublic:
3073262182Semaste    ThreadTreeDelegate (Debugger &debugger) :
3074262182Semaste        TreeDelegate(),
3075262182Semaste        m_debugger (debugger),
3076262182Semaste        m_thread_wp (),
3077262182Semaste        m_tid (LLDB_INVALID_THREAD_ID),
3078262182Semaste        m_stop_id (UINT32_MAX)
3079262182Semaste    {
3080262182Semaste    }
3081262182Semaste
3082262182Semaste    virtual
3083262182Semaste    ~ThreadTreeDelegate()
3084262182Semaste    {
3085262182Semaste    }
3086262182Semaste
3087262182Semaste    virtual void
3088262182Semaste    TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
3089262182Semaste    {
3090262182Semaste        ThreadSP thread_sp = m_thread_wp.lock();
3091262182Semaste        if (thread_sp)
3092262182Semaste        {
3093262182Semaste            StreamString strm;
3094262182Semaste            ExecutionContext exe_ctx (thread_sp);
3095262182Semaste            const char *format = "thread #${thread.index}: tid = ${thread.id}{, stop reason = ${thread.stop-reason}}";
3096262182Semaste            if (Debugger::FormatPrompt (format, NULL, &exe_ctx, NULL, strm))
3097262182Semaste            {
3098262182Semaste                int right_pad = 1;
3099262182Semaste                window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
3100262182Semaste            }
3101262182Semaste        }
3102262182Semaste    }
3103262182Semaste    virtual void
3104262182Semaste    TreeDelegateGenerateChildren (TreeItem &item)
3105262182Semaste    {
3106262182Semaste        TargetSP target_sp (m_debugger.GetSelectedTarget());
3107262182Semaste        if (target_sp)
3108262182Semaste        {
3109262182Semaste            ProcessSP process_sp = target_sp->GetProcessSP();
3110262182Semaste            if (process_sp && process_sp->IsAlive())
3111262182Semaste            {
3112262182Semaste                StateType state = process_sp->GetState();
3113262182Semaste                if (StateIsStoppedState(state, true))
3114262182Semaste                {
3115262182Semaste                    ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread();
3116262182Semaste                    if (thread_sp)
3117262182Semaste                    {
3118262182Semaste                        if (m_stop_id == process_sp->GetStopID() && thread_sp->GetID() == m_tid)
3119262182Semaste                            return; // Children are already up to date
3120262182Semaste                        if (m_frame_delegate_sp)
3121262182Semaste                            m_frame_delegate_sp->SetThread(thread_sp);
3122262182Semaste                        else
3123262182Semaste                        {
3124262182Semaste                            // Always expand the thread item the first time we show it
3125262182Semaste                            item.Expand();
3126262182Semaste                            m_frame_delegate_sp.reset (new FrameTreeDelegate(thread_sp));
3127262182Semaste                        }
3128262182Semaste
3129262182Semaste                        m_stop_id = process_sp->GetStopID();
3130262182Semaste                        m_thread_wp = thread_sp;
3131262182Semaste                        m_tid = thread_sp->GetID();
3132262182Semaste
3133262182Semaste                        TreeItem t (&item, *m_frame_delegate_sp, false);
3134262182Semaste                        size_t num_frames = thread_sp->GetStackFrameCount();
3135262182Semaste                        item.Resize (num_frames, t);
3136262182Semaste                        for (size_t i=0; i<num_frames; ++i)
3137262182Semaste                        {
3138262182Semaste                            item[i].SetIdentifier(i);
3139262182Semaste                        }
3140262182Semaste                    }
3141262182Semaste                    return;
3142262182Semaste                }
3143262182Semaste            }
3144262182Semaste        }
3145262182Semaste        item.ClearChildren();
3146262182Semaste    }
3147262182Semaste
3148262182Semaste    virtual bool
3149262182Semaste    TreeDelegateItemSelected (TreeItem &item)
3150262182Semaste    {
3151262182Semaste        ThreadSP thread_sp = m_thread_wp.lock();
3152262182Semaste        if (thread_sp)
3153262182Semaste        {
3154262182Semaste            ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
3155262182Semaste            Mutex::Locker locker (thread_list.GetMutex());
3156262182Semaste            ThreadSP selected_thread_sp = thread_list.GetSelectedThread();
3157262182Semaste            if (selected_thread_sp->GetID() != thread_sp->GetID())
3158262182Semaste            {
3159262182Semaste                thread_list.SetSelectedThreadByID(thread_sp->GetID());
3160262182Semaste                return true;
3161262182Semaste            }
3162262182Semaste        }
3163262182Semaste        return false;
3164262182Semaste    }
3165262182Semaste
3166262182Semasteprotected:
3167262182Semaste    Debugger &m_debugger;
3168262182Semaste    ThreadWP m_thread_wp;
3169262182Semaste    std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp;
3170262182Semaste    lldb::user_id_t m_tid;
3171262182Semaste    uint32_t m_stop_id;
3172262182Semaste};
3173262182Semaste
3174262182Semasteclass ValueObjectListDelegate : public WindowDelegate
3175262182Semaste{
3176262182Semastepublic:
3177262182Semaste    ValueObjectListDelegate () :
3178262182Semaste        m_valobj_list (),
3179262182Semaste        m_rows (),
3180262182Semaste        m_selected_row (NULL),
3181262182Semaste        m_selected_row_idx (0),
3182262182Semaste        m_first_visible_row (0),
3183262182Semaste        m_num_rows (0),
3184262182Semaste        m_max_x (0),
3185262182Semaste        m_max_y (0)
3186262182Semaste    {
3187262182Semaste    }
3188262182Semaste
3189262182Semaste    ValueObjectListDelegate (ValueObjectList &valobj_list) :
3190262182Semaste        m_valobj_list (valobj_list),
3191262182Semaste        m_rows (),
3192262182Semaste        m_selected_row (NULL),
3193262182Semaste        m_selected_row_idx (0),
3194262182Semaste        m_first_visible_row (0),
3195262182Semaste        m_num_rows (0),
3196262182Semaste        m_max_x (0),
3197262182Semaste        m_max_y (0)
3198262182Semaste    {
3199262182Semaste        SetValues (valobj_list);
3200262182Semaste    }
3201262182Semaste
3202262182Semaste    virtual
3203262182Semaste    ~ValueObjectListDelegate()
3204262182Semaste    {
3205262182Semaste    }
3206262182Semaste
3207262182Semaste    void
3208262182Semaste    SetValues (ValueObjectList &valobj_list)
3209262182Semaste    {
3210262182Semaste        m_selected_row = NULL;
3211262182Semaste        m_selected_row_idx = 0;
3212262182Semaste        m_first_visible_row = 0;
3213262182Semaste        m_num_rows = 0;
3214262182Semaste        m_rows.clear();
3215262182Semaste        m_valobj_list = valobj_list;
3216262182Semaste        const size_t num_values = m_valobj_list.GetSize();
3217262182Semaste        for (size_t i=0; i<num_values; ++i)
3218262182Semaste            m_rows.push_back(Row(m_valobj_list.GetValueObjectAtIndex(i), NULL));
3219262182Semaste    }
3220262182Semaste
3221262182Semaste    virtual bool
3222262182Semaste    WindowDelegateDraw (Window &window, bool force)
3223262182Semaste    {
3224262182Semaste        m_num_rows = 0;
3225262182Semaste        m_min_x = 2;
3226262182Semaste        m_min_y = 1;
3227262182Semaste        m_max_x = window.GetWidth() - 1;
3228262182Semaste        m_max_y = window.GetHeight() - 1;
3229262182Semaste
3230262182Semaste        window.Erase();
3231262182Semaste        window.DrawTitleBox (window.GetName());
3232262182Semaste
3233262182Semaste        const int num_visible_rows = NumVisibleRows();
3234262182Semaste        const int num_rows = CalculateTotalNumberRows (m_rows);
3235262182Semaste
3236262182Semaste        // If we unexpanded while having something selected our
3237262182Semaste        // total number of rows is less than the num visible rows,
3238262182Semaste        // then make sure we show all the rows by setting the first
3239262182Semaste        // visible row accordingly.
3240262182Semaste        if (m_first_visible_row > 0 && num_rows < num_visible_rows)
3241262182Semaste            m_first_visible_row = 0;
3242262182Semaste
3243262182Semaste        // Make sure the selected row is always visible
3244262182Semaste        if (m_selected_row_idx < m_first_visible_row)
3245262182Semaste            m_first_visible_row = m_selected_row_idx;
3246262182Semaste        else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
3247262182Semaste            m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
3248262182Semaste
3249262182Semaste        DisplayRows (window, m_rows, g_options);
3250262182Semaste
3251262182Semaste        window.DeferredRefresh();
3252262182Semaste
3253262182Semaste        // Get the selected row
3254262182Semaste        m_selected_row = GetRowForRowIndex (m_selected_row_idx);
3255262182Semaste        // Keep the cursor on the selected row so the highlight and the cursor
3256262182Semaste        // are always on the same line
3257262182Semaste        if (m_selected_row)
3258262182Semaste            window.MoveCursor (m_selected_row->x,
3259262182Semaste                               m_selected_row->y);
3260262182Semaste
3261262182Semaste        return true; // Drawing handled
3262262182Semaste    }
3263262182Semaste
3264262182Semaste    virtual KeyHelp *
3265262182Semaste    WindowDelegateGetKeyHelp ()
3266262182Semaste    {
3267262182Semaste        static curses::KeyHelp g_source_view_key_help[] = {
3268262182Semaste            { KEY_UP, "Select previous item" },
3269262182Semaste            { KEY_DOWN, "Select next item" },
3270262182Semaste            { KEY_RIGHT, "Expand selected item" },
3271262182Semaste            { KEY_LEFT, "Unexpand selected item or select parent if not expanded" },
3272262182Semaste            { KEY_PPAGE, "Page up" },
3273262182Semaste            { KEY_NPAGE, "Page down" },
3274262182Semaste            { 'A', "Format as annotated address" },
3275262182Semaste            { 'b', "Format as binary" },
3276262182Semaste            { 'B', "Format as hex bytes with ASCII" },
3277262182Semaste            { 'c', "Format as character" },
3278262182Semaste            { 'd', "Format as a signed integer" },
3279262182Semaste            { 'D', "Format selected value using the default format for the type" },
3280262182Semaste            { 'f', "Format as float" },
3281262182Semaste            { 'h', "Show help dialog" },
3282262182Semaste            { 'i', "Format as instructions" },
3283262182Semaste            { 'o', "Format as octal" },
3284262182Semaste            { 'p', "Format as pointer" },
3285262182Semaste            { 's', "Format as C string" },
3286262182Semaste            { 't', "Toggle showing/hiding type names" },
3287262182Semaste            { 'u', "Format as an unsigned integer" },
3288262182Semaste            { 'x', "Format as hex" },
3289262182Semaste            { 'X', "Format as uppercase hex" },
3290262182Semaste            { ' ', "Toggle item expansion" },
3291262182Semaste            { ',', "Page up" },
3292262182Semaste            { '.', "Page down" },
3293262182Semaste            { '\0', NULL }
3294262182Semaste        };
3295262182Semaste        return g_source_view_key_help;
3296262182Semaste    }
3297262182Semaste
3298262182Semaste
3299262182Semaste    virtual HandleCharResult
3300262182Semaste    WindowDelegateHandleChar (Window &window, int c)
3301262182Semaste    {
3302262182Semaste        switch(c)
3303262182Semaste        {
3304262182Semaste            case 'x':
3305262182Semaste            case 'X':
3306262182Semaste            case 'o':
3307262182Semaste            case 's':
3308262182Semaste            case 'u':
3309262182Semaste            case 'd':
3310262182Semaste            case 'D':
3311262182Semaste            case 'i':
3312262182Semaste            case 'A':
3313262182Semaste            case 'p':
3314262182Semaste            case 'c':
3315262182Semaste            case 'b':
3316262182Semaste            case 'B':
3317262182Semaste            case 'f':
3318262182Semaste                // Change the format for the currently selected item
3319262182Semaste                if (m_selected_row)
3320262182Semaste                    m_selected_row->valobj->SetFormat (FormatForChar (c));
3321262182Semaste                return eKeyHandled;
3322262182Semaste
3323262182Semaste            case 't':
3324262182Semaste                // Toggle showing type names
3325262182Semaste                g_options.show_types = !g_options.show_types;
3326262182Semaste                return eKeyHandled;
3327262182Semaste
3328262182Semaste            case ',':
3329262182Semaste            case KEY_PPAGE:
3330262182Semaste                // Page up key
3331262182Semaste                if (m_first_visible_row > 0)
3332262182Semaste                {
3333262182Semaste                    if (m_first_visible_row > m_max_y)
3334262182Semaste                        m_first_visible_row -= m_max_y;
3335262182Semaste                    else
3336262182Semaste                        m_first_visible_row = 0;
3337262182Semaste                    m_selected_row_idx = m_first_visible_row;
3338262182Semaste                }
3339262182Semaste                return eKeyHandled;
3340262182Semaste
3341262182Semaste            case '.':
3342262182Semaste            case KEY_NPAGE:
3343262182Semaste                // Page down key
3344262182Semaste                if (m_num_rows > m_max_y)
3345262182Semaste                {
3346262182Semaste                    if (m_first_visible_row + m_max_y < m_num_rows)
3347262182Semaste                    {
3348262182Semaste                        m_first_visible_row += m_max_y;
3349262182Semaste                        m_selected_row_idx = m_first_visible_row;
3350262182Semaste                    }
3351262182Semaste                }
3352262182Semaste                return eKeyHandled;
3353262182Semaste
3354262182Semaste            case KEY_UP:
3355262182Semaste                if (m_selected_row_idx > 0)
3356262182Semaste                    --m_selected_row_idx;
3357262182Semaste                return eKeyHandled;
3358262182Semaste            case KEY_DOWN:
3359262182Semaste                if (m_selected_row_idx + 1 < m_num_rows)
3360262182Semaste                    ++m_selected_row_idx;
3361262182Semaste                return eKeyHandled;
3362262182Semaste
3363262182Semaste            case KEY_RIGHT:
3364262182Semaste                if (m_selected_row)
3365262182Semaste                {
3366262182Semaste                    if (!m_selected_row->expanded)
3367262182Semaste                        m_selected_row->Expand();
3368262182Semaste                }
3369262182Semaste                return eKeyHandled;
3370262182Semaste
3371262182Semaste            case KEY_LEFT:
3372262182Semaste                if (m_selected_row)
3373262182Semaste                {
3374262182Semaste                    if (m_selected_row->expanded)
3375262182Semaste                        m_selected_row->Unexpand();
3376262182Semaste                    else if (m_selected_row->parent)
3377262182Semaste                        m_selected_row_idx = m_selected_row->parent->row_idx;
3378262182Semaste                }
3379262182Semaste                return eKeyHandled;
3380262182Semaste
3381262182Semaste            case ' ':
3382262182Semaste                // Toggle expansion state when SPACE is pressed
3383262182Semaste                if (m_selected_row)
3384262182Semaste                {
3385262182Semaste                    if (m_selected_row->expanded)
3386262182Semaste                        m_selected_row->Unexpand();
3387262182Semaste                    else
3388262182Semaste                        m_selected_row->Expand();
3389262182Semaste                }
3390262182Semaste                return eKeyHandled;
3391262182Semaste
3392262182Semaste            case 'h':
3393262182Semaste                window.CreateHelpSubwindow ();
3394262182Semaste                return eKeyHandled;
3395262182Semaste
3396262182Semaste            default:
3397262182Semaste                break;
3398262182Semaste        }
3399262182Semaste        return eKeyNotHandled;
3400262182Semaste    }
3401262182Semaste
3402262182Semasteprotected:
3403262182Semaste    ValueObjectList m_valobj_list;
3404262182Semaste    std::vector<Row> m_rows;
3405262182Semaste    Row *m_selected_row;
3406262182Semaste    uint32_t m_selected_row_idx;
3407262182Semaste    uint32_t m_first_visible_row;
3408262182Semaste    uint32_t m_num_rows;
3409262182Semaste    int m_min_x;
3410262182Semaste    int m_min_y;
3411262182Semaste    int m_max_x;
3412262182Semaste    int m_max_y;
3413262182Semaste
3414262182Semaste    static Format
3415262182Semaste    FormatForChar (int c)
3416262182Semaste    {
3417262182Semaste        switch (c)
3418262182Semaste        {
3419262182Semaste            case 'x': return eFormatHex;
3420262182Semaste            case 'X': return eFormatHexUppercase;
3421262182Semaste            case 'o': return eFormatOctal;
3422262182Semaste            case 's': return eFormatCString;
3423262182Semaste            case 'u': return eFormatUnsigned;
3424262182Semaste            case 'd': return eFormatDecimal;
3425262182Semaste            case 'D': return eFormatDefault;
3426262182Semaste            case 'i': return eFormatInstruction;
3427262182Semaste            case 'A': return eFormatAddressInfo;
3428262182Semaste            case 'p': return eFormatPointer;
3429262182Semaste            case 'c': return eFormatChar;
3430262182Semaste            case 'b': return eFormatBinary;
3431262182Semaste            case 'B': return eFormatBytesWithASCII;
3432262182Semaste            case 'f': return eFormatFloat;
3433262182Semaste        }
3434262182Semaste        return eFormatDefault;
3435262182Semaste    }
3436262182Semaste
3437262182Semaste    bool
3438262182Semaste    DisplayRowObject (Window &window,
3439262182Semaste                      Row &row,
3440262182Semaste                      DisplayOptions &options,
3441262182Semaste                      bool highlight,
3442262182Semaste                      bool last_child)
3443262182Semaste    {
3444262182Semaste        ValueObject *valobj = row.valobj.get();
3445262182Semaste
3446262182Semaste        if (valobj == NULL)
3447262182Semaste            return false;
3448262182Semaste
3449262182Semaste        const char *type_name = options.show_types ? valobj->GetTypeName().GetCString() : NULL;
3450262182Semaste        const char *name = valobj->GetName().GetCString();
3451262182Semaste        const char *value = valobj->GetValueAsCString ();
3452262182Semaste        const char *summary = valobj->GetSummaryAsCString ();
3453262182Semaste
3454262182Semaste        window.MoveCursor (row.x, row.y);
3455262182Semaste
3456262182Semaste        row.DrawTree (window);
3457262182Semaste
3458262182Semaste        if (highlight)
3459262182Semaste            window.AttributeOn(A_REVERSE);
3460262182Semaste
3461262182Semaste        if (type_name && type_name[0])
3462262182Semaste            window.Printf ("(%s) ", type_name);
3463262182Semaste
3464262182Semaste        if (name && name[0])
3465262182Semaste            window.PutCString(name);
3466262182Semaste
3467262182Semaste        attr_t changd_attr = 0;
3468262182Semaste        if (valobj->GetValueDidChange())
3469262182Semaste            changd_attr = COLOR_PAIR(5) | A_BOLD;
3470262182Semaste
3471262182Semaste        if (value && value[0])
3472262182Semaste        {
3473262182Semaste            window.PutCString(" = ");
3474262182Semaste            if (changd_attr)
3475262182Semaste                window.AttributeOn(changd_attr);
3476262182Semaste            window.PutCString (value);
3477262182Semaste            if (changd_attr)
3478262182Semaste                window.AttributeOff(changd_attr);
3479262182Semaste        }
3480262182Semaste
3481262182Semaste        if (summary && summary[0])
3482262182Semaste        {
3483262182Semaste            window.PutChar(' ');
3484262182Semaste            if (changd_attr)
3485262182Semaste                window.AttributeOn(changd_attr);
3486262182Semaste            window.PutCString(summary);
3487262182Semaste            if (changd_attr)
3488262182Semaste                window.AttributeOff(changd_attr);
3489262182Semaste        }
3490262182Semaste
3491262182Semaste        if (highlight)
3492262182Semaste            window.AttributeOff (A_REVERSE);
3493262182Semaste
3494262182Semaste        return true;
3495262182Semaste    }
3496262182Semaste    void
3497262182Semaste    DisplayRows (Window &window,
3498262182Semaste                 std::vector<Row> &rows,
3499262182Semaste                 DisplayOptions &options)
3500262182Semaste    {
3501262182Semaste        // >   0x25B7
3502262182Semaste        // \/  0x25BD
3503262182Semaste
3504262182Semaste        bool window_is_active = window.IsActive();
3505262182Semaste        for (auto &row : rows)
3506262182Semaste        {
3507262182Semaste            const bool last_child = row.parent && &rows[rows.size()-1] == &row;
3508262182Semaste            // Save the row index in each Row structure
3509262182Semaste            row.row_idx = m_num_rows;
3510262182Semaste            if ((m_num_rows >= m_first_visible_row) &&
3511262182Semaste                ((m_num_rows - m_first_visible_row) < NumVisibleRows()))
3512262182Semaste            {
3513262182Semaste                row.x = m_min_x;
3514262182Semaste                row.y = m_num_rows - m_first_visible_row + 1;
3515262182Semaste                if (DisplayRowObject (window,
3516262182Semaste                                      row,
3517262182Semaste                                      options,
3518262182Semaste                                      window_is_active && m_num_rows == m_selected_row_idx,
3519262182Semaste                                      last_child))
3520262182Semaste                {
3521262182Semaste                    ++m_num_rows;
3522262182Semaste                }
3523262182Semaste                else
3524262182Semaste                {
3525262182Semaste                    row.x = 0;
3526262182Semaste                    row.y = 0;
3527262182Semaste                }
3528262182Semaste            }
3529262182Semaste            else
3530262182Semaste            {
3531262182Semaste                row.x = 0;
3532262182Semaste                row.y = 0;
3533262182Semaste                ++m_num_rows;
3534262182Semaste            }
3535262182Semaste
3536262182Semaste            if (row.expanded && !row.children.empty())
3537262182Semaste            {
3538262182Semaste                DisplayRows (window,
3539262182Semaste                             row.children,
3540262182Semaste                             options);
3541262182Semaste            }
3542262182Semaste        }
3543262182Semaste    }
3544262182Semaste
3545262182Semaste    int
3546262182Semaste    CalculateTotalNumberRows (const std::vector<Row> &rows)
3547262182Semaste    {
3548262182Semaste        int row_count = 0;
3549262182Semaste        for (const auto &row : rows)
3550262182Semaste        {
3551262182Semaste            ++row_count;
3552262182Semaste            if (row.expanded)
3553262182Semaste                row_count += CalculateTotalNumberRows(row.children);
3554262182Semaste        }
3555262182Semaste        return row_count;
3556262182Semaste    }
3557262182Semaste    static Row *
3558262182Semaste    GetRowForRowIndexImpl (std::vector<Row> &rows, size_t &row_index)
3559262182Semaste    {
3560262182Semaste        for (auto &row : rows)
3561262182Semaste        {
3562262182Semaste            if (row_index == 0)
3563262182Semaste                return &row;
3564262182Semaste            else
3565262182Semaste            {
3566262182Semaste                --row_index;
3567262182Semaste                if (row.expanded && !row.children.empty())
3568262182Semaste                {
3569262182Semaste                    Row *result = GetRowForRowIndexImpl (row.children, row_index);
3570262182Semaste                    if (result)
3571262182Semaste                        return result;
3572262182Semaste                }
3573262182Semaste            }
3574262182Semaste        }
3575262182Semaste        return NULL;
3576262182Semaste    }
3577262182Semaste
3578262182Semaste    Row *
3579262182Semaste    GetRowForRowIndex (size_t row_index)
3580262182Semaste    {
3581262182Semaste        return GetRowForRowIndexImpl (m_rows, row_index);
3582262182Semaste    }
3583262182Semaste
3584262182Semaste    int
3585262182Semaste    NumVisibleRows () const
3586262182Semaste    {
3587262182Semaste        return m_max_y - m_min_y;
3588262182Semaste    }
3589262182Semaste
3590262182Semaste    static DisplayOptions g_options;
3591262182Semaste};
3592262182Semaste
3593262182Semasteclass FrameVariablesWindowDelegate : public ValueObjectListDelegate
3594262182Semaste{
3595262182Semastepublic:
3596262182Semaste    FrameVariablesWindowDelegate (Debugger &debugger) :
3597262182Semaste        ValueObjectListDelegate (),
3598262182Semaste        m_debugger (debugger),
3599262182Semaste        m_frame_block (NULL)
3600262182Semaste    {
3601262182Semaste    }
3602262182Semaste
3603262182Semaste    virtual
3604262182Semaste    ~FrameVariablesWindowDelegate()
3605262182Semaste    {
3606262182Semaste    }
3607262182Semaste
3608262182Semaste    virtual const char *
3609262182Semaste    WindowDelegateGetHelpText ()
3610262182Semaste    {
3611262182Semaste        return "Frame variable window keyboard shortcuts:";
3612262182Semaste    }
3613262182Semaste
3614262182Semaste    virtual bool
3615262182Semaste    WindowDelegateDraw (Window &window, bool force)
3616262182Semaste    {
3617262182Semaste        ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
3618262182Semaste        Process *process = exe_ctx.GetProcessPtr();
3619262182Semaste        Block *frame_block = NULL;
3620262182Semaste        StackFrame *frame = NULL;
3621262182Semaste
3622262182Semaste        if (process)
3623262182Semaste        {
3624262182Semaste            StateType state = process->GetState();
3625262182Semaste            if (StateIsStoppedState(state, true))
3626262182Semaste            {
3627262182Semaste                frame = exe_ctx.GetFramePtr();
3628262182Semaste                if (frame)
3629262182Semaste                    frame_block = frame->GetFrameBlock ();
3630262182Semaste            }
3631262182Semaste            else if (StateIsRunningState(state))
3632262182Semaste            {
3633262182Semaste                return true; // Don't do any updating when we are running
3634262182Semaste            }
3635262182Semaste        }
3636262182Semaste
3637262182Semaste        ValueObjectList local_values;
3638262182Semaste        if (frame_block)
3639262182Semaste        {
3640262182Semaste            // Only update the variables if they have changed
3641262182Semaste            if (m_frame_block != frame_block)
3642262182Semaste            {
3643262182Semaste                m_frame_block = frame_block;
3644262182Semaste
3645262182Semaste                VariableList *locals = frame->GetVariableList(true);
3646262182Semaste                if (locals)
3647262182Semaste                {
3648262182Semaste                    const DynamicValueType use_dynamic = eDynamicDontRunTarget;
3649262182Semaste                    const size_t num_locals = locals->GetSize();
3650262182Semaste                    for (size_t i=0; i<num_locals; ++i)
3651262182Semaste                        local_values.Append(frame->GetValueObjectForFrameVariable (locals->GetVariableAtIndex(i), use_dynamic));
3652262182Semaste                    // Update the values
3653262182Semaste                    SetValues(local_values);
3654262182Semaste                }
3655262182Semaste            }
3656262182Semaste        }
3657262182Semaste        else
3658262182Semaste        {
3659262182Semaste            m_frame_block = NULL;
3660262182Semaste            // Update the values with an empty list if there is no frame
3661262182Semaste            SetValues(local_values);
3662262182Semaste        }
3663262182Semaste
3664262182Semaste        return ValueObjectListDelegate::WindowDelegateDraw (window, force);
3665262182Semaste
3666262182Semaste    }
3667262182Semaste
3668262182Semasteprotected:
3669262182Semaste    Debugger &m_debugger;
3670262182Semaste    Block *m_frame_block;
3671262182Semaste};
3672262182Semaste
3673262182Semaste
3674262182Semasteclass RegistersWindowDelegate : public ValueObjectListDelegate
3675262182Semaste{
3676262182Semastepublic:
3677262182Semaste    RegistersWindowDelegate (Debugger &debugger) :
3678262182Semaste        ValueObjectListDelegate (),
3679262182Semaste        m_debugger (debugger)
3680262182Semaste    {
3681262182Semaste    }
3682262182Semaste
3683262182Semaste    virtual
3684262182Semaste    ~RegistersWindowDelegate()
3685262182Semaste    {
3686262182Semaste    }
3687262182Semaste
3688262182Semaste    virtual const char *
3689262182Semaste    WindowDelegateGetHelpText ()
3690262182Semaste    {
3691262182Semaste        return "Register window keyboard shortcuts:";
3692262182Semaste    }
3693262182Semaste
3694262182Semaste    virtual bool
3695262182Semaste    WindowDelegateDraw (Window &window, bool force)
3696262182Semaste    {
3697262182Semaste        ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
3698262182Semaste        StackFrame *frame = exe_ctx.GetFramePtr();
3699262182Semaste
3700262182Semaste        ValueObjectList value_list;
3701262182Semaste        if (frame)
3702262182Semaste        {
3703262182Semaste            if (frame->GetStackID() != m_stack_id)
3704262182Semaste            {
3705262182Semaste                m_stack_id = frame->GetStackID();
3706262182Semaste                RegisterContextSP reg_ctx (frame->GetRegisterContext());
3707262182Semaste                if (reg_ctx)
3708262182Semaste                {
3709262182Semaste                    const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
3710262182Semaste                    for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx)
3711262182Semaste                    {
3712262182Semaste                        value_list.Append(ValueObjectRegisterSet::Create (frame, reg_ctx, set_idx));
3713262182Semaste                    }
3714262182Semaste                }
3715262182Semaste                SetValues(value_list);
3716262182Semaste            }
3717262182Semaste        }
3718262182Semaste        else
3719262182Semaste        {
3720262182Semaste            Process *process = exe_ctx.GetProcessPtr();
3721262182Semaste            if (process && process->IsAlive())
3722262182Semaste                return true; // Don't do any updating if we are running
3723262182Semaste            else
3724262182Semaste            {
3725262182Semaste                // Update the values with an empty list if there
3726262182Semaste                // is no process or the process isn't alive anymore
3727262182Semaste                SetValues(value_list);
3728262182Semaste            }
3729262182Semaste        }
3730262182Semaste        return ValueObjectListDelegate::WindowDelegateDraw (window, force);
3731262182Semaste    }
3732262182Semaste
3733262182Semasteprotected:
3734262182Semaste    Debugger &m_debugger;
3735262182Semaste    StackID m_stack_id;
3736262182Semaste};
3737262182Semaste
3738262182Semastestatic const char *
3739262182SemasteCursesKeyToCString (int ch)
3740262182Semaste{
3741262182Semaste    static char g_desc[32];
3742262182Semaste    if (ch >= KEY_F0 && ch < KEY_F0 + 64)
3743262182Semaste    {
3744262182Semaste        snprintf(g_desc, sizeof(g_desc), "F%u", ch - KEY_F0);
3745262182Semaste        return g_desc;
3746262182Semaste    }
3747262182Semaste    switch (ch)
3748262182Semaste    {
3749262182Semaste        case KEY_DOWN:  return "down";
3750262182Semaste        case KEY_UP:    return "up";
3751262182Semaste        case KEY_LEFT:  return "left";
3752262182Semaste        case KEY_RIGHT: return "right";
3753262182Semaste        case KEY_HOME:  return "home";
3754262182Semaste        case KEY_BACKSPACE: return "backspace";
3755262182Semaste        case KEY_DL:        return "delete-line";
3756262182Semaste        case KEY_IL:        return "insert-line";
3757262182Semaste        case KEY_DC:        return "delete-char";
3758262182Semaste        case KEY_IC:        return "insert-char";
3759262182Semaste        case KEY_CLEAR:     return "clear";
3760262182Semaste        case KEY_EOS:       return "clear-to-eos";
3761262182Semaste        case KEY_EOL:       return "clear-to-eol";
3762262182Semaste        case KEY_SF:        return "scroll-forward";
3763262182Semaste        case KEY_SR:        return "scroll-backward";
3764262182Semaste        case KEY_NPAGE:     return "page-down";
3765262182Semaste        case KEY_PPAGE:     return "page-up";
3766262182Semaste        case KEY_STAB:      return "set-tab";
3767262182Semaste        case KEY_CTAB:      return "clear-tab";
3768262182Semaste        case KEY_CATAB:     return "clear-all-tabs";
3769262182Semaste        case KEY_ENTER:     return "enter";
3770262182Semaste        case KEY_PRINT:     return "print";
3771262182Semaste        case KEY_LL:        return "lower-left key";
3772262182Semaste        case KEY_A1:        return "upper left of keypad";
3773262182Semaste        case KEY_A3:        return "upper right of keypad";
3774262182Semaste        case KEY_B2:        return "center of keypad";
3775262182Semaste        case KEY_C1:        return "lower left of keypad";
3776262182Semaste        case KEY_C3:        return "lower right of keypad";
3777262182Semaste        case KEY_BTAB:      return "back-tab key";
3778262182Semaste        case KEY_BEG:       return "begin key";
3779262182Semaste        case KEY_CANCEL:    return "cancel key";
3780262182Semaste        case KEY_CLOSE:     return "close key";
3781262182Semaste        case KEY_COMMAND:   return "command key";
3782262182Semaste        case KEY_COPY:      return "copy key";
3783262182Semaste        case KEY_CREATE:    return "create key";
3784262182Semaste        case KEY_END:       return "end key";
3785262182Semaste        case KEY_EXIT:      return "exit key";
3786262182Semaste        case KEY_FIND:      return "find key";
3787262182Semaste        case KEY_HELP:      return "help key";
3788262182Semaste        case KEY_MARK:      return "mark key";
3789262182Semaste        case KEY_MESSAGE:   return "message key";
3790262182Semaste        case KEY_MOVE:      return "move key";
3791262182Semaste        case KEY_NEXT:      return "next key";
3792262182Semaste        case KEY_OPEN:      return "open key";
3793262182Semaste        case KEY_OPTIONS:   return "options key";
3794262182Semaste        case KEY_PREVIOUS:  return "previous key";
3795262182Semaste        case KEY_REDO:      return "redo key";
3796262182Semaste        case KEY_REFERENCE: return "reference key";
3797262182Semaste        case KEY_REFRESH:   return "refresh key";
3798262182Semaste        case KEY_REPLACE:   return "replace key";
3799262182Semaste        case KEY_RESTART:   return "restart key";
3800262182Semaste        case KEY_RESUME:    return "resume key";
3801262182Semaste        case KEY_SAVE:      return "save key";
3802262182Semaste        case KEY_SBEG:      return "shifted begin key";
3803262182Semaste        case KEY_SCANCEL:   return "shifted cancel key";
3804262182Semaste        case KEY_SCOMMAND:  return "shifted command key";
3805262182Semaste        case KEY_SCOPY:     return "shifted copy key";
3806262182Semaste        case KEY_SCREATE:   return "shifted create key";
3807262182Semaste        case KEY_SDC:       return "shifted delete-character key";
3808262182Semaste        case KEY_SDL:       return "shifted delete-line key";
3809262182Semaste        case KEY_SELECT:    return "select key";
3810262182Semaste        case KEY_SEND:      return "shifted end key";
3811262182Semaste        case KEY_SEOL:      return "shifted clear-to-end-of-line key";
3812262182Semaste        case KEY_SEXIT:     return "shifted exit key";
3813262182Semaste        case KEY_SFIND:     return "shifted find key";
3814262182Semaste        case KEY_SHELP:     return "shifted help key";
3815262182Semaste        case KEY_SHOME:     return "shifted home key";
3816262182Semaste        case KEY_SIC:       return "shifted insert-character key";
3817262182Semaste        case KEY_SLEFT:     return "shifted left-arrow key";
3818262182Semaste        case KEY_SMESSAGE:  return "shifted message key";
3819262182Semaste        case KEY_SMOVE:     return "shifted move key";
3820262182Semaste        case KEY_SNEXT:     return "shifted next key";
3821262182Semaste        case KEY_SOPTIONS:  return "shifted options key";
3822262182Semaste        case KEY_SPREVIOUS: return "shifted previous key";
3823262182Semaste        case KEY_SPRINT:    return "shifted print key";
3824262182Semaste        case KEY_SREDO:     return "shifted redo key";
3825262182Semaste        case KEY_SREPLACE:  return "shifted replace key";
3826262182Semaste        case KEY_SRIGHT:    return "shifted right-arrow key";
3827262182Semaste        case KEY_SRSUME:    return "shifted resume key";
3828262182Semaste        case KEY_SSAVE:     return "shifted save key";
3829262182Semaste        case KEY_SSUSPEND:  return "shifted suspend key";
3830262182Semaste        case KEY_SUNDO:     return "shifted undo key";
3831262182Semaste        case KEY_SUSPEND:   return "suspend key";
3832262182Semaste        case KEY_UNDO:      return "undo key";
3833262182Semaste        case KEY_MOUSE:     return "Mouse event has occurred";
3834262182Semaste        case KEY_RESIZE:    return "Terminal resize event";
3835262182Semaste        case KEY_EVENT:     return "We were interrupted by an event";
3836262182Semaste        case KEY_RETURN:    return "return";
3837262182Semaste        case ' ':           return "space";
3838262182Semaste        case '\t':          return "tab";
3839262182Semaste        case KEY_ESCAPE:    return "escape";
3840262182Semaste        default:
3841262182Semaste            if (isprint(ch))
3842262182Semaste                snprintf(g_desc, sizeof(g_desc), "%c", ch);
3843262182Semaste            else
3844262182Semaste                snprintf(g_desc, sizeof(g_desc), "\\x%2.2x", ch);
3845262182Semaste            return g_desc;
3846262182Semaste    }
3847262182Semaste    return NULL;
3848262182Semaste}
3849262182Semaste
3850262182SemasteHelpDialogDelegate::HelpDialogDelegate (const char *text, KeyHelp *key_help_array) :
3851262182Semaste    m_text (),
3852262182Semaste    m_first_visible_line (0)
3853262182Semaste{
3854262182Semaste    if (text && text[0])
3855262182Semaste    {
3856262182Semaste        m_text.SplitIntoLines(text);
3857262182Semaste        m_text.AppendString("");
3858262182Semaste    }
3859262182Semaste    if (key_help_array)
3860262182Semaste    {
3861262182Semaste        for (KeyHelp *key = key_help_array; key->ch; ++key)
3862262182Semaste        {
3863262182Semaste            StreamString key_description;
3864262182Semaste            key_description.Printf("%10s - %s", CursesKeyToCString(key->ch), key->description);
3865262182Semaste            m_text.AppendString(std::move(key_description.GetString()));
3866262182Semaste        }
3867262182Semaste    }
3868262182Semaste}
3869262182Semaste
3870262182SemasteHelpDialogDelegate::~HelpDialogDelegate()
3871262182Semaste{
3872262182Semaste}
3873262182Semaste
3874262182Semastebool
3875262182SemasteHelpDialogDelegate::WindowDelegateDraw (Window &window, bool force)
3876262182Semaste{
3877262182Semaste    window.Erase();
3878262182Semaste    const int window_height = window.GetHeight();
3879262182Semaste    int x = 2;
3880262182Semaste    int y = 1;
3881262182Semaste    const int min_y = y;
3882262182Semaste    const int max_y = window_height - 1 - y;
3883262182Semaste    const int num_visible_lines = max_y - min_y + 1;
3884262182Semaste    const size_t num_lines = m_text.GetSize();
3885262182Semaste    const char *bottom_message;
3886262182Semaste    if (num_lines <= num_visible_lines)
3887262182Semaste        bottom_message = "Press any key to exit";
3888262182Semaste    else
3889262182Semaste        bottom_message = "Use arrows to scroll, any other key to exit";
3890262182Semaste    window.DrawTitleBox(window.GetName(), bottom_message);
3891262182Semaste    while (y <= max_y)
3892262182Semaste    {
3893262182Semaste        window.MoveCursor(x, y);
3894262182Semaste        window.PutCStringTruncated(m_text.GetStringAtIndex(m_first_visible_line + y - min_y), 1);
3895262182Semaste        ++y;
3896262182Semaste    }
3897262182Semaste    return true;
3898262182Semaste}
3899262182Semaste
3900262182SemasteHandleCharResult
3901262182SemasteHelpDialogDelegate::WindowDelegateHandleChar (Window &window, int key)
3902262182Semaste{
3903262182Semaste    bool done = false;
3904262182Semaste    const size_t num_lines = m_text.GetSize();
3905262182Semaste    const size_t num_visible_lines = window.GetHeight() - 2;
3906262182Semaste
3907262182Semaste    if (num_lines <= num_visible_lines)
3908262182Semaste    {
3909262182Semaste        done = true;
3910262182Semaste        // If we have all lines visible and don't need scrolling, then any
3911262182Semaste        // key press will cause us to exit
3912262182Semaste    }
3913262182Semaste    else
3914262182Semaste    {
3915262182Semaste        switch (key)
3916262182Semaste        {
3917262182Semaste            case KEY_UP:
3918262182Semaste                if (m_first_visible_line > 0)
3919262182Semaste                    --m_first_visible_line;
3920262182Semaste                break;
3921262182Semaste
3922262182Semaste            case KEY_DOWN:
3923262182Semaste                if (m_first_visible_line + num_visible_lines < num_lines)
3924262182Semaste                    ++m_first_visible_line;
3925262182Semaste                break;
3926262182Semaste
3927262182Semaste            case KEY_PPAGE:
3928262182Semaste            case ',':
3929262182Semaste                if (m_first_visible_line > 0)
3930262182Semaste                {
3931262182Semaste                    if (m_first_visible_line >= num_visible_lines)
3932262182Semaste                        m_first_visible_line -= num_visible_lines;
3933262182Semaste                    else
3934262182Semaste                        m_first_visible_line = 0;
3935262182Semaste                }
3936262182Semaste                break;
3937262182Semaste            case KEY_NPAGE:
3938262182Semaste            case '.':
3939262182Semaste                if (m_first_visible_line + num_visible_lines < num_lines)
3940262182Semaste                {
3941262182Semaste                    m_first_visible_line += num_visible_lines;
3942262182Semaste                    if (m_first_visible_line > num_lines)
3943262182Semaste                        m_first_visible_line = num_lines - num_visible_lines;
3944262182Semaste                }
3945262182Semaste                break;
3946262182Semaste            default:
3947262182Semaste                done = true;
3948262182Semaste                break;
3949262182Semaste        }
3950262182Semaste    }
3951262182Semaste    if (done)
3952262182Semaste        window.GetParent()->RemoveSubWindow(&window);
3953262182Semaste    return eKeyHandled;
3954262182Semaste}
3955262182Semaste
3956262182Semasteclass ApplicationDelegate :
3957262182Semaste    public WindowDelegate,
3958262182Semaste    public MenuDelegate
3959262182Semaste{
3960262182Semastepublic:
3961262182Semaste    enum {
3962262182Semaste        eMenuID_LLDB = 1,
3963262182Semaste        eMenuID_LLDBAbout,
3964262182Semaste        eMenuID_LLDBExit,
3965262182Semaste
3966262182Semaste        eMenuID_Target,
3967262182Semaste        eMenuID_TargetCreate,
3968262182Semaste        eMenuID_TargetDelete,
3969262182Semaste
3970262182Semaste        eMenuID_Process,
3971262182Semaste        eMenuID_ProcessAttach,
3972262182Semaste        eMenuID_ProcessDetach,
3973262182Semaste        eMenuID_ProcessLaunch,
3974262182Semaste        eMenuID_ProcessContinue,
3975262182Semaste        eMenuID_ProcessHalt,
3976262182Semaste        eMenuID_ProcessKill,
3977262182Semaste
3978262182Semaste        eMenuID_Thread,
3979262182Semaste        eMenuID_ThreadStepIn,
3980262182Semaste        eMenuID_ThreadStepOver,
3981262182Semaste        eMenuID_ThreadStepOut,
3982262182Semaste
3983262182Semaste        eMenuID_View,
3984262182Semaste        eMenuID_ViewBacktrace,
3985262182Semaste        eMenuID_ViewRegisters,
3986262182Semaste        eMenuID_ViewSource,
3987262182Semaste        eMenuID_ViewVariables,
3988262182Semaste
3989262182Semaste        eMenuID_Help,
3990262182Semaste        eMenuID_HelpGUIHelp
3991262182Semaste    };
3992262182Semaste
3993262182Semaste    ApplicationDelegate (Application &app, Debugger &debugger) :
3994262182Semaste        WindowDelegate (),
3995262182Semaste        MenuDelegate (),
3996262182Semaste        m_app (app),
3997262182Semaste        m_debugger (debugger)
3998262182Semaste    {
3999262182Semaste    }
4000262182Semaste
4001262182Semaste    virtual
4002262182Semaste    ~ApplicationDelegate ()
4003262182Semaste    {
4004262182Semaste    }
4005262182Semaste    virtual bool
4006262182Semaste    WindowDelegateDraw (Window &window, bool force)
4007262182Semaste    {
4008262182Semaste        return false; // Drawing not handled, let standard window drawing happen
4009262182Semaste    }
4010262182Semaste
4011262182Semaste    virtual HandleCharResult
4012262182Semaste    WindowDelegateHandleChar (Window &window, int key)
4013262182Semaste    {
4014262182Semaste        switch (key)
4015262182Semaste        {
4016262182Semaste            case '\t':
4017262182Semaste                window.SelectNextWindowAsActive();
4018262182Semaste                return eKeyHandled;
4019262182Semaste
4020262182Semaste            case 'h':
4021262182Semaste                window.CreateHelpSubwindow();
4022262182Semaste                return eKeyHandled;
4023262182Semaste
4024262182Semaste            case KEY_ESCAPE:
4025262182Semaste                return eQuitApplication;
4026262182Semaste
4027262182Semaste            default:
4028262182Semaste                break;
4029262182Semaste        }
4030262182Semaste        return eKeyNotHandled;
4031262182Semaste    }
4032262182Semaste
4033262182Semaste
4034262182Semaste    virtual const char *
4035262182Semaste    WindowDelegateGetHelpText ()
4036262182Semaste    {
4037262182Semaste        return "Welcome to the LLDB curses GUI.\n\n"
4038262182Semaste        "Press the TAB key to change the selected view.\n"
4039262182Semaste        "Each view has its own keyboard shortcuts, press 'h' to open a dialog to display them.\n\n"
4040262182Semaste        "Common key bindings for all views:";
4041262182Semaste    }
4042262182Semaste
4043262182Semaste    virtual KeyHelp *
4044262182Semaste    WindowDelegateGetKeyHelp ()
4045262182Semaste    {
4046262182Semaste        static curses::KeyHelp g_source_view_key_help[] = {
4047262182Semaste            { '\t', "Select next view" },
4048262182Semaste            { 'h', "Show help dialog with view specific key bindings" },
4049262182Semaste            { ',', "Page up" },
4050262182Semaste            { '.', "Page down" },
4051262182Semaste            { KEY_UP, "Select previous" },
4052262182Semaste            { KEY_DOWN, "Select next" },
4053262182Semaste            { KEY_LEFT, "Unexpand or select parent" },
4054262182Semaste            { KEY_RIGHT, "Expand" },
4055262182Semaste            { KEY_PPAGE, "Page up" },
4056262182Semaste            { KEY_NPAGE, "Page down" },
4057262182Semaste            { '\0', NULL }
4058262182Semaste        };
4059262182Semaste        return g_source_view_key_help;
4060262182Semaste    }
4061262182Semaste
4062262182Semaste    virtual MenuActionResult
4063262182Semaste    MenuDelegateAction (Menu &menu)
4064262182Semaste    {
4065262182Semaste        switch (menu.GetIdentifier())
4066262182Semaste        {
4067262182Semaste            case eMenuID_ThreadStepIn:
4068262182Semaste                {
4069262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4070262182Semaste                    if (exe_ctx.HasThreadScope())
4071262182Semaste                    {
4072262182Semaste                        Process *process = exe_ctx.GetProcessPtr();
4073262182Semaste                        if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
4074262182Semaste                            exe_ctx.GetThreadRef().StepIn(true, true);
4075262182Semaste                    }
4076262182Semaste                }
4077262182Semaste                return MenuActionResult::Handled;
4078262182Semaste
4079262182Semaste            case eMenuID_ThreadStepOut:
4080262182Semaste                {
4081262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4082262182Semaste                    if (exe_ctx.HasThreadScope())
4083262182Semaste                    {
4084262182Semaste                        Process *process = exe_ctx.GetProcessPtr();
4085262182Semaste                        if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
4086262182Semaste                            exe_ctx.GetThreadRef().StepOut();
4087262182Semaste                    }
4088262182Semaste                }
4089262182Semaste                return MenuActionResult::Handled;
4090262182Semaste
4091262182Semaste            case eMenuID_ThreadStepOver:
4092262182Semaste                {
4093262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4094262182Semaste                    if (exe_ctx.HasThreadScope())
4095262182Semaste                    {
4096262182Semaste                        Process *process = exe_ctx.GetProcessPtr();
4097262182Semaste                        if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
4098262182Semaste                            exe_ctx.GetThreadRef().StepOver(true);
4099262182Semaste                    }
4100262182Semaste                }
4101262182Semaste                return MenuActionResult::Handled;
4102262182Semaste
4103262182Semaste            case eMenuID_ProcessContinue:
4104262182Semaste                {
4105262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4106262182Semaste                    if (exe_ctx.HasProcessScope())
4107262182Semaste                    {
4108262182Semaste                        Process *process = exe_ctx.GetProcessPtr();
4109262182Semaste                        if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
4110262182Semaste                            process->Resume();
4111262182Semaste                    }
4112262182Semaste                }
4113262182Semaste                return MenuActionResult::Handled;
4114262182Semaste
4115262182Semaste            case eMenuID_ProcessKill:
4116262182Semaste                {
4117262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4118262182Semaste                    if (exe_ctx.HasProcessScope())
4119262182Semaste                    {
4120262182Semaste                        Process *process = exe_ctx.GetProcessPtr();
4121262182Semaste                        if (process && process->IsAlive())
4122262182Semaste                            process->Destroy();
4123262182Semaste                    }
4124262182Semaste                }
4125262182Semaste                return MenuActionResult::Handled;
4126262182Semaste
4127262182Semaste            case eMenuID_ProcessHalt:
4128262182Semaste                {
4129262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4130262182Semaste                    if (exe_ctx.HasProcessScope())
4131262182Semaste                    {
4132262182Semaste                        Process *process = exe_ctx.GetProcessPtr();
4133262182Semaste                        if (process && process->IsAlive())
4134262182Semaste                            process->Halt();
4135262182Semaste                    }
4136262182Semaste                }
4137262182Semaste                return MenuActionResult::Handled;
4138262182Semaste
4139262182Semaste            case eMenuID_ProcessDetach:
4140262182Semaste                {
4141262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4142262182Semaste                    if (exe_ctx.HasProcessScope())
4143262182Semaste                    {
4144262182Semaste                        Process *process = exe_ctx.GetProcessPtr();
4145262182Semaste                        if (process && process->IsAlive())
4146262182Semaste                            process->Detach(false);
4147262182Semaste                    }
4148262182Semaste                }
4149262182Semaste                return MenuActionResult::Handled;
4150262182Semaste
4151262182Semaste            case eMenuID_Process:
4152262182Semaste                {
4153262182Semaste                    // Populate the menu with all of the threads if the process is stopped when
4154262182Semaste                    // the Process menu gets selected and is about to display its submenu.
4155262182Semaste                    Menus &submenus = menu.GetSubmenus();
4156262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4157262182Semaste                    Process *process = exe_ctx.GetProcessPtr();
4158262182Semaste                    if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
4159262182Semaste                    {
4160262182Semaste                        if (submenus.size() == 7)
4161262182Semaste                            menu.AddSubmenu (MenuSP (new Menu(Menu::Type::Separator)));
4162262182Semaste                        else if (submenus.size() > 8)
4163262182Semaste                            submenus.erase (submenus.begin() + 8, submenus.end());
4164262182Semaste
4165262182Semaste                        ThreadList &threads = process->GetThreadList();
4166262182Semaste                        Mutex::Locker locker (threads.GetMutex());
4167262182Semaste                        size_t num_threads = threads.GetSize();
4168262182Semaste                        for (size_t i=0; i<num_threads; ++i)
4169262182Semaste                        {
4170262182Semaste                            ThreadSP thread_sp = threads.GetThreadAtIndex(i);
4171262182Semaste                            char menu_char = '\0';
4172262182Semaste                            if (i < 9)
4173262182Semaste                                menu_char = '1' + i;
4174262182Semaste                            StreamString thread_menu_title;
4175262182Semaste                            thread_menu_title.Printf("Thread %u", thread_sp->GetIndexID());
4176262182Semaste                            const char *thread_name = thread_sp->GetName();
4177262182Semaste                            if (thread_name && thread_name[0])
4178262182Semaste                                thread_menu_title.Printf (" %s", thread_name);
4179262182Semaste                            else
4180262182Semaste                            {
4181262182Semaste                                const char *queue_name = thread_sp->GetQueueName();
4182262182Semaste                                if (queue_name && queue_name[0])
4183262182Semaste                                    thread_menu_title.Printf (" %s", queue_name);
4184262182Semaste                            }
4185262182Semaste                            menu.AddSubmenu (MenuSP (new Menu(thread_menu_title.GetString().c_str(), NULL, menu_char, thread_sp->GetID())));
4186262182Semaste                        }
4187262182Semaste                    }
4188262182Semaste                    else if (submenus.size() > 7)
4189262182Semaste                    {
4190262182Semaste                        // Remove the separator and any other thread submenu items
4191262182Semaste                        // that were previously added
4192262182Semaste                        submenus.erase (submenus.begin() + 7, submenus.end());
4193262182Semaste                    }
4194262182Semaste                    // Since we are adding and removing items we need to recalculate the name lengths
4195262182Semaste                    menu.RecalculateNameLengths();
4196262182Semaste                }
4197262182Semaste                return MenuActionResult::Handled;
4198262182Semaste
4199262182Semaste            case eMenuID_ViewVariables:
4200262182Semaste                {
4201262182Semaste                    WindowSP main_window_sp = m_app.GetMainWindow();
4202262182Semaste                    WindowSP source_window_sp = main_window_sp->FindSubWindow("Source");
4203262182Semaste                    WindowSP variables_window_sp = main_window_sp->FindSubWindow("Variables");
4204262182Semaste                    WindowSP registers_window_sp = main_window_sp->FindSubWindow("Registers");
4205262182Semaste                    const Rect source_bounds = source_window_sp->GetBounds();
4206262182Semaste
4207262182Semaste                    if (variables_window_sp)
4208262182Semaste                    {
4209262182Semaste                        const Rect variables_bounds = variables_window_sp->GetBounds();
4210262182Semaste
4211262182Semaste                        main_window_sp->RemoveSubWindow(variables_window_sp.get());
4212262182Semaste
4213262182Semaste                        if (registers_window_sp)
4214262182Semaste                        {
4215262182Semaste                            // We have a registers window, so give all the area back to the registers window
4216262182Semaste                            Rect registers_bounds = variables_bounds;
4217262182Semaste                            registers_bounds.size.width = source_bounds.size.width;
4218262182Semaste                            registers_window_sp->SetBounds(registers_bounds);
4219262182Semaste                        }
4220262182Semaste                        else
4221262182Semaste                        {
4222262182Semaste                            // We have no registers window showing so give the bottom
4223262182Semaste                            // area back to the source view
4224262182Semaste                            source_window_sp->Resize (source_bounds.size.width,
4225262182Semaste                                                      source_bounds.size.height + variables_bounds.size.height);
4226262182Semaste                        }
4227262182Semaste                    }
4228262182Semaste                    else
4229262182Semaste                    {
4230262182Semaste                        Rect new_variables_rect;
4231262182Semaste                        if (registers_window_sp)
4232262182Semaste                        {
4233262182Semaste                            // We have a registers window so split the area of the registers
4234262182Semaste                            // window into two columns where the left hand side will be the
4235262182Semaste                            // variables and the right hand side will be the registers
4236262182Semaste                            const Rect variables_bounds = registers_window_sp->GetBounds();
4237262182Semaste                            Rect new_registers_rect;
4238262182Semaste                            variables_bounds.VerticalSplitPercentage (0.50, new_variables_rect, new_registers_rect);
4239262182Semaste                            registers_window_sp->SetBounds (new_registers_rect);
4240262182Semaste                        }
4241262182Semaste                        else
4242262182Semaste                        {
4243262182Semaste                            // No variables window, grab the bottom part of the source window
4244262182Semaste                            Rect new_source_rect;
4245262182Semaste                            source_bounds.HorizontalSplitPercentage (0.70, new_source_rect, new_variables_rect);
4246262182Semaste                            source_window_sp->SetBounds (new_source_rect);
4247262182Semaste                        }
4248262182Semaste                        WindowSP new_window_sp = main_window_sp->CreateSubWindow ("Variables",
4249262182Semaste                                                                                  new_variables_rect,
4250262182Semaste                                                                                  false);
4251262182Semaste                        new_window_sp->SetDelegate (WindowDelegateSP(new FrameVariablesWindowDelegate(m_debugger)));
4252262182Semaste                    }
4253262182Semaste                    touchwin(stdscr);
4254262182Semaste                }
4255262182Semaste                return MenuActionResult::Handled;
4256262182Semaste
4257262182Semaste            case eMenuID_ViewRegisters:
4258262182Semaste                {
4259262182Semaste                    WindowSP main_window_sp = m_app.GetMainWindow();
4260262182Semaste                    WindowSP source_window_sp = main_window_sp->FindSubWindow("Source");
4261262182Semaste                    WindowSP variables_window_sp = main_window_sp->FindSubWindow("Variables");
4262262182Semaste                    WindowSP registers_window_sp = main_window_sp->FindSubWindow("Registers");
4263262182Semaste                    const Rect source_bounds = source_window_sp->GetBounds();
4264262182Semaste
4265262182Semaste                    if (registers_window_sp)
4266262182Semaste                    {
4267262182Semaste                        if (variables_window_sp)
4268262182Semaste                        {
4269262182Semaste                            const Rect variables_bounds = variables_window_sp->GetBounds();
4270262182Semaste
4271262182Semaste                            // We have a variables window, so give all the area back to the variables window
4272262182Semaste                            variables_window_sp->Resize (variables_bounds.size.width + registers_window_sp->GetWidth(),
4273262182Semaste                                                         variables_bounds.size.height);
4274262182Semaste                        }
4275262182Semaste                        else
4276262182Semaste                        {
4277262182Semaste                            // We have no variables window showing so give the bottom
4278262182Semaste                            // area back to the source view
4279262182Semaste                            source_window_sp->Resize (source_bounds.size.width,
4280262182Semaste                                                      source_bounds.size.height + registers_window_sp->GetHeight());
4281262182Semaste                        }
4282262182Semaste                        main_window_sp->RemoveSubWindow(registers_window_sp.get());
4283262182Semaste                    }
4284262182Semaste                    else
4285262182Semaste                    {
4286262182Semaste                        Rect new_regs_rect;
4287262182Semaste                        if (variables_window_sp)
4288262182Semaste                        {
4289262182Semaste                            // We have a variables window, split it into two columns
4290262182Semaste                            // where the left hand side will be the variables and the
4291262182Semaste                            // right hand side will be the registers
4292262182Semaste                            const Rect variables_bounds = variables_window_sp->GetBounds();
4293262182Semaste                            Rect new_vars_rect;
4294262182Semaste                            variables_bounds.VerticalSplitPercentage (0.50, new_vars_rect, new_regs_rect);
4295262182Semaste                            variables_window_sp->SetBounds (new_vars_rect);
4296262182Semaste                        }
4297262182Semaste                        else
4298262182Semaste                        {
4299262182Semaste                            // No registers window, grab the bottom part of the source window
4300262182Semaste                            Rect new_source_rect;
4301262182Semaste                            source_bounds.HorizontalSplitPercentage (0.70, new_source_rect, new_regs_rect);
4302262182Semaste                            source_window_sp->SetBounds (new_source_rect);
4303262182Semaste                        }
4304262182Semaste                        WindowSP new_window_sp = main_window_sp->CreateSubWindow ("Registers",
4305262182Semaste                                                                                  new_regs_rect,
4306262182Semaste                                                                                  false);
4307262182Semaste                        new_window_sp->SetDelegate (WindowDelegateSP(new RegistersWindowDelegate(m_debugger)));
4308262182Semaste                    }
4309262182Semaste                    touchwin(stdscr);
4310262182Semaste                }
4311262182Semaste                return MenuActionResult::Handled;
4312262182Semaste
4313262182Semaste            case eMenuID_HelpGUIHelp:
4314262182Semaste                m_app.GetMainWindow ()->CreateHelpSubwindow();
4315262182Semaste                return MenuActionResult::Handled;
4316262182Semaste
4317262182Semaste            default:
4318262182Semaste                break;
4319262182Semaste        }
4320262182Semaste
4321262182Semaste        return MenuActionResult::NotHandled;
4322262182Semaste    }
4323262182Semasteprotected:
4324262182Semaste    Application &m_app;
4325262182Semaste    Debugger &m_debugger;
4326262182Semaste};
4327262182Semaste
4328262182Semaste
4329262182Semasteclass StatusBarWindowDelegate : public WindowDelegate
4330262182Semaste{
4331262182Semastepublic:
4332262182Semaste    StatusBarWindowDelegate (Debugger &debugger) :
4333262182Semaste        m_debugger (debugger)
4334262182Semaste    {
4335262182Semaste    }
4336262182Semaste
4337262182Semaste    virtual
4338262182Semaste    ~StatusBarWindowDelegate ()
4339262182Semaste    {
4340262182Semaste    }
4341262182Semaste    virtual bool
4342262182Semaste    WindowDelegateDraw (Window &window, bool force)
4343262182Semaste    {
4344262182Semaste        ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4345262182Semaste        Process *process = exe_ctx.GetProcessPtr();
4346262182Semaste        Thread *thread = exe_ctx.GetThreadPtr();
4347262182Semaste        StackFrame *frame = exe_ctx.GetFramePtr();
4348262182Semaste        window.Erase();
4349262182Semaste        window.SetBackground(2);
4350262182Semaste        window.MoveCursor (0, 0);
4351262182Semaste        if (process)
4352262182Semaste        {
4353262182Semaste            const StateType state = process->GetState();
4354262182Semaste            window.Printf ("Process: %5" PRIu64 " %10s", process->GetID(), StateAsCString(state));
4355262182Semaste
4356262182Semaste            if (StateIsStoppedState(state, true))
4357262182Semaste            {
4358262182Semaste                window.MoveCursor (40, 0);
4359262182Semaste                if (thread)
4360262182Semaste                    window.Printf ("Thread: 0x%4.4" PRIx64, thread->GetID());
4361262182Semaste
4362262182Semaste                window.MoveCursor (60, 0);
4363262182Semaste                if (frame)
4364262182Semaste                    window.Printf ("Frame: %3u  PC = 0x%16.16" PRIx64, frame->GetFrameIndex(), frame->GetFrameCodeAddress().GetOpcodeLoadAddress (exe_ctx.GetTargetPtr()));
4365262182Semaste            }
4366262182Semaste            else if (state == eStateExited)
4367262182Semaste            {
4368262182Semaste                const char *exit_desc = process->GetExitDescription();
4369262182Semaste                const int exit_status = process->GetExitStatus();
4370262182Semaste                if (exit_desc && exit_desc[0])
4371262182Semaste                    window.Printf (" with status = %i (%s)", exit_status, exit_desc);
4372262182Semaste                else
4373262182Semaste                    window.Printf (" with status = %i", exit_status);
4374262182Semaste            }
4375262182Semaste        }
4376262182Semaste        window.DeferredRefresh();
4377262182Semaste        return true;
4378262182Semaste    }
4379262182Semaste
4380262182Semasteprotected:
4381262182Semaste    Debugger &m_debugger;
4382262182Semaste};
4383262182Semaste
4384262182Semasteclass SourceFileWindowDelegate : public WindowDelegate
4385262182Semaste{
4386262182Semastepublic:
4387262182Semaste    SourceFileWindowDelegate (Debugger &debugger) :
4388262182Semaste        WindowDelegate (),
4389262182Semaste        m_debugger (debugger),
4390262182Semaste        m_sc (),
4391262182Semaste        m_file_sp (),
4392262182Semaste        m_disassembly_scope (NULL),
4393262182Semaste        m_disassembly_sp (),
4394262182Semaste        m_disassembly_range (),
4395262182Semaste        m_line_width (4),
4396262182Semaste        m_selected_line (0),
4397262182Semaste        m_pc_line (0),
4398262182Semaste        m_stop_id (0),
4399262182Semaste        m_frame_idx (UINT32_MAX),
4400262182Semaste        m_first_visible_line (0),
4401262182Semaste        m_min_x (0),
4402262182Semaste        m_min_y (0),
4403262182Semaste        m_max_x (0),
4404262182Semaste        m_max_y (0)
4405262182Semaste    {
4406262182Semaste    }
4407262182Semaste
4408262182Semaste
4409262182Semaste    virtual
4410262182Semaste    ~SourceFileWindowDelegate()
4411262182Semaste    {
4412262182Semaste    }
4413262182Semaste
4414262182Semaste    void
4415262182Semaste    Update (const SymbolContext &sc)
4416262182Semaste    {
4417262182Semaste        m_sc = sc;
4418262182Semaste    }
4419262182Semaste
4420262182Semaste    uint32_t
4421262182Semaste    NumVisibleLines () const
4422262182Semaste    {
4423262182Semaste        return m_max_y - m_min_y;
4424262182Semaste    }
4425262182Semaste
4426262182Semaste    virtual const char *
4427262182Semaste    WindowDelegateGetHelpText ()
4428262182Semaste    {
4429262182Semaste        return "Source/Disassembly window keyboard shortcuts:";
4430262182Semaste    }
4431262182Semaste
4432262182Semaste    virtual KeyHelp *
4433262182Semaste    WindowDelegateGetKeyHelp ()
4434262182Semaste    {
4435262182Semaste        static curses::KeyHelp g_source_view_key_help[] = {
4436262182Semaste            { KEY_RETURN, "Run to selected line with one shot breakpoint" },
4437262182Semaste            { KEY_UP, "Select previous source line" },
4438262182Semaste            { KEY_DOWN, "Select next source line" },
4439262182Semaste            { KEY_PPAGE, "Page up" },
4440262182Semaste            { KEY_NPAGE, "Page down" },
4441262182Semaste            { 'b', "Set breakpoint on selected source/disassembly line" },
4442262182Semaste            { 'c', "Continue process" },
4443262182Semaste            { 'd', "Detach and resume process" },
4444262182Semaste            { 'D', "Detach with process suspended" },
4445262182Semaste            { 'h', "Show help dialog" },
4446262182Semaste            { 'k', "Kill process" },
4447262182Semaste            { 'n', "Step over (source line)" },
4448262182Semaste            { 'N', "Step over (single instruction)" },
4449262182Semaste            { 'o', "Step out" },
4450262182Semaste            { 's', "Step in (source line)" },
4451262182Semaste            { 'S', "Step in (single instruction)" },
4452262182Semaste            { ',', "Page up" },
4453262182Semaste            { '.', "Page down" },
4454262182Semaste            { '\0', NULL }
4455262182Semaste        };
4456262182Semaste        return g_source_view_key_help;
4457262182Semaste    }
4458262182Semaste
4459262182Semaste    virtual bool
4460262182Semaste    WindowDelegateDraw (Window &window, bool force)
4461262182Semaste    {
4462262182Semaste        ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4463262182Semaste        Process *process = exe_ctx.GetProcessPtr();
4464262182Semaste        Thread *thread = NULL;
4465262182Semaste
4466262182Semaste        bool update_location = false;
4467262182Semaste        if (process)
4468262182Semaste        {
4469262182Semaste            StateType state = process->GetState();
4470262182Semaste            if (StateIsStoppedState(state, true))
4471262182Semaste            {
4472262182Semaste                // We are stopped, so it is ok to
4473262182Semaste                update_location = true;
4474262182Semaste            }
4475262182Semaste        }
4476262182Semaste
4477262182Semaste        m_min_x = 1;
4478262182Semaste        m_min_y = 1;
4479262182Semaste        m_max_x = window.GetMaxX()-1;
4480262182Semaste        m_max_y = window.GetMaxY()-1;
4481262182Semaste
4482262182Semaste        const uint32_t num_visible_lines = NumVisibleLines();
4483262182Semaste        StackFrameSP frame_sp;
4484262182Semaste        bool set_selected_line_to_pc = false;
4485262182Semaste
4486262182Semaste
4487262182Semaste        if (update_location)
4488262182Semaste        {
4489262182Semaste
4490262182Semaste            const bool process_alive = process ? process->IsAlive() : false;
4491262182Semaste            bool thread_changed = false;
4492262182Semaste            if (process_alive)
4493262182Semaste            {
4494262182Semaste                thread = exe_ctx.GetThreadPtr();
4495262182Semaste                if (thread)
4496262182Semaste                {
4497262182Semaste                    frame_sp = thread->GetSelectedFrame();
4498262182Semaste                    auto tid = thread->GetID();
4499262182Semaste                    thread_changed = tid != m_tid;
4500262182Semaste                    m_tid = tid;
4501262182Semaste                }
4502262182Semaste                else
4503262182Semaste                {
4504262182Semaste                    if (m_tid != LLDB_INVALID_THREAD_ID)
4505262182Semaste                    {
4506262182Semaste                        thread_changed = true;
4507262182Semaste                        m_tid = LLDB_INVALID_THREAD_ID;
4508262182Semaste                    }
4509262182Semaste                }
4510262182Semaste            }
4511262182Semaste            const uint32_t stop_id = process ? process->GetStopID() : 0;
4512262182Semaste            const bool stop_id_changed = stop_id != m_stop_id;
4513262182Semaste            bool frame_changed = false;
4514262182Semaste            m_stop_id = stop_id;
4515262182Semaste            if (frame_sp)
4516262182Semaste            {
4517262182Semaste                m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
4518262182Semaste                const uint32_t frame_idx = frame_sp->GetFrameIndex();
4519262182Semaste                frame_changed = frame_idx != m_frame_idx;
4520262182Semaste                m_frame_idx = frame_idx;
4521262182Semaste            }
4522262182Semaste            else
4523262182Semaste            {
4524262182Semaste                m_sc.Clear(true);
4525262182Semaste                frame_changed = m_frame_idx != UINT32_MAX;
4526262182Semaste                m_frame_idx = UINT32_MAX;
4527262182Semaste            }
4528262182Semaste
4529262182Semaste            const bool context_changed = thread_changed || frame_changed || stop_id_changed;
4530262182Semaste
4531262182Semaste            if (process_alive)
4532262182Semaste            {
4533262182Semaste                if (m_sc.line_entry.IsValid())
4534262182Semaste                {
4535262182Semaste                    m_pc_line = m_sc.line_entry.line;
4536262182Semaste                    if (m_pc_line != UINT32_MAX)
4537262182Semaste                        --m_pc_line; // Convert to zero based line number...
4538262182Semaste                    // Update the selected line if the stop ID changed...
4539262182Semaste                    if (context_changed)
4540262182Semaste                        m_selected_line = m_pc_line;
4541262182Semaste
4542262182Semaste                    if (m_file_sp && m_file_sp->FileSpecMatches(m_sc.line_entry.file))
4543262182Semaste                    {
4544262182Semaste                        // Same file, nothing to do, we should either have the
4545262182Semaste                        // lines or not (source file missing)
4546262182Semaste                        if (m_selected_line >= m_first_visible_line)
4547262182Semaste                        {
4548262182Semaste                            if (m_selected_line >= m_first_visible_line + num_visible_lines)
4549262182Semaste                                m_first_visible_line = m_selected_line - 10;
4550262182Semaste                        }
4551262182Semaste                        else
4552262182Semaste                        {
4553262182Semaste                            if (m_selected_line > 10)
4554262182Semaste                                m_first_visible_line = m_selected_line - 10;
4555262182Semaste                            else
4556262182Semaste                                m_first_visible_line = 0;
4557262182Semaste                        }
4558262182Semaste                    }
4559262182Semaste                    else
4560262182Semaste                    {
4561262182Semaste                        // File changed, set selected line to the line with the PC
4562262182Semaste                        m_selected_line = m_pc_line;
4563262182Semaste                        m_file_sp = m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file);
4564262182Semaste                        if (m_file_sp)
4565262182Semaste                        {
4566262182Semaste                            const size_t num_lines = m_file_sp->GetNumLines();
4567262182Semaste                            int m_line_width = 1;
4568262182Semaste                            for (size_t n = num_lines; n >= 10; n = n / 10)
4569262182Semaste                                ++m_line_width;
4570262182Semaste
4571262182Semaste                            snprintf (m_line_format, sizeof(m_line_format), " %%%iu ", m_line_width);
4572262182Semaste                            if (num_lines < num_visible_lines || m_selected_line < num_visible_lines)
4573262182Semaste                                m_first_visible_line = 0;
4574262182Semaste                            else
4575262182Semaste                                m_first_visible_line = m_selected_line - 10;
4576262182Semaste                        }
4577262182Semaste                    }
4578262182Semaste                }
4579262182Semaste                else
4580262182Semaste                {
4581262182Semaste                    m_file_sp.reset();
4582262182Semaste                }
4583262182Semaste
4584262182Semaste                if (!m_file_sp || m_file_sp->GetNumLines() == 0)
4585262182Semaste                {
4586262182Semaste                    // Show disassembly
4587262182Semaste                    bool prefer_file_cache = false;
4588262182Semaste                    if (m_sc.function)
4589262182Semaste                    {
4590262182Semaste                        if (m_disassembly_scope != m_sc.function)
4591262182Semaste                        {
4592262182Semaste                            m_disassembly_scope = m_sc.function;
4593262182Semaste                            m_disassembly_sp = m_sc.function->GetInstructions (exe_ctx, NULL, prefer_file_cache);
4594262182Semaste                            if (m_disassembly_sp)
4595262182Semaste                            {
4596262182Semaste                                set_selected_line_to_pc = true;
4597262182Semaste                                m_disassembly_range = m_sc.function->GetAddressRange();
4598262182Semaste                            }
4599262182Semaste                            else
4600262182Semaste                            {
4601262182Semaste                                m_disassembly_range.Clear();
4602262182Semaste                            }
4603262182Semaste                        }
4604262182Semaste                        else
4605262182Semaste                        {
4606262182Semaste                            set_selected_line_to_pc = context_changed;
4607262182Semaste                        }
4608262182Semaste                    }
4609262182Semaste                    else if (m_sc.symbol)
4610262182Semaste                    {
4611262182Semaste                        if (m_disassembly_scope != m_sc.symbol)
4612262182Semaste                        {
4613262182Semaste                            m_disassembly_scope = m_sc.symbol;
4614262182Semaste                            m_disassembly_sp = m_sc.symbol->GetInstructions (exe_ctx, NULL, prefer_file_cache);
4615262182Semaste                            if (m_disassembly_sp)
4616262182Semaste                            {
4617262182Semaste                                set_selected_line_to_pc = true;
4618262182Semaste                                m_disassembly_range.GetBaseAddress() = m_sc.symbol->GetAddress();
4619262182Semaste                                m_disassembly_range.SetByteSize(m_sc.symbol->GetByteSize());
4620262182Semaste                            }
4621262182Semaste                            else
4622262182Semaste                            {
4623262182Semaste                                m_disassembly_range.Clear();
4624262182Semaste                            }
4625262182Semaste                        }
4626262182Semaste                        else
4627262182Semaste                        {
4628262182Semaste                            set_selected_line_to_pc = context_changed;
4629262182Semaste                        }
4630262182Semaste                    }
4631262182Semaste                }
4632262182Semaste            }
4633262182Semaste            else
4634262182Semaste            {
4635262182Semaste                m_pc_line = UINT32_MAX;
4636262182Semaste            }
4637262182Semaste        }
4638262182Semaste
4639262182Semaste
4640262182Semaste        window.Erase();
4641262182Semaste        window.DrawTitleBox ("Sources");
4642262182Semaste
4643262182Semaste
4644262182Semaste        Target *target = exe_ctx.GetTargetPtr();
4645262182Semaste        const size_t num_source_lines = GetNumSourceLines();
4646262182Semaste        if (num_source_lines > 0)
4647262182Semaste        {
4648262182Semaste            // Display source
4649262182Semaste            BreakpointLines bp_lines;
4650262182Semaste            if (target)
4651262182Semaste            {
4652262182Semaste                BreakpointList &bp_list = target->GetBreakpointList();
4653262182Semaste                const size_t num_bps = bp_list.GetSize();
4654262182Semaste                for (size_t bp_idx=0; bp_idx<num_bps; ++bp_idx)
4655262182Semaste                {
4656262182Semaste                    BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx);
4657262182Semaste                    const size_t num_bps_locs = bp_sp->GetNumLocations();
4658262182Semaste                    for (size_t bp_loc_idx=0; bp_loc_idx<num_bps_locs; ++bp_loc_idx)
4659262182Semaste                    {
4660262182Semaste                        BreakpointLocationSP bp_loc_sp = bp_sp->GetLocationAtIndex(bp_loc_idx);
4661262182Semaste                        LineEntry bp_loc_line_entry;
4662262182Semaste                        if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry (bp_loc_line_entry))
4663262182Semaste                        {
4664262182Semaste                            if (m_file_sp->GetFileSpec() == bp_loc_line_entry.file)
4665262182Semaste                            {
4666262182Semaste                                bp_lines.insert(bp_loc_line_entry.line);
4667262182Semaste                            }
4668262182Semaste                        }
4669262182Semaste                    }
4670262182Semaste                }
4671262182Semaste            }
4672262182Semaste
4673262182Semaste
4674262182Semaste            const attr_t selected_highlight_attr = A_REVERSE;
4675262182Semaste            const attr_t pc_highlight_attr = COLOR_PAIR(1);
4676262182Semaste
4677262182Semaste            for (int i=0; i<num_visible_lines; ++i)
4678262182Semaste            {
4679262182Semaste                const uint32_t curr_line = m_first_visible_line + i;
4680262182Semaste                if (curr_line < num_source_lines)
4681262182Semaste                {
4682262182Semaste                    const int line_y = 1+i;
4683262182Semaste                    window.MoveCursor(1, line_y);
4684262182Semaste                    const bool is_pc_line = curr_line == m_pc_line;
4685262182Semaste                    const bool line_is_selected = m_selected_line == curr_line;
4686262182Semaste                    // Highlight the line as the PC line first, then if the selected line
4687262182Semaste                    // isn't the same as the PC line, highlight it differently
4688262182Semaste                    attr_t highlight_attr = 0;
4689262182Semaste                    attr_t bp_attr = 0;
4690262182Semaste                    if (is_pc_line)
4691262182Semaste                        highlight_attr = pc_highlight_attr;
4692262182Semaste                    else if (line_is_selected)
4693262182Semaste                        highlight_attr = selected_highlight_attr;
4694262182Semaste
4695262182Semaste                    if (bp_lines.find(curr_line+1) != bp_lines.end())
4696262182Semaste                        bp_attr = COLOR_PAIR(2);
4697262182Semaste
4698262182Semaste                    if (bp_attr)
4699262182Semaste                        window.AttributeOn(bp_attr);
4700262182Semaste
4701262182Semaste                    window.Printf (m_line_format, curr_line + 1);
4702262182Semaste
4703262182Semaste                    if (bp_attr)
4704262182Semaste                        window.AttributeOff(bp_attr);
4705262182Semaste
4706262182Semaste                    window.PutChar(ACS_VLINE);
4707262182Semaste                    // Mark the line with the PC with a diamond
4708262182Semaste                    if (is_pc_line)
4709262182Semaste                        window.PutChar(ACS_DIAMOND);
4710262182Semaste                    else
4711262182Semaste                        window.PutChar(' ');
4712262182Semaste
4713262182Semaste                    if (highlight_attr)
4714262182Semaste                        window.AttributeOn(highlight_attr);
4715262182Semaste                    const uint32_t line_len = m_file_sp->GetLineLength(curr_line + 1, false);
4716262182Semaste                    if (line_len > 0)
4717262182Semaste                        window.PutCString(m_file_sp->PeekLineData(curr_line + 1), line_len);
4718262182Semaste
4719262182Semaste                    if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0)
4720262182Semaste                    {
4721262182Semaste                        StopInfoSP stop_info_sp;
4722262182Semaste                        if (thread)
4723262182Semaste                            stop_info_sp = thread->GetStopInfo();
4724262182Semaste                        if (stop_info_sp)
4725262182Semaste                        {
4726262182Semaste                            const char *stop_description = stop_info_sp->GetDescription();
4727262182Semaste                            if (stop_description && stop_description[0])
4728262182Semaste                            {
4729262182Semaste                                size_t stop_description_len = strlen(stop_description);
4730262182Semaste                                int desc_x = window.GetWidth() - stop_description_len - 16;
4731262182Semaste                                window.Printf ("%*s", desc_x - window.GetCursorX(), "");
4732262182Semaste                                //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y);
4733262182Semaste                                window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description);
4734262182Semaste                            }
4735262182Semaste                        }
4736262182Semaste                        else
4737262182Semaste                        {
4738262182Semaste                            window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, "");
4739262182Semaste                        }
4740262182Semaste                    }
4741262182Semaste                    if (highlight_attr)
4742262182Semaste                        window.AttributeOff(highlight_attr);
4743262182Semaste
4744262182Semaste                }
4745262182Semaste                else
4746262182Semaste                {
4747262182Semaste                    break;
4748262182Semaste                }
4749262182Semaste            }
4750262182Semaste        }
4751262182Semaste        else
4752262182Semaste        {
4753262182Semaste            size_t num_disassembly_lines = GetNumDisassemblyLines();
4754262182Semaste            if (num_disassembly_lines > 0)
4755262182Semaste            {
4756262182Semaste                // Display disassembly
4757262182Semaste                BreakpointAddrs bp_file_addrs;
4758262182Semaste                Target *target = exe_ctx.GetTargetPtr();
4759262182Semaste                if (target)
4760262182Semaste                {
4761262182Semaste                    BreakpointList &bp_list = target->GetBreakpointList();
4762262182Semaste                    const size_t num_bps = bp_list.GetSize();
4763262182Semaste                    for (size_t bp_idx=0; bp_idx<num_bps; ++bp_idx)
4764262182Semaste                    {
4765262182Semaste                        BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx);
4766262182Semaste                        const size_t num_bps_locs = bp_sp->GetNumLocations();
4767262182Semaste                        for (size_t bp_loc_idx=0; bp_loc_idx<num_bps_locs; ++bp_loc_idx)
4768262182Semaste                        {
4769262182Semaste                            BreakpointLocationSP bp_loc_sp = bp_sp->GetLocationAtIndex(bp_loc_idx);
4770262182Semaste                            LineEntry bp_loc_line_entry;
4771262182Semaste                            const lldb::addr_t file_addr = bp_loc_sp->GetAddress().GetFileAddress();
4772262182Semaste                            if (file_addr != LLDB_INVALID_ADDRESS)
4773262182Semaste                            {
4774262182Semaste                                if (m_disassembly_range.ContainsFileAddress(file_addr))
4775262182Semaste                                    bp_file_addrs.insert(file_addr);
4776262182Semaste                            }
4777262182Semaste                        }
4778262182Semaste                    }
4779262182Semaste                }
4780262182Semaste
4781262182Semaste
4782262182Semaste                const attr_t selected_highlight_attr = A_REVERSE;
4783262182Semaste                const attr_t pc_highlight_attr = COLOR_PAIR(1);
4784262182Semaste
4785262182Semaste                StreamString strm;
4786262182Semaste
4787262182Semaste                InstructionList &insts = m_disassembly_sp->GetInstructionList();
4788262182Semaste                Address pc_address;
4789262182Semaste
4790262182Semaste                if (frame_sp)
4791262182Semaste                    pc_address = frame_sp->GetFrameCodeAddress();
4792262182Semaste                const uint32_t pc_idx = pc_address.IsValid() ? insts.GetIndexOfInstructionAtAddress (pc_address) : UINT32_MAX;
4793262182Semaste                if (set_selected_line_to_pc)
4794262182Semaste                {
4795262182Semaste                    m_selected_line = pc_idx;
4796262182Semaste                }
4797262182Semaste
4798262182Semaste                const uint32_t non_visible_pc_offset = (num_visible_lines / 5);
4799262182Semaste                if (m_first_visible_line >= num_disassembly_lines)
4800262182Semaste                    m_first_visible_line = 0;
4801262182Semaste
4802262182Semaste                if (pc_idx < num_disassembly_lines)
4803262182Semaste                {
4804262182Semaste                    if (pc_idx < m_first_visible_line ||
4805262182Semaste                        pc_idx >= m_first_visible_line + num_visible_lines)
4806262182Semaste                        m_first_visible_line = pc_idx - non_visible_pc_offset;
4807262182Semaste                }
4808262182Semaste
4809262182Semaste                for (size_t i=0; i<num_visible_lines; ++i)
4810262182Semaste                {
4811262182Semaste                    const uint32_t inst_idx = m_first_visible_line + i;
4812262182Semaste                    Instruction *inst = insts.GetInstructionAtIndex(inst_idx).get();
4813262182Semaste                    if (!inst)
4814262182Semaste                        break;
4815262182Semaste
4816262182Semaste                    window.MoveCursor(1, i+1);
4817262182Semaste                    const bool is_pc_line = frame_sp && inst_idx == pc_idx;
4818262182Semaste                    const bool line_is_selected = m_selected_line == inst_idx;
4819262182Semaste                    // Highlight the line as the PC line first, then if the selected line
4820262182Semaste                    // isn't the same as the PC line, highlight it differently
4821262182Semaste                    attr_t highlight_attr = 0;
4822262182Semaste                    attr_t bp_attr = 0;
4823262182Semaste                    if (is_pc_line)
4824262182Semaste                        highlight_attr = pc_highlight_attr;
4825262182Semaste                    else if (line_is_selected)
4826262182Semaste                        highlight_attr = selected_highlight_attr;
4827262182Semaste
4828262182Semaste                    if (bp_file_addrs.find(inst->GetAddress().GetFileAddress()) != bp_file_addrs.end())
4829262182Semaste                        bp_attr = COLOR_PAIR(2);
4830262182Semaste
4831262182Semaste                    if (bp_attr)
4832262182Semaste                        window.AttributeOn(bp_attr);
4833262182Semaste
4834262182Semaste                    window.Printf (" 0x%16.16llx ", inst->GetAddress().GetLoadAddress(target));
4835262182Semaste
4836262182Semaste                    if (bp_attr)
4837262182Semaste                        window.AttributeOff(bp_attr);
4838262182Semaste
4839262182Semaste                    window.PutChar(ACS_VLINE);
4840262182Semaste                    // Mark the line with the PC with a diamond
4841262182Semaste                    if (is_pc_line)
4842262182Semaste                        window.PutChar(ACS_DIAMOND);
4843262182Semaste                    else
4844262182Semaste                        window.PutChar(' ');
4845262182Semaste
4846262182Semaste                    if (highlight_attr)
4847262182Semaste                        window.AttributeOn(highlight_attr);
4848262182Semaste
4849262182Semaste                    const char *mnemonic = inst->GetMnemonic(&exe_ctx);
4850262182Semaste                    const char *operands = inst->GetOperands(&exe_ctx);
4851262182Semaste                    const char *comment = inst->GetComment(&exe_ctx);
4852262182Semaste
4853262182Semaste                    if (mnemonic && mnemonic[0] == '\0')
4854262182Semaste                        mnemonic = NULL;
4855262182Semaste                    if (operands && operands[0] == '\0')
4856262182Semaste                        operands = NULL;
4857262182Semaste                    if (comment && comment[0] == '\0')
4858262182Semaste                        comment = NULL;
4859262182Semaste
4860262182Semaste                    strm.Clear();
4861262182Semaste
4862262182Semaste                    if (mnemonic && operands && comment)
4863262182Semaste                        strm.Printf ("%-8s %-25s ; %s", mnemonic, operands, comment);
4864262182Semaste                    else if (mnemonic && operands)
4865262182Semaste                        strm.Printf ("%-8s %s", mnemonic, operands);
4866262182Semaste                    else if (mnemonic)
4867262182Semaste                        strm.Printf ("%s", mnemonic);
4868262182Semaste
4869262182Semaste                    int right_pad = 1;
4870262182Semaste                    window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
4871262182Semaste
4872262182Semaste                    if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0)
4873262182Semaste                    {
4874262182Semaste                        StopInfoSP stop_info_sp;
4875262182Semaste                        if (thread)
4876262182Semaste                            stop_info_sp = thread->GetStopInfo();
4877262182Semaste                        if (stop_info_sp)
4878262182Semaste                        {
4879262182Semaste                            const char *stop_description = stop_info_sp->GetDescription();
4880262182Semaste                            if (stop_description && stop_description[0])
4881262182Semaste                            {
4882262182Semaste                                size_t stop_description_len = strlen(stop_description);
4883262182Semaste                                int desc_x = window.GetWidth() - stop_description_len - 16;
4884262182Semaste                                window.Printf ("%*s", desc_x - window.GetCursorX(), "");
4885262182Semaste                                //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y);
4886262182Semaste                                window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description);
4887262182Semaste                            }
4888262182Semaste                        }
4889262182Semaste                        else
4890262182Semaste                        {
4891262182Semaste                            window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, "");
4892262182Semaste                        }
4893262182Semaste                    }
4894262182Semaste                    if (highlight_attr)
4895262182Semaste                        window.AttributeOff(highlight_attr);
4896262182Semaste                }
4897262182Semaste            }
4898262182Semaste        }
4899262182Semaste        window.DeferredRefresh();
4900262182Semaste        return true; // Drawing handled
4901262182Semaste    }
4902262182Semaste
4903262182Semaste    size_t
4904262182Semaste    GetNumLines ()
4905262182Semaste    {
4906262182Semaste        size_t num_lines = GetNumSourceLines();
4907262182Semaste        if (num_lines == 0)
4908262182Semaste            num_lines = GetNumDisassemblyLines();
4909262182Semaste        return num_lines;
4910262182Semaste    }
4911262182Semaste
4912262182Semaste    size_t
4913262182Semaste    GetNumSourceLines () const
4914262182Semaste    {
4915262182Semaste        if (m_file_sp)
4916262182Semaste            return m_file_sp->GetNumLines();
4917262182Semaste        return 0;
4918262182Semaste    }
4919262182Semaste    size_t
4920262182Semaste    GetNumDisassemblyLines () const
4921262182Semaste    {
4922262182Semaste        if (m_disassembly_sp)
4923262182Semaste            return m_disassembly_sp->GetInstructionList().GetSize();
4924262182Semaste        return 0;
4925262182Semaste    }
4926262182Semaste
4927262182Semaste    virtual HandleCharResult
4928262182Semaste    WindowDelegateHandleChar (Window &window, int c)
4929262182Semaste    {
4930262182Semaste        const uint32_t num_visible_lines = NumVisibleLines();
4931262182Semaste        const size_t num_lines = GetNumLines ();
4932262182Semaste
4933262182Semaste        switch (c)
4934262182Semaste        {
4935262182Semaste            case ',':
4936262182Semaste            case KEY_PPAGE:
4937262182Semaste                // Page up key
4938262182Semaste                if (m_first_visible_line > num_visible_lines)
4939262182Semaste                    m_first_visible_line -= num_visible_lines;
4940262182Semaste                else
4941262182Semaste                    m_first_visible_line = 0;
4942262182Semaste                m_selected_line = m_first_visible_line;
4943262182Semaste                return eKeyHandled;
4944262182Semaste
4945262182Semaste            case '.':
4946262182Semaste            case KEY_NPAGE:
4947262182Semaste                // Page down key
4948262182Semaste                {
4949262182Semaste                    if (m_first_visible_line + num_visible_lines < num_lines)
4950262182Semaste                        m_first_visible_line += num_visible_lines;
4951262182Semaste                    else if (num_lines < num_visible_lines)
4952262182Semaste                        m_first_visible_line = 0;
4953262182Semaste                    else
4954262182Semaste                        m_first_visible_line = num_lines - num_visible_lines;
4955262182Semaste                    m_selected_line = m_first_visible_line;
4956262182Semaste                }
4957262182Semaste                return eKeyHandled;
4958262182Semaste
4959262182Semaste            case KEY_UP:
4960262182Semaste                if (m_selected_line > 0)
4961262182Semaste                {
4962262182Semaste                    m_selected_line--;
4963262182Semaste                    if (m_first_visible_line > m_selected_line)
4964262182Semaste                        m_first_visible_line = m_selected_line;
4965262182Semaste                }
4966262182Semaste                return eKeyHandled;
4967262182Semaste
4968262182Semaste            case KEY_DOWN:
4969262182Semaste                if (m_selected_line + 1 < num_lines)
4970262182Semaste                {
4971262182Semaste                    m_selected_line++;
4972262182Semaste                    if (m_first_visible_line + num_visible_lines < m_selected_line)
4973262182Semaste                        m_first_visible_line++;
4974262182Semaste                }
4975262182Semaste                return eKeyHandled;
4976262182Semaste
4977262182Semaste            case '\r':
4978262182Semaste            case '\n':
4979262182Semaste            case KEY_ENTER:
4980262182Semaste                // Set a breakpoint and run to the line using a one shot breakpoint
4981262182Semaste                if (GetNumSourceLines() > 0)
4982262182Semaste                {
4983262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4984262182Semaste                    if (exe_ctx.HasProcessScope() && exe_ctx.GetProcessRef().IsAlive())
4985262182Semaste                    {
4986262182Semaste                        BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (NULL,                      // Don't limit the breakpoint to certain modules
4987262182Semaste                                                                                      m_file_sp->GetFileSpec(),  // Source file
4988262182Semaste                                                                                      m_selected_line + 1,       // Source line number (m_selected_line is zero based)
4989262182Semaste                                                                                      eLazyBoolCalculate,        // Check inlines using global setting
4990262182Semaste                                                                                      eLazyBoolCalculate,        // Skip prologue using global setting,
4991262182Semaste                                                                                      false,                     // internal
4992262182Semaste                                                                                      false);                    // request_hardware
4993262182Semaste                        // Make breakpoint one shot
4994262182Semaste                        bp_sp->GetOptions()->SetOneShot(true);
4995262182Semaste                        exe_ctx.GetProcessRef().Resume();
4996262182Semaste                    }
4997262182Semaste                }
4998262182Semaste                else if (m_selected_line < GetNumDisassemblyLines())
4999262182Semaste                {
5000262182Semaste                    const Instruction *inst = m_disassembly_sp->GetInstructionList().GetInstructionAtIndex(m_selected_line).get();
5001262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5002262182Semaste                    if (exe_ctx.HasTargetScope())
5003262182Semaste                    {
5004262182Semaste                        Address addr = inst->GetAddress();
5005262182Semaste                        BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (addr,     // lldb_private::Address
5006262182Semaste                                                                                      false,    // internal
5007262182Semaste                                                                                      false);   // request_hardware
5008262182Semaste                        // Make breakpoint one shot
5009262182Semaste                        bp_sp->GetOptions()->SetOneShot(true);
5010262182Semaste                        exe_ctx.GetProcessRef().Resume();
5011262182Semaste                    }
5012262182Semaste                }
5013262182Semaste                return eKeyHandled;
5014262182Semaste
5015262182Semaste            case 'b':   // 'b' == toggle breakpoint on currently selected line
5016262182Semaste                if (m_selected_line < GetNumSourceLines())
5017262182Semaste                {
5018262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5019262182Semaste                    if (exe_ctx.HasTargetScope())
5020262182Semaste                    {
5021262182Semaste                        BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (NULL,                      // Don't limit the breakpoint to certain modules
5022262182Semaste                                                                                      m_file_sp->GetFileSpec(),  // Source file
5023262182Semaste                                                                                      m_selected_line + 1,       // Source line number (m_selected_line is zero based)
5024262182Semaste                                                                                      eLazyBoolCalculate,        // Check inlines using global setting
5025262182Semaste                                                                                      eLazyBoolCalculate,        // Skip prologue using global setting,
5026262182Semaste                                                                                      false,                     // internal
5027262182Semaste                                                                                      false);                    // request_hardware
5028262182Semaste                    }
5029262182Semaste                }
5030262182Semaste                else if (m_selected_line < GetNumDisassemblyLines())
5031262182Semaste                {
5032262182Semaste                    const Instruction *inst = m_disassembly_sp->GetInstructionList().GetInstructionAtIndex(m_selected_line).get();
5033262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5034262182Semaste                    if (exe_ctx.HasTargetScope())
5035262182Semaste                    {
5036262182Semaste                        Address addr = inst->GetAddress();
5037262182Semaste                        BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (addr,     // lldb_private::Address
5038262182Semaste                                                                                      false,    // internal
5039262182Semaste                                                                                      false);   // request_hardware
5040262182Semaste                    }
5041262182Semaste                }
5042262182Semaste                return eKeyHandled;
5043262182Semaste
5044262182Semaste            case 'd':   // 'd' == detach and let run
5045262182Semaste            case 'D':   // 'D' == detach and keep stopped
5046262182Semaste                {
5047262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5048262182Semaste                    if (exe_ctx.HasProcessScope())
5049262182Semaste                        exe_ctx.GetProcessRef().Detach(c == 'D');
5050262182Semaste                }
5051262182Semaste                return eKeyHandled;
5052262182Semaste
5053262182Semaste            case 'k':
5054262182Semaste                // 'k' == kill
5055262182Semaste                {
5056262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5057262182Semaste                    if (exe_ctx.HasProcessScope())
5058262182Semaste                        exe_ctx.GetProcessRef().Destroy();
5059262182Semaste                }
5060262182Semaste                return eKeyHandled;
5061262182Semaste
5062262182Semaste            case 'c':
5063262182Semaste                // 'c' == continue
5064262182Semaste                {
5065262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5066262182Semaste                    if (exe_ctx.HasProcessScope())
5067262182Semaste                        exe_ctx.GetProcessRef().Resume();
5068262182Semaste                }
5069262182Semaste                return eKeyHandled;
5070262182Semaste
5071262182Semaste            case 'o':
5072262182Semaste                // 'o' == step out
5073262182Semaste                {
5074262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5075262182Semaste                    if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
5076262182Semaste                    {
5077262182Semaste                        exe_ctx.GetThreadRef().StepOut();
5078262182Semaste                    }
5079262182Semaste                }
5080262182Semaste                return eKeyHandled;
5081262182Semaste            case 'n':   // 'n' == step over
5082262182Semaste            case 'N':   // 'N' == step over instruction
5083262182Semaste                {
5084262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5085262182Semaste                    if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
5086262182Semaste                    {
5087262182Semaste                        bool source_step = (c == 'n');
5088262182Semaste                        exe_ctx.GetThreadRef().StepOver(source_step);
5089262182Semaste                    }
5090262182Semaste                }
5091262182Semaste                return eKeyHandled;
5092262182Semaste            case 's':   // 's' == step into
5093262182Semaste            case 'S':   // 'S' == step into instruction
5094262182Semaste                {
5095262182Semaste                    ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5096262182Semaste                    if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
5097262182Semaste                    {
5098262182Semaste                        bool source_step = (c == 's');
5099262182Semaste                        bool avoid_code_without_debug_info = true;
5100262182Semaste                        exe_ctx.GetThreadRef().StepIn(source_step, avoid_code_without_debug_info);
5101262182Semaste                    }
5102262182Semaste                }
5103262182Semaste                return eKeyHandled;
5104262182Semaste
5105262182Semaste            case 'h':
5106262182Semaste                window.CreateHelpSubwindow ();
5107262182Semaste                return eKeyHandled;
5108262182Semaste
5109262182Semaste            default:
5110262182Semaste                break;
5111262182Semaste        }
5112262182Semaste        return eKeyNotHandled;
5113262182Semaste    }
5114262182Semaste
5115262182Semasteprotected:
5116262182Semaste    typedef std::set<uint32_t> BreakpointLines;
5117262182Semaste    typedef std::set<lldb::addr_t> BreakpointAddrs;
5118262182Semaste
5119262182Semaste    Debugger &m_debugger;
5120262182Semaste    SymbolContext m_sc;
5121262182Semaste    SourceManager::FileSP m_file_sp;
5122262182Semaste    SymbolContextScope *m_disassembly_scope;
5123262182Semaste    lldb::DisassemblerSP m_disassembly_sp;
5124262182Semaste    AddressRange m_disassembly_range;
5125262182Semaste    lldb::user_id_t m_tid;
5126262182Semaste    char m_line_format[8];
5127262182Semaste    int m_line_width;
5128262182Semaste    uint32_t m_selected_line;       // The selected line
5129262182Semaste    uint32_t m_pc_line;             // The line with the PC
5130262182Semaste    uint32_t m_stop_id;
5131262182Semaste    uint32_t m_frame_idx;
5132262182Semaste    int m_first_visible_line;
5133262182Semaste    int m_min_x;
5134262182Semaste    int m_min_y;
5135262182Semaste    int m_max_x;
5136262182Semaste    int m_max_y;
5137262182Semaste
5138262182Semaste};
5139262182Semaste
5140262182SemasteDisplayOptions ValueObjectListDelegate::g_options = { true };
5141262182Semaste
5142262182SemasteIOHandlerCursesGUI::IOHandlerCursesGUI (Debugger &debugger) :
5143262182Semaste    IOHandler (debugger)
5144262182Semaste{
5145262182Semaste}
5146262182Semaste
5147262182Semastevoid
5148262182SemasteIOHandlerCursesGUI::Activate ()
5149262182Semaste{
5150262182Semaste    IOHandler::Activate();
5151262182Semaste    if (!m_app_ap)
5152262182Semaste    {
5153262182Semaste        m_app_ap.reset (new Application (GetInputFILE(), GetOutputFILE()));
5154262182Semaste
5155262182Semaste
5156262182Semaste        // This is both a window and a menu delegate
5157262182Semaste        std::shared_ptr<ApplicationDelegate> app_delegate_sp(new ApplicationDelegate(*m_app_ap, m_debugger));
5158262182Semaste
5159262182Semaste        MenuDelegateSP app_menu_delegate_sp = std::static_pointer_cast<MenuDelegate>(app_delegate_sp);
5160262182Semaste        MenuSP lldb_menu_sp(new Menu("LLDB" , "F1", KEY_F(1), ApplicationDelegate::eMenuID_LLDB));
5161262182Semaste        MenuSP exit_menuitem_sp(new Menu("Exit", NULL, 'x', ApplicationDelegate::eMenuID_LLDBExit));
5162262182Semaste        exit_menuitem_sp->SetCannedResult(MenuActionResult::Quit);
5163262182Semaste        lldb_menu_sp->AddSubmenu (MenuSP (new Menu("About LLDB", NULL, 'a', ApplicationDelegate::eMenuID_LLDBAbout)));
5164262182Semaste        lldb_menu_sp->AddSubmenu (MenuSP (new Menu(Menu::Type::Separator)));
5165262182Semaste        lldb_menu_sp->AddSubmenu (exit_menuitem_sp);
5166262182Semaste
5167262182Semaste        MenuSP target_menu_sp(new Menu("Target" ,"F2", KEY_F(2), ApplicationDelegate::eMenuID_Target));
5168262182Semaste        target_menu_sp->AddSubmenu (MenuSP (new Menu("Create", NULL, 'c', ApplicationDelegate::eMenuID_TargetCreate)));
5169262182Semaste        target_menu_sp->AddSubmenu (MenuSP (new Menu("Delete", NULL, 'd', ApplicationDelegate::eMenuID_TargetDelete)));
5170262182Semaste
5171262182Semaste        MenuSP process_menu_sp(new Menu("Process", "F3", KEY_F(3), ApplicationDelegate::eMenuID_Process));
5172262182Semaste        process_menu_sp->AddSubmenu (MenuSP (new Menu("Attach"  , NULL, 'a', ApplicationDelegate::eMenuID_ProcessAttach)));
5173262182Semaste        process_menu_sp->AddSubmenu (MenuSP (new Menu("Detach"  , NULL, 'd', ApplicationDelegate::eMenuID_ProcessDetach)));
5174262182Semaste        process_menu_sp->AddSubmenu (MenuSP (new Menu("Launch"  , NULL, 'l', ApplicationDelegate::eMenuID_ProcessLaunch)));
5175262182Semaste        process_menu_sp->AddSubmenu (MenuSP (new Menu(Menu::Type::Separator)));
5176262182Semaste        process_menu_sp->AddSubmenu (MenuSP (new Menu("Continue", NULL, 'c', ApplicationDelegate::eMenuID_ProcessContinue)));
5177262182Semaste        process_menu_sp->AddSubmenu (MenuSP (new Menu("Halt"    , NULL, 'h', ApplicationDelegate::eMenuID_ProcessHalt)));
5178262182Semaste        process_menu_sp->AddSubmenu (MenuSP (new Menu("Kill"    , NULL, 'k', ApplicationDelegate::eMenuID_ProcessKill)));
5179262182Semaste
5180262182Semaste        MenuSP thread_menu_sp(new Menu("Thread", "F4", KEY_F(4), ApplicationDelegate::eMenuID_Thread));
5181262182Semaste        thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step In"  , NULL, 'i', ApplicationDelegate::eMenuID_ThreadStepIn)));
5182262182Semaste        thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step Over", NULL, 'v', ApplicationDelegate::eMenuID_ThreadStepOver)));
5183262182Semaste        thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step Out" , NULL, 'o', ApplicationDelegate::eMenuID_ThreadStepOut)));
5184262182Semaste
5185262182Semaste        MenuSP view_menu_sp(new Menu("View", "F5", KEY_F(5), ApplicationDelegate::eMenuID_View));
5186262182Semaste        view_menu_sp->AddSubmenu (MenuSP (new Menu("Backtrace", NULL, 'b', ApplicationDelegate::eMenuID_ViewBacktrace)));
5187262182Semaste        view_menu_sp->AddSubmenu (MenuSP (new Menu("Registers", NULL, 'r', ApplicationDelegate::eMenuID_ViewRegisters)));
5188262182Semaste        view_menu_sp->AddSubmenu (MenuSP (new Menu("Source"   , NULL, 's', ApplicationDelegate::eMenuID_ViewSource)));
5189262182Semaste        view_menu_sp->AddSubmenu (MenuSP (new Menu("Variables", NULL, 'v', ApplicationDelegate::eMenuID_ViewVariables)));
5190262182Semaste
5191262182Semaste        MenuSP help_menu_sp(new Menu("Help", "F6", KEY_F(6), ApplicationDelegate::eMenuID_Help));
5192262182Semaste        help_menu_sp->AddSubmenu (MenuSP (new Menu("GUI Help", NULL, 'g', ApplicationDelegate::eMenuID_HelpGUIHelp)));
5193262182Semaste
5194262182Semaste        m_app_ap->Initialize();
5195262182Semaste        WindowSP &main_window_sp = m_app_ap->GetMainWindow();
5196262182Semaste
5197262182Semaste        MenuSP menubar_sp(new Menu(Menu::Type::Bar));
5198262182Semaste        menubar_sp->AddSubmenu (lldb_menu_sp);
5199262182Semaste        menubar_sp->AddSubmenu (target_menu_sp);
5200262182Semaste        menubar_sp->AddSubmenu (process_menu_sp);
5201262182Semaste        menubar_sp->AddSubmenu (thread_menu_sp);
5202262182Semaste        menubar_sp->AddSubmenu (view_menu_sp);
5203262182Semaste        menubar_sp->AddSubmenu (help_menu_sp);
5204262182Semaste        menubar_sp->SetDelegate(app_menu_delegate_sp);
5205262182Semaste
5206262182Semaste        Rect content_bounds = main_window_sp->GetFrame();
5207262182Semaste        Rect menubar_bounds = content_bounds.MakeMenuBar();
5208262182Semaste        Rect status_bounds = content_bounds.MakeStatusBar();
5209262182Semaste        Rect source_bounds;
5210262182Semaste        Rect variables_bounds;
5211262182Semaste        Rect threads_bounds;
5212262182Semaste        Rect source_variables_bounds;
5213262182Semaste        content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds, threads_bounds);
5214262182Semaste        source_variables_bounds.HorizontalSplitPercentage(0.70, source_bounds, variables_bounds);
5215262182Semaste
5216262182Semaste        WindowSP menubar_window_sp = main_window_sp->CreateSubWindow("Menubar", menubar_bounds, false);
5217262182Semaste        // Let the menubar get keys if the active window doesn't handle the
5218262182Semaste        // keys that are typed so it can respond to menubar key presses.
5219262182Semaste        menubar_window_sp->SetCanBeActive(false); // Don't let the menubar become the active window
5220262182Semaste        menubar_window_sp->SetDelegate(menubar_sp);
5221262182Semaste
5222262182Semaste        WindowSP source_window_sp (main_window_sp->CreateSubWindow("Source",
5223262182Semaste                                                                   source_bounds,
5224262182Semaste                                                                   true));
5225262182Semaste        WindowSP variables_window_sp (main_window_sp->CreateSubWindow("Variables",
5226262182Semaste                                                                      variables_bounds,
5227262182Semaste                                                                      false));
5228262182Semaste        WindowSP threads_window_sp (main_window_sp->CreateSubWindow("Threads",
5229262182Semaste                                                                      threads_bounds,
5230262182Semaste                                                                      false));
5231262182Semaste        WindowSP status_window_sp (main_window_sp->CreateSubWindow("Status",
5232262182Semaste                                                                   status_bounds,
5233262182Semaste                                                                   false));
5234262182Semaste        status_window_sp->SetCanBeActive(false); // Don't let the status bar become the active window
5235262182Semaste        main_window_sp->SetDelegate (std::static_pointer_cast<WindowDelegate>(app_delegate_sp));
5236262182Semaste        source_window_sp->SetDelegate (WindowDelegateSP(new SourceFileWindowDelegate(m_debugger)));
5237262182Semaste        variables_window_sp->SetDelegate (WindowDelegateSP(new FrameVariablesWindowDelegate(m_debugger)));
5238262182Semaste        TreeDelegateSP thread_delegate_sp (new ThreadTreeDelegate(m_debugger));
5239262182Semaste        threads_window_sp->SetDelegate (WindowDelegateSP(new TreeWindowDelegate(m_debugger, thread_delegate_sp)));
5240262182Semaste        status_window_sp->SetDelegate (WindowDelegateSP(new StatusBarWindowDelegate(m_debugger)));
5241262182Semaste
5242262182Semaste        // Show the main help window once the first time the curses GUI is launched
5243262182Semaste        static bool g_showed_help = false;
5244262182Semaste        if (!g_showed_help)
5245262182Semaste        {
5246262182Semaste            g_showed_help = true;
5247262182Semaste            main_window_sp->CreateHelpSubwindow();
5248262182Semaste        }
5249262182Semaste
5250262182Semaste        init_pair (1, COLOR_WHITE   , COLOR_BLUE  );
5251262182Semaste        init_pair (2, COLOR_BLACK   , COLOR_WHITE );
5252262182Semaste        init_pair (3, COLOR_MAGENTA , COLOR_WHITE );
5253262182Semaste        init_pair (4, COLOR_MAGENTA , COLOR_BLACK );
5254262182Semaste        init_pair (5, COLOR_RED     , COLOR_BLACK );
5255262182Semaste
5256262182Semaste    }
5257262182Semaste}
5258262182Semaste
5259262182Semastevoid
5260262182SemasteIOHandlerCursesGUI::Deactivate ()
5261262182Semaste{
5262262182Semaste    m_app_ap->Terminate();
5263262182Semaste}
5264262182Semaste
5265262182Semastevoid
5266262182SemasteIOHandlerCursesGUI::Run ()
5267262182Semaste{
5268262182Semaste    m_app_ap->Run(m_debugger);
5269262182Semaste    SetIsDone(true);
5270262182Semaste}
5271262182Semaste
5272262182Semaste
5273262182SemasteIOHandlerCursesGUI::~IOHandlerCursesGUI ()
5274262182Semaste{
5275262182Semaste
5276262182Semaste}
5277262182Semaste
5278262182Semastevoid
5279262182SemasteIOHandlerCursesGUI::Hide ()
5280262182Semaste{
5281262182Semaste}
5282262182Semaste
5283262182Semaste
5284262182Semastevoid
5285262182SemasteIOHandlerCursesGUI::Refresh ()
5286262182Semaste{
5287262182Semaste}
5288262182Semaste
5289262500Semastevoid
5290262500SemasteIOHandlerCursesGUI::Cancel ()
5291262500Semaste{
5292262500Semaste}
5293262182Semaste
5294262182Semastevoid
5295262182SemasteIOHandlerCursesGUI::Interrupt ()
5296262182Semaste{
5297262182Semaste}
5298262182Semaste
5299262182Semaste
5300262182Semastevoid
5301262182SemasteIOHandlerCursesGUI::GotEOF()
5302262182Semaste{
5303262182Semaste}
5304262182Semaste
5305262182Semaste#endif // #ifndef LLDB_DISABLE_CURSES