]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/llvm/tools/lldb/source/Core/IOHandler.cpp
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / llvm / tools / lldb / source / Core / IOHandler.cpp
1 //===-- IOHandler.cpp -------------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10
11 #include "lldb/lldb-python.h"
12
13 #include <string>
14
15 #include "lldb/Breakpoint/BreakpointLocation.h"
16 #include "lldb/Core/IOHandler.h"
17 #include "lldb/Core/Debugger.h"
18 #include "lldb/Core/State.h"
19 #include "lldb/Core/StreamFile.h"
20 #include "lldb/Core/ValueObjectRegister.h"
21 #include "lldb/Host/Editline.h"
22 #include "lldb/Interpreter/CommandCompletions.h"
23 #include "lldb/Interpreter/CommandInterpreter.h"
24 #include "lldb/Symbol/Block.h"
25 #include "lldb/Symbol/Function.h"
26 #include "lldb/Symbol/Symbol.h"
27 #include "lldb/Target/RegisterContext.h"
28 #include "lldb/Target/ThreadPlan.h"
29
30 #ifndef LLDB_DISABLE_CURSES
31 #include <ncurses.h>
32 #include <panel.h>
33 #endif
34
35 using namespace lldb;
36 using namespace lldb_private;
37
38 IOHandler::IOHandler (Debugger &debugger) :
39     IOHandler (debugger,
40                StreamFileSP(),  // Adopt STDIN from top input reader
41                StreamFileSP(),  // Adopt STDOUT from top input reader
42                StreamFileSP(),  // Adopt STDERR from top input reader
43                0)               // Flags
44 {
45 }
46
47
48 IOHandler::IOHandler (Debugger &debugger,
49                       const lldb::StreamFileSP &input_sp,
50                       const lldb::StreamFileSP &output_sp,
51                       const lldb::StreamFileSP &error_sp,
52                       uint32_t flags) :
53     m_debugger (debugger),
54     m_input_sp (input_sp),
55     m_output_sp (output_sp),
56     m_error_sp (error_sp),
57     m_flags (flags),
58     m_user_data (NULL),
59     m_done (false),
60     m_active (false)
61 {
62     // If any files are not specified, then adopt them from the top input reader.
63     if (!m_input_sp || !m_output_sp || !m_error_sp)
64         debugger.AdoptTopIOHandlerFilesIfInvalid (m_input_sp,
65                                                   m_output_sp,
66                                                   m_error_sp);
67 }
68
69 IOHandler::~IOHandler()
70 {
71 }
72
73
74 int
75 IOHandler::GetInputFD()
76 {
77     if (m_input_sp)
78         return m_input_sp->GetFile().GetDescriptor();
79     return -1;
80 }
81
82 int
83 IOHandler::GetOutputFD()
84 {
85     if (m_output_sp)
86         return m_output_sp->GetFile().GetDescriptor();
87     return -1;
88 }
89
90 int
91 IOHandler::GetErrorFD()
92 {
93     if (m_error_sp)
94         return m_error_sp->GetFile().GetDescriptor();
95     return -1;
96 }
97
98 FILE *
99 IOHandler::GetInputFILE()
100 {
101     if (m_input_sp)
102         return m_input_sp->GetFile().GetStream();
103     return NULL;
104 }
105
106 FILE *
107 IOHandler::GetOutputFILE()
108 {
109     if (m_output_sp)
110         return m_output_sp->GetFile().GetStream();
111     return NULL;
112 }
113
114 FILE *
115 IOHandler::GetErrorFILE()
116 {
117     if (m_error_sp)
118         return m_error_sp->GetFile().GetStream();
119     return NULL;
120 }
121
122 StreamFileSP &
123 IOHandler::GetInputStreamFile()
124 {
125     return m_input_sp;
126 }
127
128 StreamFileSP &
129 IOHandler::GetOutputStreamFile()
130 {
131     return m_output_sp;
132 }
133
134
135 StreamFileSP &
136 IOHandler::GetErrorStreamFile()
137 {
138     return m_error_sp;
139 }
140
141 bool
142 IOHandler::GetIsInteractive ()
143 {
144     return GetInputStreamFile()->GetFile().GetIsInteractive ();
145 }
146
147 bool
148 IOHandler::GetIsRealTerminal ()
149 {
150     return GetInputStreamFile()->GetFile().GetIsRealTerminal();
151 }
152
153 IOHandlerConfirm::IOHandlerConfirm (Debugger &debugger,
154                                     const char *prompt,
155                                     bool default_response) :
156     IOHandlerEditline(debugger,
157                       NULL,     // NULL editline_name means no history loaded/saved
158                       NULL,
159                       false,    // Multi-line
160                       *this),
161     m_default_response (default_response),
162     m_user_response (default_response)
163 {
164     StreamString prompt_stream;
165     prompt_stream.PutCString(prompt);
166     if (m_default_response)
167         prompt_stream.Printf(": [Y/n] ");
168     else
169         prompt_stream.Printf(": [y/N] ");
170     
171     SetPrompt (prompt_stream.GetString().c_str());
172     
173 }
174
175
176 IOHandlerConfirm::~IOHandlerConfirm ()
177 {
178 }
179
180 int
181 IOHandlerConfirm::IOHandlerComplete (IOHandler &io_handler,
182                                      const char *current_line,
183                                      const char *cursor,
184                                      const char *last_char,
185                                      int skip_first_n_matches,
186                                      int max_matches,
187                                      StringList &matches)
188 {
189     if (current_line == cursor)
190     {
191         if (m_default_response)
192         {
193             matches.AppendString("y");
194         }
195         else
196         {
197             matches.AppendString("n");
198         }
199     }
200     return matches.GetSize();
201 }
202
203 void
204 IOHandlerConfirm::IOHandlerInputComplete (IOHandler &io_handler, std::string &line)
205 {
206     if (line.empty())
207     {
208         // User just hit enter, set the response to the default
209         m_user_response = m_default_response;
210         io_handler.SetIsDone(true);
211         return;
212     }
213
214     if (line.size() == 1)
215     {
216         switch (line[0])
217         {
218             case 'y':
219             case 'Y':
220                 m_user_response = true;
221                 io_handler.SetIsDone(true);
222                 return;
223             case 'n':
224             case 'N':
225                 m_user_response = false;
226                 io_handler.SetIsDone(true);
227                 return;
228             default:
229                 break;
230         }
231     }
232
233     if (line == "yes" || line == "YES" || line == "Yes")
234     {
235         m_user_response = true;
236         io_handler.SetIsDone(true);
237     }
238     else if (line == "no" || line == "NO" || line == "No")
239     {
240         m_user_response = false;
241         io_handler.SetIsDone(true);
242     }
243 }
244
245 int
246 IOHandlerDelegate::IOHandlerComplete (IOHandler &io_handler,
247                                       const char *current_line,
248                                       const char *cursor,
249                                       const char *last_char,
250                                       int skip_first_n_matches,
251                                       int max_matches,
252                                       StringList &matches)
253 {
254     switch (m_completion)
255     {
256     case Completion::None:
257         break;
258
259     case Completion::LLDBCommand:
260         return io_handler.GetDebugger().GetCommandInterpreter().HandleCompletion (current_line,
261                                                                                   cursor,
262                                                                                   last_char,
263                                                                                   skip_first_n_matches,
264                                                                                   max_matches,
265                                                                                   matches);
266
267     case Completion::Expression:
268         {
269             bool word_complete = false;
270             const char *word_start = cursor;
271             if (cursor > current_line)
272                 --word_start;
273             while (word_start > current_line && !isspace(*word_start))
274                 --word_start;
275             CommandCompletions::InvokeCommonCompletionCallbacks (io_handler.GetDebugger().GetCommandInterpreter(),
276                                                                  CommandCompletions::eVariablePathCompletion,
277                                                                  word_start,
278                                                                  skip_first_n_matches,
279                                                                  max_matches,
280                                                                  NULL,
281                                                                  word_complete,
282                                                                  matches);
283             
284             size_t num_matches = matches.GetSize();
285             if (num_matches > 0)
286             {
287                 std::string common_prefix;
288                 matches.LongestCommonPrefix (common_prefix);
289                 const size_t partial_name_len = strlen(word_start);
290                 
291                 // If we matched a unique single command, add a space...
292                 // Only do this if the completer told us this was a complete word, however...
293                 if (num_matches == 1 && word_complete)
294                 {
295                     common_prefix.push_back(' ');
296                 }
297                 common_prefix.erase (0, partial_name_len);
298                 matches.InsertStringAtIndex(0, std::move(common_prefix));
299             }
300             return num_matches;
301         }
302         break;
303     }
304     
305     
306     return 0;
307 }
308
309
310 IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
311                                       const char *editline_name, // Used for saving history files
312                                       const char *prompt,
313                                       bool multi_line,
314                                       IOHandlerDelegate &delegate) :
315     IOHandlerEditline(debugger,
316                       StreamFileSP(), // Inherit input from top input reader
317                       StreamFileSP(), // Inherit output from top input reader
318                       StreamFileSP(), // Inherit error from top input reader
319                       0,              // Flags
320                       editline_name,  // Used for saving history files
321                       prompt,
322                       multi_line,
323                       delegate)
324 {
325 }
326
327 IOHandlerEditline::IOHandlerEditline (Debugger &debugger,
328                                       const lldb::StreamFileSP &input_sp,
329                                       const lldb::StreamFileSP &output_sp,
330                                       const lldb::StreamFileSP &error_sp,
331                                       uint32_t flags,
332                                       const char *editline_name, // Used for saving history files
333                                       const char *prompt,
334                                       bool multi_line,
335                                       IOHandlerDelegate &delegate) :
336     IOHandler (debugger, input_sp, output_sp, error_sp, flags),
337     m_editline_ap (),
338     m_delegate (delegate),
339     m_prompt (),
340     m_multi_line (multi_line)
341 {
342     SetPrompt(prompt);
343
344     bool use_editline = false;
345     
346 #ifndef _MSC_VER
347     use_editline = m_input_sp->GetFile().GetIsRealTerminal();
348 #else
349     use_editline = true;
350 #endif
351
352     if (use_editline)
353     {
354         m_editline_ap.reset(new Editline (editline_name,
355                                           prompt ? prompt : "",
356                                           GetInputFILE (),
357                                           GetOutputFILE (),
358                                           GetErrorFILE ()));
359         m_editline_ap->SetLineCompleteCallback (LineCompletedCallback, this);
360         m_editline_ap->SetAutoCompleteCallback (AutoCompleteCallback, this);
361     }
362     
363 }
364
365 IOHandlerEditline::~IOHandlerEditline ()
366 {
367     m_editline_ap.reset();
368 }
369
370
371 bool
372 IOHandlerEditline::GetLine (std::string &line)
373 {
374     if (m_editline_ap)
375     {
376         return m_editline_ap->GetLine(line).Success();
377     }
378     else
379     {
380         line.clear();
381
382         FILE *in = GetInputFILE();
383         if (in)
384         {
385             if (GetIsInteractive())
386             {
387                 const char *prompt = GetPrompt();
388                 if (prompt && prompt[0])
389                 {
390                     FILE *out = GetOutputFILE();
391                     if (out)
392                     {
393                         ::fprintf(out, "%s", prompt);
394                         ::fflush(out);
395                     }
396                 }
397             }
398             char buffer[256];
399             bool done = false;
400             bool got_line = false;
401             while (!done)
402             {
403                 if (fgets(buffer, sizeof(buffer), in) == NULL)
404                     done = true;
405                 else
406                 {
407                     got_line = true;
408                     size_t buffer_len = strlen(buffer);
409                     assert (buffer[buffer_len] == '\0');
410                     char last_char = buffer[buffer_len-1];
411                     if (last_char == '\r' || last_char == '\n')
412                     {
413                         done = true;
414                         // Strip trailing newlines
415                         while (last_char == '\r' || last_char == '\n')
416                         {
417                             --buffer_len;
418                             if (buffer_len == 0)
419                                 break;
420                             last_char = buffer[buffer_len-1];
421                         }
422                     }
423                     line.append(buffer, buffer_len);
424                 }
425             }
426             // We might have gotten a newline on a line by itself
427             // make sure to return true in this case.
428             return got_line;
429         }
430         else
431         {
432             // No more input file, we are done...
433             SetIsDone(true);
434         }
435         return false;
436     }
437 }
438
439
440 LineStatus
441 IOHandlerEditline::LineCompletedCallback (Editline *editline,
442                                           StringList &lines,
443                                           uint32_t line_idx,
444                                           Error &error,
445                                           void *baton)
446 {
447     IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
448     return editline_reader->m_delegate.IOHandlerLinesUpdated(*editline_reader, lines, line_idx, error);
449 }
450
451 int
452 IOHandlerEditline::AutoCompleteCallback (const char *current_line,
453                                          const char *cursor,
454                                          const char *last_char,
455                                          int skip_first_n_matches,
456                                          int max_matches,
457                                          StringList &matches,
458                                          void *baton)
459 {
460     IOHandlerEditline *editline_reader = (IOHandlerEditline *) baton;
461     if (editline_reader)
462         return editline_reader->m_delegate.IOHandlerComplete (*editline_reader,
463                                                               current_line,
464                                                               cursor,
465                                                               last_char,
466                                                               skip_first_n_matches,
467                                                               max_matches,
468                                                               matches);
469     return 0;
470 }
471
472 const char *
473 IOHandlerEditline::GetPrompt ()
474 {
475     if (m_editline_ap)
476         return m_editline_ap->GetPrompt ();
477     else if (m_prompt.empty())
478         return NULL;
479     return m_prompt.c_str();
480 }
481
482 bool
483 IOHandlerEditline::SetPrompt (const char *p)
484 {
485     if (p && p[0])
486         m_prompt = p;
487     else
488         m_prompt.clear();
489     if (m_editline_ap)
490         m_editline_ap->SetPrompt (m_prompt.empty() ? NULL : m_prompt.c_str());
491     return true;
492 }
493
494 bool
495 IOHandlerEditline::GetLines (StringList &lines)
496 {
497     bool success = false;
498     if (m_editline_ap)
499     {
500         std::string end_token;
501         success = m_editline_ap->GetLines(end_token, lines).Success();
502     }
503     else
504     {
505         LineStatus lines_status = LineStatus::Success;
506
507         while (lines_status == LineStatus::Success)
508         {
509             std::string line;
510             if (GetLine(line))
511             {
512                 lines.AppendString(line);
513                 Error error;
514                 lines_status = m_delegate.IOHandlerLinesUpdated(*this, lines, lines.GetSize() - 1, error);
515             }
516             else
517             {
518                 lines_status = LineStatus::Done;
519             }
520         }
521         success = lines.GetSize() > 0;
522     }
523     return success;
524 }
525
526 // Each IOHandler gets to run until it is done. It should read data
527 // from the "in" and place output into "out" and "err and return
528 // when done.
529 void
530 IOHandlerEditline::Run ()
531 {
532     std::string line;
533     while (IsActive())
534     {
535         if (m_multi_line)
536         {
537             StringList lines;
538             if (GetLines (lines))
539             {
540                 line = lines.CopyList();
541                 m_delegate.IOHandlerInputComplete(*this, line);
542             }
543             else
544             {
545                 m_done = true;
546             }
547         }
548         else
549         {
550             if (GetLine(line))
551             {
552                 m_delegate.IOHandlerInputComplete(*this, line);
553             }
554             else
555             {
556                 m_done = true;
557             }
558         }
559     }
560 }
561
562 void
563 IOHandlerEditline::Hide ()
564 {
565     if (m_editline_ap && m_editline_ap->GettingLine())
566         m_editline_ap->Hide();
567 }
568
569
570 void
571 IOHandlerEditline::Refresh ()
572 {
573     if (m_editline_ap && m_editline_ap->GettingLine())
574         m_editline_ap->Refresh();
575     else
576     {
577         const char *prompt = GetPrompt();
578         if (prompt && prompt[0])
579         {
580             FILE *out = GetOutputFILE();
581             if (out)
582             {
583                 ::fprintf(out, "%s", prompt);
584                 ::fflush(out);
585             }
586         }
587     }
588 }
589
590 void
591 IOHandlerEditline::Cancel ()
592 {
593     if (m_editline_ap)
594         m_editline_ap->Interrupt ();
595 }
596
597 void
598 IOHandlerEditline::Interrupt ()
599 {
600     if (m_editline_ap)
601         m_editline_ap->Interrupt();
602 }
603
604 void
605 IOHandlerEditline::GotEOF()
606 {
607     if (m_editline_ap)
608         m_editline_ap->Interrupt();
609 }
610
611 // we may want curses to be disabled for some builds
612 // for instance, windows
613 #ifndef LLDB_DISABLE_CURSES
614
615 #include "lldb/Core/ValueObject.h"
616 #include "lldb/Symbol/VariableList.h"
617 #include "lldb/Target/Target.h"
618 #include "lldb/Target/Process.h"
619 #include "lldb/Target/Thread.h"
620 #include "lldb/Target/StackFrame.h"
621
622 #define KEY_RETURN   10
623 #define KEY_ESCAPE  27
624
625 namespace curses
626 {
627     class Menu;
628     class MenuDelegate;
629     class Window;
630     class WindowDelegate;
631     typedef std::shared_ptr<Menu> MenuSP;
632     typedef std::shared_ptr<MenuDelegate> MenuDelegateSP;
633     typedef std::shared_ptr<Window> WindowSP;
634     typedef std::shared_ptr<WindowDelegate> WindowDelegateSP;
635     typedef std::vector<MenuSP> Menus;
636     typedef std::vector<WindowSP> Windows;
637     typedef std::vector<WindowDelegateSP> WindowDelegates;
638
639 #if 0
640 type summary add -s "x=${var.x}, y=${var.y}" curses::Point
641 type summary add -s "w=${var.width}, h=${var.height}" curses::Size
642 type summary add -s "${var.origin%S} ${var.size%S}" curses::Rect
643 #endif
644     struct Point
645     {
646         int x;
647         int y;
648         
649         Point (int _x = 0, int _y = 0) :
650             x(_x),
651             y(_y)
652         {
653         }
654
655         void
656         Clear ()
657         {
658             x = 0;
659             y = 0;
660         }
661         
662         Point &
663         operator += (const Point &rhs)
664         {
665             x += rhs.x;
666             y += rhs.y;
667             return *this;
668         }
669         
670         void
671         Dump ()
672         {
673             printf ("(x=%i, y=%i)\n", x, y);
674         }
675
676     };
677     
678     bool operator == (const Point &lhs, const Point &rhs)
679     {
680         return lhs.x == rhs.x && lhs.y == rhs.y;
681     }
682     bool operator != (const Point &lhs, const Point &rhs)
683     {
684         return lhs.x != rhs.x || lhs.y != rhs.y;
685     }
686
687     struct Size
688     {
689         int width;
690         int height;
691         Size (int w = 0, int h = 0) :
692             width (w),
693             height (h)
694         {
695         }
696         
697         void
698         Clear ()
699         {
700             width = 0;
701             height = 0;
702         }
703
704         void
705         Dump ()
706         {
707             printf ("(w=%i, h=%i)\n", width, height);
708         }
709
710     };
711     
712     bool operator == (const Size &lhs, const Size &rhs)
713     {
714         return lhs.width == rhs.width && lhs.height == rhs.height;
715     }
716     bool operator != (const Size &lhs, const Size &rhs)
717     {
718         return lhs.width != rhs.width || lhs.height != rhs.height;
719     }
720
721     struct Rect
722     {
723         Point origin;
724         Size size;
725         
726         Rect () :
727             origin(),
728             size()
729         {
730         }
731     
732         Rect (const Point &p, const Size &s) :
733             origin (p),
734             size (s)
735         {
736         }
737         
738         void
739         Clear ()
740         {
741             origin.Clear();
742             size.Clear();
743         }
744         
745         void
746         Dump ()
747         {
748             printf ("(x=%i, y=%i), w=%i, h=%i)\n", origin.x, origin.y, size.width, size.height);
749         }
750         
751         void
752         Inset (int w, int h)
753         {
754             if (size.width > w*2)
755                 size.width -= w*2;
756             origin.x += w;
757
758             if (size.height > h*2)
759                 size.height -= h*2;
760             origin.y += h;
761         }
762         // Return a status bar rectangle which is the last line of
763         // this rectangle. This rectangle will be modified to not
764         // include the status bar area.
765         Rect
766         MakeStatusBar ()
767         {
768             Rect status_bar;
769             if (size.height > 1)
770             {
771                 status_bar.origin.x = origin.x;
772                 status_bar.origin.y = size.height;
773                 status_bar.size.width = size.width;
774                 status_bar.size.height = 1;
775                 --size.height;
776             }
777             return status_bar;
778         }
779
780         // Return a menubar rectangle which is the first line of
781         // this rectangle. This rectangle will be modified to not
782         // include the menubar area.
783         Rect
784         MakeMenuBar ()
785         {
786             Rect menubar;
787             if (size.height > 1)
788             {
789                 menubar.origin.x = origin.x;
790                 menubar.origin.y = origin.y;
791                 menubar.size.width = size.width;
792                 menubar.size.height = 1;
793                 ++origin.y;
794                 --size.height;
795             }
796             return menubar;
797         }
798
799         void
800         HorizontalSplitPercentage (float top_percentage, Rect &top, Rect &bottom) const
801         {
802             float top_height = top_percentage * size.height;
803             HorizontalSplit (top_height, top, bottom);
804         }
805
806         void
807         HorizontalSplit (int top_height, Rect &top, Rect &bottom) const
808         {
809             top = *this;
810             if (top_height < size.height)
811             {
812                 top.size.height = top_height;
813                 bottom.origin.x = origin.x;
814                 bottom.origin.y = origin.y + top.size.height;
815                 bottom.size.width = size.width;
816                 bottom.size.height = size.height - top.size.height;
817             }
818             else
819             {
820                 bottom.Clear();
821             }
822         }
823         
824         void
825         VerticalSplitPercentage (float left_percentage, Rect &left, Rect &right) const
826         {
827             float left_width = left_percentage * size.width;
828             VerticalSplit (left_width, left, right);
829         }
830
831
832         void
833         VerticalSplit (int left_width, Rect &left, Rect &right) const
834         {
835             left = *this;
836             if (left_width < size.width)
837             {
838                 left.size.width = left_width;
839                 right.origin.x = origin.x + left.size.width;
840                 right.origin.y = origin.y;
841                 right.size.width = size.width - left.size.width;
842                 right.size.height = size.height;
843             }
844             else
845             {
846                 right.Clear();
847             }
848         }
849     };
850
851     bool operator == (const Rect &lhs, const Rect &rhs)
852     {
853         return lhs.origin == rhs.origin && lhs.size == rhs.size;
854     }
855     bool operator != (const Rect &lhs, const Rect &rhs)
856     {
857         return lhs.origin != rhs.origin || lhs.size != rhs.size;
858     }
859
860     enum HandleCharResult
861     {
862         eKeyNotHandled      = 0,
863         eKeyHandled         = 1,
864         eQuitApplication    = 2
865     };
866     
867     enum class MenuActionResult
868     {
869         Handled,
870         NotHandled,
871         Quit    // Exit all menus and quit
872     };
873
874     struct KeyHelp
875     {
876         int ch;
877         const char *description;
878     };
879
880     class WindowDelegate
881     {
882     public:
883         virtual
884         ~WindowDelegate()
885         {
886         }
887         
888         virtual bool
889         WindowDelegateDraw (Window &window, bool force)
890         {
891             return false; // Drawing not handled
892         }
893         
894         virtual HandleCharResult
895         WindowDelegateHandleChar (Window &window, int key)
896         {
897             return eKeyNotHandled;
898         }
899         
900         virtual const char *
901         WindowDelegateGetHelpText ()
902         {
903             return NULL;
904         }
905
906         virtual KeyHelp *
907         WindowDelegateGetKeyHelp ()
908         {
909             return NULL;
910         }
911     };
912     
913     class HelpDialogDelegate :
914         public WindowDelegate
915     {
916     public:
917         HelpDialogDelegate (const char *text, KeyHelp *key_help_array);
918         
919         virtual
920         ~HelpDialogDelegate();
921         
922         virtual bool
923         WindowDelegateDraw (Window &window, bool force);
924         
925         virtual HandleCharResult
926         WindowDelegateHandleChar (Window &window, int key);
927         
928         size_t
929         GetNumLines() const
930         {
931             return m_text.GetSize();
932         }
933
934         size_t
935         GetMaxLineLength () const
936         {
937             return m_text.GetMaxStringLength();
938         }
939
940     protected:
941         StringList m_text;
942         int m_first_visible_line;
943     };
944
945
946     class Window
947     {
948     public:
949
950         Window (const char *name) :
951             m_name (name),
952             m_window (NULL),
953             m_panel (NULL),
954             m_parent (NULL),
955             m_subwindows (),
956             m_delegate_sp (),
957             m_curr_active_window_idx (UINT32_MAX),
958             m_prev_active_window_idx (UINT32_MAX),
959             m_delete (false),
960             m_needs_update (true),
961             m_can_activate (true),
962             m_is_subwin (false)
963         {
964         }
965         
966         Window (const char *name, WINDOW *w, bool del = true) :
967             m_name (name),
968             m_window (NULL),
969             m_panel (NULL),
970             m_parent (NULL),
971             m_subwindows (),
972             m_delegate_sp (),
973             m_curr_active_window_idx (UINT32_MAX),
974             m_prev_active_window_idx (UINT32_MAX),
975             m_delete (del),
976             m_needs_update (true),
977             m_can_activate (true),
978             m_is_subwin (false)
979         {
980             if (w)
981                 Reset(w);
982         }
983         
984         Window (const char *name, const Rect &bounds) :
985             m_name (name),
986             m_window (NULL),
987             m_parent (NULL),
988             m_subwindows (),
989             m_delegate_sp (),
990             m_curr_active_window_idx (UINT32_MAX),
991             m_prev_active_window_idx (UINT32_MAX),
992             m_delete (true),
993             m_needs_update (true),
994             m_can_activate (true),
995             m_is_subwin (false)
996         {
997             Reset (::newwin (bounds.size.height, bounds.size.width, bounds.origin.y, bounds.origin.y));
998         }
999         
1000         virtual
1001         ~Window ()
1002         {
1003             RemoveSubWindows ();
1004             Reset ();
1005         }
1006         
1007         void
1008         Reset (WINDOW *w = NULL, bool del = true)
1009         {
1010             if (m_window == w)
1011                 return;
1012             
1013             if (m_panel)
1014             {
1015                 ::del_panel (m_panel);
1016                 m_panel = NULL;
1017             }
1018             if (m_window && m_delete)
1019             {
1020                 ::delwin (m_window);
1021                 m_window = NULL;
1022                 m_delete = false;
1023             }
1024             if (w)
1025             {
1026                 m_window = w;
1027                 m_panel = ::new_panel (m_window);
1028                 m_delete = del;
1029             }
1030         }
1031         
1032         void    AttributeOn (attr_t attr)   { ::wattron (m_window, attr); }
1033         void    AttributeOff (attr_t attr)  { ::wattroff (m_window, attr); }
1034         void    Box (chtype v_char = ACS_VLINE, chtype h_char = ACS_HLINE) { ::box(m_window, v_char, h_char); }
1035         void    Clear ()    { ::wclear (m_window); }
1036         void    Erase ()    { ::werase (m_window); }
1037         Rect    GetBounds () { return Rect (GetParentOrigin(), GetSize()); } // Get the rectangle in our parent window
1038         int     GetChar ()  { return ::wgetch (m_window); }
1039         int     GetCursorX ()     { return getcurx (m_window); }
1040         int     GetCursorY ()     { return getcury (m_window); }
1041         Rect    GetFrame ()    { return Rect (Point(), GetSize()); } // Get our rectangle in our own coordinate system
1042         Point   GetParentOrigin() { return Point (GetParentX(), GetParentY()); }
1043         Size    GetSize()         { return Size (GetWidth(), GetHeight()); }
1044         int     GetParentX ()     { return getparx (m_window); }
1045         int     GetParentY ()     { return getpary (m_window); }
1046         int     GetMaxX()   { return getmaxx (m_window); }
1047         int     GetMaxY()   { return getmaxy (m_window); }
1048         int     GetWidth()  { return GetMaxX(); }
1049         int     GetHeight() { return GetMaxY(); }
1050         void    MoveCursor (int x, int y) {  ::wmove (m_window, y, x); }
1051         void    MoveWindow (int x, int y) {  MoveWindow(Point(x,y)); }
1052         void    Resize (int w, int h) { ::wresize(m_window, h, w); }
1053         void    Resize (const Size &size) { ::wresize(m_window, size.height, size.width); }
1054         void    PutChar (int ch)    { ::waddch (m_window, ch); }
1055         void    PutCString (const char *s, int len = -1) { ::waddnstr (m_window, s, len); }
1056         void    Refresh ()  { ::wrefresh (m_window); }
1057         void    DeferredRefresh ()
1058         {
1059             // We are using panels, so we don't need to call this...
1060             //::wnoutrefresh(m_window);
1061         }
1062         void    SetBackground (int color_pair_idx) { ::wbkgd (m_window,COLOR_PAIR(color_pair_idx)); }
1063         void    UnderlineOn ()  { AttributeOn(A_UNDERLINE); }
1064         void    UnderlineOff () { AttributeOff(A_UNDERLINE); }
1065
1066         void    PutCStringTruncated (const char *s, int right_pad)
1067         {
1068             int bytes_left = GetWidth() - GetCursorX();
1069             if (bytes_left > right_pad)
1070             {
1071                 bytes_left -= right_pad;
1072                 ::waddnstr (m_window, s, bytes_left);
1073             }
1074         }
1075
1076         void
1077         MoveWindow (const Point &origin)
1078         {
1079             const bool moving_window = origin != GetParentOrigin();
1080             if (m_is_subwin && moving_window)
1081             {
1082                 // Can't move subwindows, must delete and re-create
1083                 Size size = GetSize();
1084                 Reset (::subwin (m_parent->m_window,
1085                                  size.height,
1086                                  size.width,
1087                                  origin.y,
1088                                  origin.x), true);
1089             }
1090             else
1091             {
1092                 ::mvwin (m_window, origin.y, origin.x);
1093             }
1094         }
1095
1096         void
1097         SetBounds (const Rect &bounds)
1098         {
1099             const bool moving_window = bounds.origin != GetParentOrigin();
1100             if (m_is_subwin && moving_window)
1101             {
1102                 // Can't move subwindows, must delete and re-create
1103                 Reset (::subwin (m_parent->m_window,
1104                                  bounds.size.height,
1105                                  bounds.size.width,
1106                                  bounds.origin.y,
1107                                  bounds.origin.x), true);
1108             }
1109             else
1110             {
1111                 if (moving_window)
1112                     MoveWindow(bounds.origin);
1113                 Resize (bounds.size);
1114             }
1115         }
1116
1117         void
1118         Printf (const char *format, ...)  __attribute__ ((format (printf, 2, 3)))
1119         {
1120             va_list args;
1121             va_start (args, format);
1122             vwprintw(m_window, format, args);
1123             va_end (args);
1124         }
1125
1126         void
1127         Touch ()
1128         {
1129             ::touchwin (m_window);
1130             if (m_parent)
1131                 m_parent->Touch();
1132         }
1133
1134         WindowSP
1135         CreateSubWindow (const char *name, const Rect &bounds, bool make_active)
1136         {
1137             WindowSP subwindow_sp;
1138             if (m_window)
1139             {
1140                 subwindow_sp.reset(new Window(name, ::subwin (m_window,
1141                                                               bounds.size.height,
1142                                                               bounds.size.width,
1143                                                               bounds.origin.y,
1144                                                               bounds.origin.x), true));
1145                 subwindow_sp->m_is_subwin = true;
1146             }
1147             else
1148             {
1149                 subwindow_sp.reset(new Window(name, ::newwin (bounds.size.height,
1150                                                               bounds.size.width,
1151                                                               bounds.origin.y,
1152                                                               bounds.origin.x), true));
1153                 subwindow_sp->m_is_subwin = false;
1154             }
1155             subwindow_sp->m_parent = this;
1156             if (make_active)
1157             {
1158                 m_prev_active_window_idx = m_curr_active_window_idx;
1159                 m_curr_active_window_idx = m_subwindows.size();
1160             }
1161             m_subwindows.push_back(subwindow_sp);
1162             ::top_panel (subwindow_sp->m_panel);
1163             m_needs_update = true;
1164             return subwindow_sp;
1165         }
1166         
1167         bool
1168         RemoveSubWindow (Window *window)
1169         {
1170             Windows::iterator pos, end = m_subwindows.end();
1171             size_t i = 0;
1172             for (pos = m_subwindows.begin(); pos != end; ++pos, ++i)
1173             {
1174                 if ((*pos).get() == window)
1175                 {
1176                     if (m_prev_active_window_idx == i)
1177                         m_prev_active_window_idx = UINT32_MAX;
1178                     else if (m_prev_active_window_idx != UINT32_MAX && m_prev_active_window_idx > i)
1179                         --m_prev_active_window_idx;
1180
1181                     if (m_curr_active_window_idx == i)
1182                         m_curr_active_window_idx = UINT32_MAX;
1183                     else if (m_curr_active_window_idx != UINT32_MAX && m_curr_active_window_idx > i)
1184                         --m_curr_active_window_idx;
1185                     window->Erase();
1186                     m_subwindows.erase(pos);
1187                     m_needs_update = true;
1188                     if (m_parent)
1189                         m_parent->Touch();
1190                     else
1191                         ::touchwin (stdscr);
1192                     return true;
1193                 }
1194             }
1195             return false;
1196         }
1197         
1198         WindowSP
1199         FindSubWindow (const char *name)
1200         {
1201             Windows::iterator pos, end = m_subwindows.end();
1202             size_t i = 0;
1203             for (pos = m_subwindows.begin(); pos != end; ++pos, ++i)
1204             {
1205                 if ((*pos)->m_name.compare(name) == 0)
1206                     return *pos;
1207             }
1208             return WindowSP();
1209         }
1210         
1211         void
1212         RemoveSubWindows ()
1213         {
1214             m_curr_active_window_idx = UINT32_MAX;
1215             m_prev_active_window_idx = UINT32_MAX;
1216             for (Windows::iterator pos = m_subwindows.begin();
1217                  pos != m_subwindows.end();
1218                  pos = m_subwindows.erase(pos))
1219             {
1220                 (*pos)->Erase();
1221             }
1222             if (m_parent)
1223                 m_parent->Touch();
1224             else
1225                 ::touchwin (stdscr);
1226         }
1227
1228         WINDOW *
1229         get()
1230         {
1231             return m_window;
1232         }
1233
1234         operator WINDOW *()
1235         {
1236             return m_window;
1237         }
1238         
1239         //----------------------------------------------------------------------
1240         // Window drawing utilities
1241         //----------------------------------------------------------------------
1242         void
1243         DrawTitleBox (const char *title, const char *bottom_message = NULL)
1244         {
1245             attr_t attr = 0;
1246             if (IsActive())
1247                 attr = A_BOLD | COLOR_PAIR(2);
1248             else
1249                 attr = 0;
1250             if (attr)
1251                 AttributeOn(attr);
1252
1253             Box();
1254             MoveCursor(3, 0);
1255             
1256             if (title && title[0])
1257             {
1258                 PutChar ('<');
1259                 PutCString (title);
1260                 PutChar ('>');
1261             }
1262             
1263             if (bottom_message && bottom_message[0])
1264             {
1265                 int bottom_message_length = strlen(bottom_message);
1266                 int x = GetWidth() - 3 - (bottom_message_length + 2);
1267                 
1268                 if (x > 0)
1269                 {
1270                     MoveCursor (x, GetHeight() - 1);
1271                     PutChar ('[');
1272                     PutCString(bottom_message);
1273                     PutChar (']');
1274                 }
1275                 else
1276                 {
1277                     MoveCursor (1, GetHeight() - 1);
1278                     PutChar ('[');
1279                     PutCStringTruncated (bottom_message, 1);
1280                 }
1281             }
1282             if (attr)
1283                 AttributeOff(attr);
1284             
1285         }
1286
1287         virtual void
1288         Draw (bool force)
1289         {
1290             if (m_delegate_sp && m_delegate_sp->WindowDelegateDraw (*this, force))
1291                 return;
1292
1293             for (auto &subwindow_sp : m_subwindows)
1294                 subwindow_sp->Draw(force);
1295         }
1296
1297         bool
1298         CreateHelpSubwindow ()
1299         {
1300             if (m_delegate_sp)
1301             {
1302                 const char *text = m_delegate_sp->WindowDelegateGetHelpText ();
1303                 KeyHelp *key_help = m_delegate_sp->WindowDelegateGetKeyHelp ();
1304                 if ((text && text[0]) || key_help)
1305                 {
1306                     std::auto_ptr<HelpDialogDelegate> help_delegate_ap(new HelpDialogDelegate(text, key_help));
1307                     const size_t num_lines = help_delegate_ap->GetNumLines();
1308                     const size_t max_length = help_delegate_ap->GetMaxLineLength();
1309                     Rect bounds = GetBounds();
1310                     bounds.Inset(1, 1);
1311                     if (max_length + 4 < bounds.size.width)
1312                     {
1313                         bounds.origin.x += (bounds.size.width - max_length + 4)/2;
1314                         bounds.size.width = max_length + 4;
1315                     }
1316                     else
1317                     {
1318                         if (bounds.size.width > 100)
1319                         {
1320                             const int inset_w = bounds.size.width / 4;
1321                             bounds.origin.x += inset_w;
1322                             bounds.size.width -= 2*inset_w;
1323                         }
1324                     }
1325                     
1326                     if (num_lines + 2 < bounds.size.height)
1327                     {
1328                         bounds.origin.y += (bounds.size.height - num_lines + 2)/2;
1329                         bounds.size.height = num_lines + 2;
1330                     }
1331                     else
1332                     {
1333                         if (bounds.size.height > 100)
1334                         {
1335                             const int inset_h = bounds.size.height / 4;
1336                             bounds.origin.y += inset_h;
1337                             bounds.size.height -= 2*inset_h;
1338                         }
1339                     }
1340                     WindowSP help_window_sp;
1341                     Window *parent_window = GetParent();
1342                     if (parent_window)
1343                         help_window_sp = parent_window->CreateSubWindow("Help", bounds, true);
1344                     else
1345                         help_window_sp = CreateSubWindow("Help", bounds, true);
1346                     help_window_sp->SetDelegate(WindowDelegateSP(help_delegate_ap.release()));
1347                     return true;
1348                 }
1349             }
1350             return false;
1351         }
1352
1353         virtual HandleCharResult
1354         HandleChar (int key)
1355         {
1356             // Always check the active window first
1357             HandleCharResult result = eKeyNotHandled;
1358             WindowSP active_window_sp = GetActiveWindow ();
1359             if (active_window_sp)
1360             {
1361                 result = active_window_sp->HandleChar (key);
1362                 if (result != eKeyNotHandled)
1363                     return result;
1364             }
1365             
1366             if (m_delegate_sp)
1367             {
1368                 result = m_delegate_sp->WindowDelegateHandleChar (*this, key);
1369                 if (result != eKeyNotHandled)
1370                     return result;
1371             }
1372
1373             // Then check for any windows that want any keys
1374             // that weren't handled. This is typically only
1375             // for a menubar.
1376             // Make a copy of the subwindows in case any HandleChar()
1377             // functions muck with the subwindows. If we don't do this,
1378             // we can crash when iterating over the subwindows.
1379             Windows subwindows (m_subwindows);
1380             for (auto subwindow_sp : subwindows)
1381             {
1382                 if (subwindow_sp->m_can_activate == false)
1383                 {
1384                     HandleCharResult result = subwindow_sp->HandleChar(key);
1385                     if (result != eKeyNotHandled)
1386                         return result;
1387                 }
1388             }
1389
1390             return eKeyNotHandled;
1391         }
1392
1393         bool
1394         SetActiveWindow (Window *window)
1395         {
1396             const size_t num_subwindows = m_subwindows.size();
1397             for (size_t i=0; i<num_subwindows; ++i)
1398             {
1399                 if (m_subwindows[i].get() == window)
1400                 {
1401                     m_prev_active_window_idx = m_curr_active_window_idx;
1402                     ::top_panel (window->m_panel);
1403                     m_curr_active_window_idx = i;
1404                     return true;
1405                 }
1406             }
1407             return false;
1408         }
1409
1410         WindowSP
1411         GetActiveWindow ()
1412         {
1413             if (!m_subwindows.empty())
1414             {
1415                 if (m_curr_active_window_idx >= m_subwindows.size())
1416                 {
1417                     if (m_prev_active_window_idx < m_subwindows.size())
1418                     {
1419                         m_curr_active_window_idx = m_prev_active_window_idx;
1420                         m_prev_active_window_idx = UINT32_MAX;
1421                     }
1422                     else if (IsActive())
1423                     {
1424                         m_prev_active_window_idx = UINT32_MAX;
1425                         m_curr_active_window_idx = UINT32_MAX;
1426                         
1427                         // Find first window that wants to be active if this window is active
1428                         const size_t num_subwindows = m_subwindows.size();
1429                         for (size_t i=0; i<num_subwindows; ++i)
1430                         {
1431                             if (m_subwindows[i]->GetCanBeActive())
1432                             {
1433                                 m_curr_active_window_idx = i;
1434                                 break;
1435                             }
1436                         }
1437                     }
1438                 }
1439                 
1440                 if (m_curr_active_window_idx < m_subwindows.size())
1441                     return m_subwindows[m_curr_active_window_idx];
1442             }
1443             return WindowSP();
1444         }
1445         
1446         bool
1447         GetCanBeActive () const
1448         {
1449             return m_can_activate;
1450         }
1451
1452         void
1453         SetCanBeActive (bool b)
1454         {
1455             m_can_activate = b;
1456         }
1457         
1458         const WindowDelegateSP &
1459         GetDelegate () const
1460         {
1461             return m_delegate_sp;
1462         }
1463
1464         void
1465         SetDelegate (const WindowDelegateSP &delegate_sp)
1466         {
1467             m_delegate_sp = delegate_sp;
1468         }
1469         
1470         Window *
1471         GetParent () const
1472         {
1473             return m_parent;
1474         }
1475         
1476         bool
1477         IsActive () const
1478         {
1479             if (m_parent)
1480                 return m_parent->GetActiveWindow().get() == this;
1481             else
1482                 return true; // Top level window is always active
1483         }
1484         
1485         void
1486         SelectNextWindowAsActive ()
1487         {
1488             // Move active focus to next window
1489             const size_t num_subwindows = m_subwindows.size();
1490             if (m_curr_active_window_idx == UINT32_MAX)
1491             {
1492                 uint32_t idx = 0;
1493                 for (auto subwindow_sp : m_subwindows)
1494                 {
1495                     if (subwindow_sp->GetCanBeActive())
1496                     {
1497                         m_curr_active_window_idx = idx;
1498                         break;
1499                     }
1500                     ++idx;
1501                 }
1502             }
1503             else if (m_curr_active_window_idx + 1 < num_subwindows)
1504             {
1505                 bool handled = false;
1506                 m_prev_active_window_idx = m_curr_active_window_idx;
1507                 for (size_t idx=m_curr_active_window_idx + 1; idx<num_subwindows; ++idx)
1508                 {
1509                     if (m_subwindows[idx]->GetCanBeActive())
1510                     {
1511                         m_curr_active_window_idx = idx;
1512                         handled = true;
1513                         break;
1514                     }
1515                 }
1516                 if (!handled)
1517                 {
1518                     for (size_t idx=0; idx<=m_prev_active_window_idx; ++idx)
1519                     {
1520                         if (m_subwindows[idx]->GetCanBeActive())
1521                         {
1522                             m_curr_active_window_idx = idx;
1523                             break;
1524                         }
1525                     }
1526                 }
1527             }
1528             else
1529             {
1530                 m_prev_active_window_idx = m_curr_active_window_idx;
1531                 for (size_t idx=0; idx<num_subwindows; ++idx)
1532                 {
1533                     if (m_subwindows[idx]->GetCanBeActive())
1534                     {
1535                         m_curr_active_window_idx = idx;
1536                         break;
1537                     }
1538                 }
1539             }
1540         }
1541
1542         const char *
1543         GetName () const
1544         {
1545             return m_name.c_str();
1546         }
1547     protected:
1548         std::string m_name;
1549         WINDOW *m_window;
1550         PANEL *m_panel;
1551         Window *m_parent;
1552         Windows m_subwindows;
1553         WindowDelegateSP m_delegate_sp;
1554         uint32_t m_curr_active_window_idx;
1555         uint32_t m_prev_active_window_idx;
1556         bool m_delete;
1557         bool m_needs_update;
1558         bool m_can_activate;
1559         bool m_is_subwin;
1560         
1561     private:
1562         DISALLOW_COPY_AND_ASSIGN(Window);
1563     };
1564     
1565     class MenuDelegate
1566     {
1567     public:
1568         virtual ~MenuDelegate() {}
1569         
1570         virtual MenuActionResult
1571         MenuDelegateAction (Menu &menu) = 0;
1572     };
1573
1574     class Menu : public WindowDelegate
1575     {
1576     public:
1577         enum class Type
1578         {
1579             Invalid,
1580             Bar,
1581             Item,
1582             Separator
1583         };
1584         
1585         // Menubar or separator constructor
1586         Menu (Type type);
1587         
1588         // Menuitem constructor
1589         Menu (const char *name,
1590               const char *key_name,
1591               int key_value,
1592               uint64_t identifier);
1593         
1594         virtual ~
1595         Menu ()
1596         {
1597         }
1598
1599         const MenuDelegateSP &
1600         GetDelegate () const
1601         {
1602             return m_delegate_sp;
1603         }
1604         
1605         void
1606         SetDelegate (const MenuDelegateSP &delegate_sp)
1607         {
1608             m_delegate_sp = delegate_sp;
1609         }
1610         
1611         void
1612         RecalculateNameLengths();
1613
1614         void
1615         AddSubmenu (const MenuSP &menu_sp);
1616         
1617         int
1618         DrawAndRunMenu (Window &window);
1619         
1620         void
1621         DrawMenuTitle (Window &window, bool highlight);
1622
1623         virtual bool
1624         WindowDelegateDraw (Window &window, bool force);
1625         
1626         virtual HandleCharResult
1627         WindowDelegateHandleChar (Window &window, int key);
1628
1629         MenuActionResult
1630         ActionPrivate (Menu &menu)
1631         {
1632             MenuActionResult result = MenuActionResult::NotHandled;
1633             if (m_delegate_sp)
1634             {
1635                 result = m_delegate_sp->MenuDelegateAction (menu);
1636                 if (result != MenuActionResult::NotHandled)
1637                     return result;
1638             }
1639             else if (m_parent)
1640             {
1641                 result = m_parent->ActionPrivate(menu);
1642                 if (result != MenuActionResult::NotHandled)
1643                     return result;
1644             }
1645             return m_canned_result;
1646         }
1647
1648         MenuActionResult
1649         Action ()
1650         {
1651             // Call the recursive action so it can try to handle it
1652             // with the menu delegate, and if not, try our parent menu
1653             return ActionPrivate (*this);
1654         }
1655         
1656         void
1657         SetCannedResult (MenuActionResult result)
1658         {
1659             m_canned_result = result;
1660         }
1661
1662         Menus &
1663         GetSubmenus()
1664         {
1665             return m_submenus;
1666         }
1667
1668         const Menus &
1669         GetSubmenus() const
1670         {
1671             return m_submenus;
1672         }
1673
1674         int
1675         GetSelectedSubmenuIndex () const
1676         {
1677             return m_selected;
1678         }
1679         
1680         void
1681         SetSelectedSubmenuIndex (int idx)
1682         {
1683             m_selected = idx;
1684         }
1685
1686         Type
1687         GetType () const
1688         {
1689             return m_type;
1690         }
1691         
1692         int
1693         GetStartingColumn() const
1694         {
1695             return m_start_col;
1696         }
1697
1698         void
1699         SetStartingColumn(int col)
1700         {
1701             m_start_col = col;
1702         }
1703
1704         int
1705         GetKeyValue() const
1706         {
1707             return m_key_value;
1708         }
1709         
1710         void
1711         SetKeyValue(int key_value)
1712         {
1713             m_key_value = key_value;
1714         }
1715
1716         std::string &
1717         GetName()
1718         {
1719             return m_name;
1720         }
1721
1722         std::string &
1723         GetKeyName()
1724         {
1725             return m_key_name;
1726         }
1727
1728         int
1729         GetDrawWidth () const
1730         {
1731             return m_max_submenu_name_length + m_max_submenu_key_name_length + 8;
1732         }
1733
1734         
1735         uint64_t
1736         GetIdentifier() const
1737         {
1738             return m_identifier;
1739         }
1740
1741         void
1742         SetIdentifier (uint64_t identifier)
1743         {
1744             m_identifier = identifier;
1745         }
1746
1747     protected:
1748         std::string m_name;
1749         std::string m_key_name;
1750         uint64_t m_identifier;
1751         Type m_type;
1752         int m_key_value;
1753         int m_start_col;
1754         int m_max_submenu_name_length;
1755         int m_max_submenu_key_name_length;
1756         int m_selected;
1757         Menu *m_parent;
1758         Menus m_submenus;
1759         WindowSP m_menu_window_sp;
1760         MenuActionResult m_canned_result;
1761         MenuDelegateSP m_delegate_sp;
1762     };
1763
1764     // Menubar or separator constructor
1765     Menu::Menu (Type type) :
1766         m_name (),
1767         m_key_name (),
1768         m_identifier (0),
1769         m_type (type),
1770         m_key_value (0),
1771         m_start_col (0),
1772         m_max_submenu_name_length (0),
1773         m_max_submenu_key_name_length (0),
1774         m_selected (0),
1775         m_parent (NULL),
1776         m_submenus (),
1777         m_canned_result (MenuActionResult::NotHandled),
1778         m_delegate_sp()
1779     {
1780     }
1781
1782     // Menuitem constructor
1783     Menu::Menu (const char *name,
1784                 const char *key_name,
1785                 int key_value,
1786                 uint64_t identifier) :
1787         m_name (),
1788         m_key_name (),
1789         m_identifier (identifier),
1790         m_type (Type::Invalid),
1791         m_key_value (key_value),
1792         m_start_col (0),
1793         m_max_submenu_name_length (0),
1794         m_max_submenu_key_name_length (0),
1795         m_selected (0),
1796         m_parent (NULL),
1797         m_submenus (),
1798         m_canned_result (MenuActionResult::NotHandled),
1799         m_delegate_sp()
1800     {
1801         if (name && name[0])
1802         {
1803             m_name = name;
1804             m_type = Type::Item;
1805             if (key_name && key_name[0])
1806                 m_key_name = key_name;
1807         }
1808         else
1809         {
1810             m_type = Type::Separator;
1811         }
1812     }
1813
1814     void
1815     Menu::RecalculateNameLengths()
1816     {
1817         m_max_submenu_name_length = 0;
1818         m_max_submenu_key_name_length = 0;
1819         Menus &submenus = GetSubmenus();
1820         const size_t num_submenus = submenus.size();
1821         for (size_t i=0; i<num_submenus; ++i)
1822         {
1823             Menu *submenu = submenus[i].get();
1824             if (m_max_submenu_name_length < submenu->m_name.size())
1825                 m_max_submenu_name_length = submenu->m_name.size();
1826             if (m_max_submenu_key_name_length < submenu->m_key_name.size())
1827                 m_max_submenu_key_name_length = submenu->m_key_name.size();
1828         }
1829     }
1830
1831     void
1832     Menu::AddSubmenu (const MenuSP &menu_sp)
1833     {
1834         menu_sp->m_parent = this;
1835         if (m_max_submenu_name_length < menu_sp->m_name.size())
1836             m_max_submenu_name_length = menu_sp->m_name.size();
1837         if (m_max_submenu_key_name_length < menu_sp->m_key_name.size())
1838             m_max_submenu_key_name_length = menu_sp->m_key_name.size();
1839         m_submenus.push_back(menu_sp);
1840     }
1841
1842     void
1843     Menu::DrawMenuTitle (Window &window, bool highlight)
1844     {
1845         if (m_type == Type::Separator)
1846         {
1847             window.MoveCursor(0, window.GetCursorY());
1848             window.PutChar(ACS_LTEE);
1849             int width = window.GetWidth();
1850             if (width > 2)
1851             {
1852                 width -= 2;
1853                 for (size_t i=0; i< width; ++i)
1854                     window.PutChar(ACS_HLINE);
1855             }
1856             window.PutChar(ACS_RTEE);
1857         }
1858         else
1859         {
1860             const int shortcut_key = m_key_value;
1861             bool underlined_shortcut = false;
1862             const attr_t hilgight_attr = A_REVERSE;
1863             if (highlight)
1864                 window.AttributeOn(hilgight_attr);
1865             if (isprint(shortcut_key))
1866             {
1867                 size_t lower_pos = m_name.find(tolower(shortcut_key));
1868                 size_t upper_pos = m_name.find(toupper(shortcut_key));
1869                 const char *name = m_name.c_str();
1870                 size_t pos = std::min<size_t>(lower_pos, upper_pos);
1871                 if (pos != std::string::npos)
1872                 {
1873                     underlined_shortcut = true;
1874                     if (pos > 0)
1875                     {
1876                         window.PutCString(name, pos);
1877                         name += pos;
1878                     }
1879                     const attr_t shortcut_attr = A_UNDERLINE|A_BOLD;
1880                     window.AttributeOn (shortcut_attr);
1881                     window.PutChar(name[0]);
1882                     window.AttributeOff(shortcut_attr);
1883                     name++;
1884                     if (name[0])
1885                         window.PutCString(name);
1886                 }
1887             }
1888             
1889             if (!underlined_shortcut)
1890             {
1891                 window.PutCString(m_name.c_str());
1892             }
1893
1894             if (highlight)
1895                 window.AttributeOff(hilgight_attr);
1896
1897             if (m_key_name.empty())
1898             {
1899                 if (!underlined_shortcut && isprint(m_key_value))
1900                 {
1901                     window.AttributeOn (COLOR_PAIR(3));
1902                     window.Printf (" (%c)", m_key_value);
1903                     window.AttributeOff (COLOR_PAIR(3));
1904                 }
1905             }
1906             else
1907             {
1908                 window.AttributeOn (COLOR_PAIR(3));
1909                 window.Printf (" (%s)", m_key_name.c_str());
1910                 window.AttributeOff (COLOR_PAIR(3));
1911             }
1912         }
1913     }
1914     
1915     bool
1916     Menu::WindowDelegateDraw (Window &window, bool force)
1917     {
1918         Menus &submenus = GetSubmenus();
1919         const size_t num_submenus = submenus.size();
1920         const int selected_idx = GetSelectedSubmenuIndex();
1921         Menu::Type menu_type = GetType ();
1922         switch (menu_type)
1923         {
1924         case  Menu::Type::Bar:
1925             {
1926                 window.SetBackground(2);
1927                 window.MoveCursor(0, 0);
1928                 for (size_t i=0; i<num_submenus; ++i)
1929                 {
1930                     Menu *menu = submenus[i].get();
1931                     if (i > 0)
1932                         window.PutChar(' ');
1933                     menu->SetStartingColumn (window.GetCursorX());
1934                     window.PutCString("| ");
1935                     menu->DrawMenuTitle (window, false);
1936                 }
1937                 window.PutCString(" |");
1938                 window.DeferredRefresh();
1939             }
1940             break;
1941                 
1942         case Menu::Type::Item:
1943             {
1944                 int y = 1;
1945                 int x = 3;
1946                 // Draw the menu
1947                 int cursor_x = 0;
1948                 int cursor_y = 0;
1949                 window.Erase();
1950                 window.SetBackground(2);
1951                 window.Box();
1952                 for (size_t i=0; i<num_submenus; ++i)
1953                 {
1954                     const bool is_selected = i == selected_idx;
1955                     window.MoveCursor(x, y + i);
1956                     if (is_selected)
1957                     {
1958                         // Remember where we want the cursor to be
1959                         cursor_x = x-1;
1960                         cursor_y = y+i;
1961                     }
1962                     submenus[i]->DrawMenuTitle (window, is_selected);
1963                 }
1964                 window.MoveCursor(cursor_x, cursor_y);
1965                 window.DeferredRefresh();
1966             }
1967             break;
1968
1969         default:
1970         case Menu::Type::Separator:
1971             break;
1972         }
1973         return true; // Drawing handled...
1974     }
1975     
1976     HandleCharResult
1977     Menu::WindowDelegateHandleChar (Window &window, int key)
1978     {
1979         HandleCharResult result = eKeyNotHandled;
1980         
1981         Menus &submenus = GetSubmenus();
1982         const size_t num_submenus = submenus.size();
1983         const int selected_idx = GetSelectedSubmenuIndex();
1984         Menu::Type menu_type = GetType ();
1985         if (menu_type == Menu::Type::Bar)
1986         {
1987             MenuSP run_menu_sp;
1988             switch (key)
1989             {
1990                 case KEY_DOWN:
1991                 case KEY_UP:
1992                     // Show last menu or first menu
1993                     if (selected_idx < num_submenus)
1994                         run_menu_sp = submenus[selected_idx];
1995                     else if (!submenus.empty())
1996                         run_menu_sp = submenus.front();
1997                     result = eKeyHandled;
1998                     break;
1999                     
2000                 case KEY_RIGHT:
2001                 {
2002                     ++m_selected;
2003                     if (m_selected >= num_submenus)
2004                         m_selected = 0;
2005                     if (m_selected < num_submenus)
2006                         run_menu_sp = submenus[m_selected];
2007                     else if (!submenus.empty())
2008                         run_menu_sp = submenus.front();
2009                     result = eKeyHandled;
2010                 }
2011                     break;
2012                     
2013                 case KEY_LEFT:
2014                 {
2015                     --m_selected;
2016                     if (m_selected < 0)
2017                         m_selected = num_submenus - 1;
2018                     if (m_selected < num_submenus)
2019                         run_menu_sp = submenus[m_selected];
2020                     else if (!submenus.empty())
2021                         run_menu_sp = submenus.front();
2022                     result = eKeyHandled;
2023                 }
2024                     break;
2025                     
2026                 default:
2027                     for (size_t i=0; i<num_submenus; ++i)
2028                     {
2029                         if (submenus[i]->GetKeyValue() == key)
2030                         {
2031                             SetSelectedSubmenuIndex(i);
2032                             run_menu_sp = submenus[i];
2033                             result = eKeyHandled;
2034                             break;
2035                         }
2036                     }
2037                     break;
2038             }
2039             
2040             if (run_menu_sp)
2041             {
2042                 // Run the action on this menu in case we need to populate the
2043                 // menu with dynamic content and also in case check marks, and
2044                 // any other menu decorations need to be caclulated
2045                 if (run_menu_sp->Action() == MenuActionResult::Quit)
2046                     return eQuitApplication;
2047
2048                 Rect menu_bounds;
2049                 menu_bounds.origin.x = run_menu_sp->GetStartingColumn();
2050                 menu_bounds.origin.y = 1;
2051                 menu_bounds.size.width = run_menu_sp->GetDrawWidth();
2052                 menu_bounds.size.height = run_menu_sp->GetSubmenus().size() + 2;
2053                 if (m_menu_window_sp)
2054                     window.GetParent()->RemoveSubWindow(m_menu_window_sp.get());
2055                 
2056                 m_menu_window_sp = window.GetParent()->CreateSubWindow (run_menu_sp->GetName().c_str(),
2057                                                                         menu_bounds,
2058                                                                         true);
2059                 m_menu_window_sp->SetDelegate (run_menu_sp);
2060             }
2061         }
2062         else if (menu_type == Menu::Type::Item)
2063         {
2064             switch (key)
2065             {
2066                 case KEY_DOWN:
2067                     if (m_submenus.size() > 1)
2068                     {
2069                         const int start_select = m_selected;
2070                         while (++m_selected != start_select)
2071                         {
2072                             if (m_selected >= num_submenus)
2073                                 m_selected = 0;
2074                             if (m_submenus[m_selected]->GetType() == Type::Separator)
2075                                 continue;
2076                             else
2077                                 break;
2078                         }
2079                         return eKeyHandled;
2080                     }
2081                     break;
2082                     
2083                 case KEY_UP:
2084                     if (m_submenus.size() > 1)
2085                     {
2086                         const int start_select = m_selected;
2087                         while (--m_selected != start_select)
2088                         {
2089                             if (m_selected < 0)
2090                                 m_selected = num_submenus - 1;
2091                             if (m_submenus[m_selected]->GetType() == Type::Separator)
2092                                 continue;
2093                             else
2094                                 break;
2095                         }
2096                         return eKeyHandled;
2097                     }
2098                     break;
2099                     
2100                 case KEY_RETURN:
2101                     if (selected_idx < num_submenus)
2102                     {
2103                         if (submenus[selected_idx]->Action() == MenuActionResult::Quit)
2104                             return eQuitApplication;
2105                         window.GetParent()->RemoveSubWindow(&window);
2106                         return eKeyHandled;
2107                     }
2108                     break;
2109                     
2110                 case KEY_ESCAPE: // Beware: pressing escape key has 1 to 2 second delay in case other chars are entered for escaped sequences
2111                     window.GetParent()->RemoveSubWindow(&window);
2112                     return eKeyHandled;
2113                     
2114                 default:
2115                 {
2116                     bool handled = false;
2117                     for (size_t i=0; i<num_submenus; ++i)
2118                     {
2119                         Menu *menu = submenus[i].get();
2120                         if (menu->GetKeyValue() == key)
2121                         {
2122                             handled = true;
2123                             SetSelectedSubmenuIndex(i);
2124                             window.GetParent()->RemoveSubWindow(&window);
2125                             if (menu->Action() == MenuActionResult::Quit)
2126                                 return eQuitApplication;
2127                             return eKeyHandled;
2128                         }
2129                     }
2130                 }
2131                     break;
2132                     
2133             }
2134         }
2135         else if (menu_type == Menu::Type::Separator)
2136         {
2137             
2138         }
2139         return result;
2140     }
2141
2142
2143     class Application
2144     {
2145     public:
2146         Application (FILE *in, FILE *out) :
2147             m_window_sp(),
2148             m_screen (NULL),
2149             m_in (in),
2150             m_out (out)
2151         {
2152             
2153         }
2154         
2155         ~Application ()
2156         {
2157             m_window_delegates.clear();
2158             m_window_sp.reset();
2159             if (m_screen)
2160             {
2161                 ::delscreen(m_screen);
2162                 m_screen = NULL;
2163             }
2164         }
2165         
2166         void
2167         Initialize ()
2168         {
2169             ::setlocale(LC_ALL, "");
2170             ::setlocale(LC_CTYPE, "");
2171 #if 0
2172             ::initscr();
2173 #else
2174             m_screen = ::newterm(NULL, m_out, m_in);
2175 #endif
2176             ::start_color();
2177             ::curs_set(0);
2178             ::noecho();
2179             ::keypad(stdscr,TRUE);
2180         }
2181         
2182         void
2183         Terminate ()
2184         {
2185             ::endwin();
2186         }
2187         
2188         void
2189         Run (Debugger &debugger)
2190         {
2191             bool done = false;
2192             int delay_in_tenths_of_a_second = 1;
2193             
2194             // Alas the threading model in curses is a bit lame so we need to
2195             // resort to polling every 0.5 seconds. We could poll for stdin
2196             // ourselves and then pass the keys down but then we need to
2197             // translate all of the escape sequences ourselves. So we resort to
2198             // polling for input because we need to receive async process events
2199             // while in this loop.
2200             
2201             halfdelay(delay_in_tenths_of_a_second); // Poll using some number of tenths of seconds seconds when calling Window::GetChar()
2202
2203             ListenerSP listener_sp (new Listener ("lldb.IOHandler.curses.Application"));
2204             ConstString broadcaster_class_target(Target::GetStaticBroadcasterClass());
2205             ConstString broadcaster_class_process(Process::GetStaticBroadcasterClass());
2206             ConstString broadcaster_class_thread(Thread::GetStaticBroadcasterClass());
2207             debugger.EnableForwardEvents (listener_sp);
2208
2209             bool update = true;
2210 #if defined(__APPLE__)
2211             std::deque<int> escape_chars;
2212 #endif
2213             
2214             while (!done)
2215             {
2216                 if (update)
2217                 {
2218                     m_window_sp->Draw(false);
2219                     // All windows should be calling Window::DeferredRefresh() instead
2220                     // of Window::Refresh() so we can do a single update and avoid
2221                     // any screen blinking
2222                     update_panels();
2223
2224                     // Cursor hiding isn't working on MacOSX, so hide it in the top left corner
2225                     m_window_sp->MoveCursor(0, 0);
2226
2227                     doupdate();
2228                     update = false;
2229                 }
2230                 
2231 #if defined(__APPLE__)
2232                 // Terminal.app doesn't map its function keys correctly, F1-F4 default to:
2233                 // \033OP, \033OQ, \033OR, \033OS, so lets take care of this here if possible
2234                 int ch;
2235                 if (escape_chars.empty())
2236                     ch = m_window_sp->GetChar();
2237                 else
2238                 {
2239                     ch = escape_chars.front();
2240                     escape_chars.pop_front();
2241                 }
2242                 if (ch == KEY_ESCAPE)
2243                 {
2244                     int ch2 = m_window_sp->GetChar();
2245                     if (ch2 == 'O')
2246                     {
2247                         int ch3 = m_window_sp->GetChar();
2248                         switch (ch3)
2249                         {
2250                             case 'P': ch = KEY_F(1); break;
2251                             case 'Q': ch = KEY_F(2); break;
2252                             case 'R': ch = KEY_F(3); break;
2253                             case 'S': ch = KEY_F(4); break;
2254                             default:
2255                                 escape_chars.push_back(ch2);
2256                                 if (ch3 != -1)
2257                                     escape_chars.push_back(ch3);
2258                                 break;
2259                         }
2260                     }
2261                     else if (ch2 != -1)
2262                         escape_chars.push_back(ch2);
2263                 }
2264 #else
2265                 int ch = m_window_sp->GetChar();
2266
2267 #endif
2268                 if (ch == -1)
2269                 {
2270                     if (feof(m_in) || ferror(m_in))
2271                     {
2272                         done = true;
2273                     }
2274                     else
2275                     {
2276                         // Just a timeout from using halfdelay(), check for events
2277                         EventSP event_sp;
2278                         while (listener_sp->PeekAtNextEvent())
2279                         {
2280                             listener_sp->GetNextEvent(event_sp);
2281                             
2282                             if (event_sp)
2283                             {
2284                                 Broadcaster *broadcaster = event_sp->GetBroadcaster();
2285                                 if (broadcaster)
2286                                 {
2287                                     //uint32_t event_type = event_sp->GetType();
2288                                     ConstString broadcaster_class (broadcaster->GetBroadcasterClass());
2289                                     if (broadcaster_class == broadcaster_class_process)
2290                                     {
2291                                         update = true;
2292                                         continue; // Don't get any key, just update our view
2293                                     }
2294                                 }
2295                             }
2296                         }
2297                     }
2298                 }
2299                 else
2300                 {
2301                     HandleCharResult key_result = m_window_sp->HandleChar(ch);
2302                     switch (key_result)
2303                     {
2304                         case eKeyHandled:
2305                             update = true;
2306                             break;
2307                         case eKeyNotHandled:
2308                             break;
2309                         case eQuitApplication:
2310                             done = true;
2311                             break;
2312                     }
2313                 }
2314             }
2315             
2316             debugger.CancelForwardEvents (listener_sp);
2317
2318         }
2319         
2320         WindowSP &
2321         GetMainWindow ()
2322         {
2323             if (!m_window_sp)
2324                 m_window_sp.reset (new Window ("main", stdscr, false));
2325             return m_window_sp;
2326         }
2327         
2328         WindowDelegates &
2329         GetWindowDelegates ()
2330         {
2331             return m_window_delegates;
2332         }
2333
2334     protected:
2335         WindowSP m_window_sp;
2336         WindowDelegates m_window_delegates;
2337         SCREEN *m_screen;
2338         FILE *m_in;
2339         FILE *m_out;
2340     };
2341     
2342
2343 } // namespace curses
2344
2345
2346 using namespace curses;
2347
2348 struct Row
2349 {
2350     ValueObjectSP valobj;
2351     Row *parent;
2352     int row_idx;
2353     int x;
2354     int y;
2355     bool might_have_children;
2356     bool expanded;
2357     bool calculated_children;
2358     std::vector<Row> children;
2359     
2360     Row (const ValueObjectSP &v, Row *p) :
2361     valobj (v),
2362     parent (p),
2363     row_idx(0),
2364     x(1),
2365     y(1),
2366     might_have_children (v ? v->MightHaveChildren() : false),
2367     expanded (false),
2368     calculated_children (false),
2369     children()
2370     {
2371     }
2372     
2373     size_t
2374     GetDepth () const
2375     {
2376         if (parent)
2377             return 1 + parent->GetDepth();
2378         return 0;
2379     }
2380     
2381     void
2382     Expand()
2383     {
2384         expanded = true;
2385         if (!calculated_children)
2386         {
2387             calculated_children = true;
2388             if (valobj)
2389             {
2390                 const size_t num_children = valobj->GetNumChildren();
2391                 for (size_t i=0; i<num_children; ++i)
2392                 {
2393                     children.push_back(Row (valobj->GetChildAtIndex(i, true), this));
2394                 }
2395             }
2396         }
2397     }
2398     
2399     void
2400     Unexpand ()
2401     {
2402         expanded = false;
2403     }
2404     
2405     void
2406     DrawTree (Window &window)
2407     {
2408         if (parent)
2409             parent->DrawTreeForChild (window, this, 0);
2410         
2411         if (might_have_children)
2412         {
2413             // It we can get UTF8 characters to work we should try to use the "symbol"
2414             // UTF8 string below
2415 //            const char *symbol = "";
2416 //            if (row.expanded)
2417 //                symbol = "\xe2\x96\xbd ";
2418 //            else
2419 //                symbol = "\xe2\x96\xb7 ";
2420 //            window.PutCString (symbol);
2421             
2422             // The ACS_DARROW and ACS_RARROW don't look very nice they are just a
2423             // 'v' or '>' character...
2424 //            if (expanded)
2425 //                window.PutChar (ACS_DARROW);
2426 //            else
2427 //                window.PutChar (ACS_RARROW);
2428             // Since we can't find any good looking right arrow/down arrow
2429             // symbols, just use a diamond...
2430             window.PutChar (ACS_DIAMOND);
2431             window.PutChar (ACS_HLINE);
2432         }
2433     }
2434
2435     void
2436     DrawTreeForChild (Window &window, Row *child, uint32_t reverse_depth)
2437     {
2438         if (parent)
2439             parent->DrawTreeForChild (window, this, reverse_depth + 1);
2440         
2441         if (&children.back() == child)
2442         {
2443             // Last child
2444             if (reverse_depth == 0)
2445             {
2446                 window.PutChar (ACS_LLCORNER);
2447                 window.PutChar (ACS_HLINE);
2448             }
2449             else
2450             {
2451                 window.PutChar (' ');
2452                 window.PutChar (' ');
2453             }
2454         }
2455         else
2456         {
2457             if (reverse_depth == 0)
2458             {
2459                 window.PutChar (ACS_LTEE);
2460                 window.PutChar (ACS_HLINE);
2461             }
2462             else
2463             {
2464                 window.PutChar (ACS_VLINE);
2465                 window.PutChar (' ');
2466             }
2467         }
2468     }
2469 };
2470
2471 struct DisplayOptions
2472 {
2473     bool show_types;
2474 };
2475
2476 class TreeItem;
2477
2478 class TreeDelegate
2479 {
2480 public:
2481     TreeDelegate() {}
2482     virtual ~TreeDelegate() {}
2483     virtual void TreeDelegateDrawTreeItem (TreeItem &item, Window &window) = 0;
2484     virtual void TreeDelegateGenerateChildren (TreeItem &item) = 0;
2485     virtual bool TreeDelegateItemSelected (TreeItem &item) = 0; // Return true if we need to update views
2486 };
2487 typedef std::shared_ptr<TreeDelegate> TreeDelegateSP;
2488
2489 class TreeItem
2490 {
2491 public:
2492     
2493     TreeItem (TreeItem *parent, TreeDelegate &delegate, bool might_have_children) :
2494         m_parent (parent),
2495         m_delegate (delegate),
2496         m_identifier (0),
2497         m_row_idx (-1),
2498         m_children (),
2499         m_might_have_children (might_have_children),
2500         m_is_expanded (false)
2501     {
2502     }
2503
2504     TreeItem &
2505     operator=(const TreeItem &rhs)
2506     {
2507         if (this != &rhs)
2508         {
2509             m_parent = rhs.m_parent;
2510             m_delegate = rhs.m_delegate;
2511             m_identifier = rhs.m_identifier;
2512             m_row_idx = rhs.m_row_idx;
2513             m_children = rhs.m_children;
2514             m_might_have_children = rhs.m_might_have_children;
2515             m_is_expanded = rhs.m_is_expanded;
2516         }
2517         return *this;
2518     }
2519
2520     size_t
2521     GetDepth () const
2522     {
2523         if (m_parent)
2524             return 1 + m_parent->GetDepth();
2525         return 0;
2526     }
2527     
2528     int
2529     GetRowIndex () const
2530     {
2531         return m_row_idx;
2532     }
2533
2534     void
2535     ClearChildren ()
2536     {
2537         m_children.clear();
2538     }
2539
2540     void
2541     Resize (size_t n, const TreeItem &t)
2542     {
2543         m_children.resize(n, t);
2544     }
2545     
2546     TreeItem &
2547     operator [](size_t i)
2548     {
2549         return m_children[i];
2550     }
2551
2552     void
2553     SetRowIndex (int row_idx)
2554     {
2555         m_row_idx = row_idx;
2556     }
2557
2558     size_t
2559     GetNumChildren ()
2560     {
2561         m_delegate.TreeDelegateGenerateChildren (*this);
2562         return m_children.size();
2563     }
2564
2565     void
2566     ItemWasSelected ()
2567     {
2568         m_delegate.TreeDelegateItemSelected(*this);
2569     }
2570     void
2571     CalculateRowIndexes (int &row_idx)
2572     {
2573         SetRowIndex(row_idx);
2574         ++row_idx;
2575
2576         // The root item must calculate its children
2577         if (m_parent == NULL)
2578             GetNumChildren();
2579         
2580         const bool expanded = IsExpanded();
2581         for (auto &item : m_children)
2582         {
2583             if (expanded)
2584                 item.CalculateRowIndexes(row_idx);
2585             else
2586                 item.SetRowIndex(-1);
2587         }
2588     }
2589
2590     TreeItem *
2591     GetParent ()
2592     {
2593         return m_parent;
2594     }
2595
2596     bool
2597     IsExpanded () const
2598     {
2599         return m_is_expanded;
2600     }
2601
2602     void
2603     Expand()
2604     {
2605         m_is_expanded = true;
2606     }
2607     
2608     void
2609     Unexpand ()
2610     {
2611         m_is_expanded = false;
2612     }
2613     
2614     bool
2615     Draw (Window &window,
2616           const int first_visible_row,
2617           const uint32_t selected_row_idx,
2618           int &row_idx,
2619           int &num_rows_left)
2620     {
2621         if (num_rows_left <= 0)
2622             return false;
2623
2624         if (m_row_idx >= first_visible_row)
2625         {
2626             window.MoveCursor(2, row_idx + 1);
2627
2628             if (m_parent)
2629                 m_parent->DrawTreeForChild (window, this, 0);
2630         
2631             if (m_might_have_children)
2632             {
2633                 // It we can get UTF8 characters to work we should try to use the "symbol"
2634                 // UTF8 string below
2635                 //            const char *symbol = "";
2636                 //            if (row.expanded)
2637                 //                symbol = "\xe2\x96\xbd ";
2638                 //            else
2639                 //                symbol = "\xe2\x96\xb7 ";
2640                 //            window.PutCString (symbol);
2641                 
2642                 // The ACS_DARROW and ACS_RARROW don't look very nice they are just a
2643                 // 'v' or '>' character...
2644                 //            if (expanded)
2645                 //                window.PutChar (ACS_DARROW);
2646                 //            else
2647                 //                window.PutChar (ACS_RARROW);
2648                 // Since we can't find any good looking right arrow/down arrow
2649                 // symbols, just use a diamond...
2650                 window.PutChar (ACS_DIAMOND);
2651                 window.PutChar (ACS_HLINE);
2652             }
2653             bool highlight = (selected_row_idx == m_row_idx) && window.IsActive();
2654
2655             if (highlight)
2656                 window.AttributeOn(A_REVERSE);
2657
2658             m_delegate.TreeDelegateDrawTreeItem(*this, window);
2659
2660             if (highlight)
2661                 window.AttributeOff(A_REVERSE);
2662             ++row_idx;
2663             --num_rows_left;
2664         }
2665
2666         if (num_rows_left <= 0)
2667             return false; // We are done drawing...
2668
2669         if (IsExpanded())
2670         {
2671             for (auto &item : m_children)
2672             {
2673                 // If we displayed all the rows and item.Draw() returns
2674                 // false we are done drawing and can exit this for loop
2675                 if (item.Draw(window, first_visible_row, selected_row_idx, row_idx, num_rows_left) == false)
2676                     break;
2677             }
2678         }
2679         return num_rows_left >= 0; // Return true if not done drawing yet
2680     }
2681     
2682     void
2683     DrawTreeForChild (Window &window, TreeItem *child, uint32_t reverse_depth)
2684     {
2685         if (m_parent)
2686             m_parent->DrawTreeForChild (window, this, reverse_depth + 1);
2687         
2688         if (&m_children.back() == child)
2689         {
2690             // Last child
2691             if (reverse_depth == 0)
2692             {
2693                 window.PutChar (ACS_LLCORNER);
2694                 window.PutChar (ACS_HLINE);
2695             }
2696             else
2697             {
2698                 window.PutChar (' ');
2699                 window.PutChar (' ');
2700             }
2701         }
2702         else
2703         {
2704             if (reverse_depth == 0)
2705             {
2706                 window.PutChar (ACS_LTEE);
2707                 window.PutChar (ACS_HLINE);
2708             }
2709             else
2710             {
2711                 window.PutChar (ACS_VLINE);
2712                 window.PutChar (' ');
2713             }
2714         }
2715     }
2716     
2717     TreeItem *
2718     GetItemForRowIndex (uint32_t row_idx)
2719     {
2720         if (m_row_idx == row_idx)
2721             return this;
2722         if (m_children.empty())
2723             return NULL;
2724         if (m_children.back().m_row_idx < row_idx)
2725             return NULL;
2726         if (IsExpanded())
2727         {
2728             for (auto &item : m_children)
2729             {
2730                 TreeItem *selected_item_ptr = item.GetItemForRowIndex(row_idx);
2731                 if (selected_item_ptr)
2732                     return selected_item_ptr;
2733             }
2734         }
2735         return NULL;
2736     }
2737     
2738 //    void *
2739 //    GetUserData() const
2740 //    {
2741 //        return m_user_data;
2742 //    }
2743 //    
2744 //    void
2745 //    SetUserData (void *user_data)
2746 //    {
2747 //        m_user_data = user_data;
2748 //    }
2749     uint64_t
2750     GetIdentifier() const
2751     {
2752         return m_identifier;
2753     }
2754     
2755     void
2756     SetIdentifier (uint64_t identifier)
2757     {
2758         m_identifier = identifier;
2759     }
2760     
2761
2762 protected:
2763     TreeItem *m_parent;
2764     TreeDelegate &m_delegate;
2765     //void *m_user_data;
2766     uint64_t m_identifier;
2767     int m_row_idx; // Zero based visible row index, -1 if not visible or for the root item
2768     std::vector<TreeItem> m_children;
2769     bool m_might_have_children;
2770     bool m_is_expanded;
2771
2772 };
2773
2774 class TreeWindowDelegate : public WindowDelegate
2775 {
2776 public:
2777     TreeWindowDelegate (Debugger &debugger, const TreeDelegateSP &delegate_sp) :
2778         m_debugger (debugger),
2779         m_delegate_sp (delegate_sp),
2780         m_root (NULL, *delegate_sp, true),
2781         m_selected_item (NULL),
2782         m_num_rows (0),
2783         m_selected_row_idx (0),
2784         m_first_visible_row (0),
2785         m_min_x (0),
2786         m_min_y (0),
2787         m_max_x (0),
2788         m_max_y (0)
2789     {
2790     }
2791     
2792     int
2793     NumVisibleRows () const
2794     {
2795         return m_max_y - m_min_y;
2796     }
2797
2798     virtual bool
2799     WindowDelegateDraw (Window &window, bool force)
2800     {
2801         ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
2802         Process *process = exe_ctx.GetProcessPtr();
2803         
2804         bool display_content = false;
2805         if (process)
2806         {
2807             StateType state = process->GetState();
2808             if (StateIsStoppedState(state, true))
2809             {
2810                 // We are stopped, so it is ok to
2811                 display_content = true;
2812             }
2813             else if (StateIsRunningState(state))
2814             {
2815                 return true; // Don't do any updating when we are running
2816             }
2817         }
2818
2819         m_min_x = 2;
2820         m_min_y = 1;
2821         m_max_x = window.GetWidth() - 1;
2822         m_max_y = window.GetHeight() - 1;
2823         
2824         window.Erase();
2825         window.DrawTitleBox (window.GetName());
2826
2827         if (display_content)
2828         {
2829             const int num_visible_rows = NumVisibleRows();
2830             m_num_rows = 0;
2831             m_root.CalculateRowIndexes(m_num_rows);
2832             
2833             // If we unexpanded while having something selected our
2834             // total number of rows is less than the num visible rows,
2835             // then make sure we show all the rows by setting the first
2836             // visible row accordingly.
2837             if (m_first_visible_row > 0 && m_num_rows < num_visible_rows)
2838                 m_first_visible_row = 0;
2839             
2840             // Make sure the selected row is always visible
2841             if (m_selected_row_idx < m_first_visible_row)
2842                 m_first_visible_row = m_selected_row_idx;
2843             else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
2844                 m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
2845             
2846             int row_idx = 0;
2847             int num_rows_left = num_visible_rows;
2848             m_root.Draw (window, m_first_visible_row, m_selected_row_idx, row_idx, num_rows_left);
2849             // Get the selected row
2850             m_selected_item = m_root.GetItemForRowIndex (m_selected_row_idx);
2851         }
2852         else
2853         {
2854             m_selected_item = NULL;
2855         }
2856         
2857         window.DeferredRefresh();
2858         
2859         
2860         return true; // Drawing handled
2861     }
2862     
2863     
2864     virtual const char *
2865     WindowDelegateGetHelpText ()
2866     {
2867         return "Thread window keyboard shortcuts:";
2868     }
2869     
2870     virtual KeyHelp *
2871     WindowDelegateGetKeyHelp ()
2872     {
2873         static curses::KeyHelp g_source_view_key_help[] = {
2874             { KEY_UP, "Select previous item" },
2875             { KEY_DOWN, "Select next item" },
2876             { KEY_RIGHT, "Expand the selected item" },
2877             { KEY_LEFT, "Unexpand the selected item or select parent if not expanded" },
2878             { KEY_PPAGE, "Page up" },
2879             { KEY_NPAGE, "Page down" },
2880             { 'h', "Show help dialog" },
2881             { ' ', "Toggle item expansion" },
2882             { ',', "Page up" },
2883             { '.', "Page down" },
2884             { '\0', NULL }
2885         };
2886         return g_source_view_key_help;
2887     }
2888     
2889     virtual HandleCharResult
2890     WindowDelegateHandleChar (Window &window, int c)
2891     {
2892         switch(c)
2893         {
2894             case ',':
2895             case KEY_PPAGE:
2896                 // Page up key
2897                 if (m_first_visible_row > 0)
2898                 {
2899                     if (m_first_visible_row > m_max_y)
2900                         m_first_visible_row -= m_max_y;
2901                     else
2902                         m_first_visible_row = 0;
2903                     m_selected_row_idx = m_first_visible_row;
2904                     m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
2905                     if (m_selected_item)
2906                         m_selected_item->ItemWasSelected ();
2907                 }
2908                 return eKeyHandled;
2909                 
2910             case '.':
2911             case KEY_NPAGE:
2912                 // Page down key
2913                 if (m_num_rows > m_max_y)
2914                 {
2915                     if (m_first_visible_row + m_max_y < m_num_rows)
2916                     {
2917                         m_first_visible_row += m_max_y;
2918                         m_selected_row_idx = m_first_visible_row;
2919                         m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
2920                         if (m_selected_item)
2921                             m_selected_item->ItemWasSelected ();
2922                     }
2923                 }
2924                 return eKeyHandled;
2925                 
2926             case KEY_UP:
2927                 if (m_selected_row_idx > 0)
2928                 {
2929                     --m_selected_row_idx;
2930                     m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
2931                     if (m_selected_item)
2932                         m_selected_item->ItemWasSelected ();
2933                 }
2934                 return eKeyHandled;
2935             case KEY_DOWN:
2936                 if (m_selected_row_idx + 1 < m_num_rows)
2937                 {
2938                     ++m_selected_row_idx;
2939                     m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
2940                     if (m_selected_item)
2941                         m_selected_item->ItemWasSelected ();
2942                 }
2943                 return eKeyHandled;
2944                 
2945             case KEY_RIGHT:
2946                 if (m_selected_item)
2947                 {
2948                     if (!m_selected_item->IsExpanded())
2949                         m_selected_item->Expand();
2950                 }
2951                 return eKeyHandled;
2952                 
2953             case KEY_LEFT:
2954                 if (m_selected_item)
2955                 {
2956                     if (m_selected_item->IsExpanded())
2957                         m_selected_item->Unexpand();
2958                     else if (m_selected_item->GetParent())
2959                     {
2960                         m_selected_row_idx = m_selected_item->GetParent()->GetRowIndex();
2961                         m_selected_item = m_root.GetItemForRowIndex(m_selected_row_idx);
2962                         if (m_selected_item)
2963                             m_selected_item->ItemWasSelected ();
2964                     }
2965                 }
2966                 return eKeyHandled;
2967                 
2968             case ' ':
2969                 // Toggle expansion state when SPACE is pressed
2970                 if (m_selected_item)
2971                 {
2972                     if (m_selected_item->IsExpanded())
2973                         m_selected_item->Unexpand();
2974                     else
2975                         m_selected_item->Expand();
2976                 }
2977                 return eKeyHandled;
2978                 
2979             case 'h':
2980                 window.CreateHelpSubwindow ();
2981                 return eKeyHandled;
2982                 
2983             default:
2984                 break;
2985         }
2986         return eKeyNotHandled;
2987     }
2988
2989 protected:
2990     Debugger &m_debugger;
2991     TreeDelegateSP m_delegate_sp;
2992     TreeItem m_root;
2993     TreeItem *m_selected_item;
2994     int m_num_rows;
2995     int m_selected_row_idx;
2996     int m_first_visible_row;
2997     int m_min_x;
2998     int m_min_y;
2999     int m_max_x;
3000     int m_max_y;
3001
3002 };
3003
3004 class FrameTreeDelegate : public TreeDelegate
3005 {
3006 public:
3007     FrameTreeDelegate (const ThreadSP &thread_sp) :
3008         TreeDelegate(),
3009         m_thread_wp()
3010     {
3011         if (thread_sp)
3012             m_thread_wp = thread_sp;
3013     }
3014     
3015     virtual ~FrameTreeDelegate()
3016     {
3017     }
3018     
3019     virtual void
3020     TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
3021     {
3022         ThreadSP thread_sp = m_thread_wp.lock();
3023         if (thread_sp)
3024         {
3025             const uint64_t frame_idx = item.GetIdentifier();
3026             StackFrameSP frame_sp = thread_sp->GetStackFrameAtIndex(frame_idx);
3027             if (frame_sp)
3028             {
3029                 StreamString strm;
3030                 const SymbolContext &sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
3031                 ExecutionContext exe_ctx (frame_sp);
3032                 //const char *frame_format = "frame #${frame.index}: ${module.file.basename}{`${function.name}${function.pc-offset}}}";
3033                 const char *frame_format = "frame #${frame.index}: {${function.name}${function.pc-offset}}}";
3034                 if (Debugger::FormatPrompt (frame_format, &sc, &exe_ctx, NULL, strm))
3035                 {
3036                     int right_pad = 1;
3037                     window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
3038                 }
3039             }
3040         }
3041     }
3042     virtual void
3043     TreeDelegateGenerateChildren (TreeItem &item)
3044     {
3045         // No children for frames yet...
3046     }
3047     
3048     virtual bool
3049     TreeDelegateItemSelected (TreeItem &item)
3050     {
3051         ThreadSP thread_sp = m_thread_wp.lock();
3052         if (thread_sp)
3053         {
3054             const uint64_t frame_idx = item.GetIdentifier();
3055             thread_sp->SetSelectedFrameByIndex(frame_idx);
3056             return true;
3057         }
3058         return false;
3059     }
3060     void
3061     SetThread (ThreadSP thread_sp)
3062     {
3063         m_thread_wp = thread_sp;
3064     }
3065     
3066 protected:
3067     ThreadWP m_thread_wp;
3068 };
3069
3070 class ThreadTreeDelegate : public TreeDelegate
3071 {
3072 public:
3073     ThreadTreeDelegate (Debugger &debugger) :
3074         TreeDelegate(),
3075         m_debugger (debugger),
3076         m_thread_wp (),
3077         m_tid (LLDB_INVALID_THREAD_ID),
3078         m_stop_id (UINT32_MAX)
3079     {
3080     }
3081     
3082     virtual
3083     ~ThreadTreeDelegate()
3084     {
3085     }
3086     
3087     virtual void
3088     TreeDelegateDrawTreeItem (TreeItem &item, Window &window)
3089     {
3090         ThreadSP thread_sp = m_thread_wp.lock();
3091         if (thread_sp)
3092         {
3093             StreamString strm;
3094             ExecutionContext exe_ctx (thread_sp);
3095             const char *format = "thread #${thread.index}: tid = ${thread.id}{, stop reason = ${thread.stop-reason}}";
3096             if (Debugger::FormatPrompt (format, NULL, &exe_ctx, NULL, strm))
3097             {
3098                 int right_pad = 1;
3099                 window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
3100             }
3101         }
3102     }
3103     virtual void
3104     TreeDelegateGenerateChildren (TreeItem &item)
3105     {
3106         TargetSP target_sp (m_debugger.GetSelectedTarget());
3107         if (target_sp)
3108         {
3109             ProcessSP process_sp = target_sp->GetProcessSP();
3110             if (process_sp && process_sp->IsAlive())
3111             {
3112                 StateType state = process_sp->GetState();
3113                 if (StateIsStoppedState(state, true))
3114                 {
3115                     ThreadSP thread_sp = process_sp->GetThreadList().GetSelectedThread();
3116                     if (thread_sp)
3117                     {
3118                         if (m_stop_id == process_sp->GetStopID() && thread_sp->GetID() == m_tid)
3119                             return; // Children are already up to date
3120                         if (m_frame_delegate_sp)
3121                             m_frame_delegate_sp->SetThread(thread_sp);
3122                         else
3123                         {
3124                             // Always expand the thread item the first time we show it
3125                             item.Expand();
3126                             m_frame_delegate_sp.reset (new FrameTreeDelegate(thread_sp));
3127                         }
3128
3129                         m_stop_id = process_sp->GetStopID();
3130                         m_thread_wp = thread_sp;
3131                         m_tid = thread_sp->GetID();
3132                         
3133                         TreeItem t (&item, *m_frame_delegate_sp, false);
3134                         size_t num_frames = thread_sp->GetStackFrameCount();
3135                         item.Resize (num_frames, t);
3136                         for (size_t i=0; i<num_frames; ++i)
3137                         {
3138                             item[i].SetIdentifier(i);
3139                         }
3140                     }
3141                     return;
3142                 }
3143             }
3144         }
3145         item.ClearChildren();
3146     }
3147     
3148     virtual bool
3149     TreeDelegateItemSelected (TreeItem &item)
3150     {
3151         ThreadSP thread_sp = m_thread_wp.lock();
3152         if (thread_sp)
3153         {
3154             ThreadList &thread_list = thread_sp->GetProcess()->GetThreadList();
3155             Mutex::Locker locker (thread_list.GetMutex());
3156             ThreadSP selected_thread_sp = thread_list.GetSelectedThread();
3157             if (selected_thread_sp->GetID() != thread_sp->GetID())
3158             {
3159                 thread_list.SetSelectedThreadByID(thread_sp->GetID());
3160                 return true;
3161             }
3162         }
3163         return false;
3164     }
3165
3166 protected:
3167     Debugger &m_debugger;
3168     ThreadWP m_thread_wp;
3169     std::shared_ptr<FrameTreeDelegate> m_frame_delegate_sp;
3170     lldb::user_id_t m_tid;
3171     uint32_t m_stop_id;
3172 };
3173
3174 class ValueObjectListDelegate : public WindowDelegate
3175 {
3176 public:
3177     ValueObjectListDelegate () :
3178         m_valobj_list (),
3179         m_rows (),
3180         m_selected_row (NULL),
3181         m_selected_row_idx (0),
3182         m_first_visible_row (0),
3183         m_num_rows (0),
3184         m_max_x (0),
3185         m_max_y (0)
3186     {
3187     }
3188     
3189     ValueObjectListDelegate (ValueObjectList &valobj_list) :
3190         m_valobj_list (valobj_list),
3191         m_rows (),
3192         m_selected_row (NULL),
3193         m_selected_row_idx (0),
3194         m_first_visible_row (0),
3195         m_num_rows (0),
3196         m_max_x (0),
3197         m_max_y (0)
3198     {
3199         SetValues (valobj_list);
3200     }
3201     
3202     virtual
3203     ~ValueObjectListDelegate()
3204     {
3205     }
3206
3207     void
3208     SetValues (ValueObjectList &valobj_list)
3209     {
3210         m_selected_row = NULL;
3211         m_selected_row_idx = 0;
3212         m_first_visible_row = 0;
3213         m_num_rows = 0;
3214         m_rows.clear();
3215         m_valobj_list = valobj_list;
3216         const size_t num_values = m_valobj_list.GetSize();
3217         for (size_t i=0; i<num_values; ++i)
3218             m_rows.push_back(Row(m_valobj_list.GetValueObjectAtIndex(i), NULL));
3219     }
3220     
3221     virtual bool
3222     WindowDelegateDraw (Window &window, bool force)
3223     {
3224         m_num_rows = 0;
3225         m_min_x = 2;
3226         m_min_y = 1;
3227         m_max_x = window.GetWidth() - 1;
3228         m_max_y = window.GetHeight() - 1;
3229         
3230         window.Erase();
3231         window.DrawTitleBox (window.GetName());
3232         
3233         const int num_visible_rows = NumVisibleRows();
3234         const int num_rows = CalculateTotalNumberRows (m_rows);
3235         
3236         // If we unexpanded while having something selected our
3237         // total number of rows is less than the num visible rows,
3238         // then make sure we show all the rows by setting the first
3239         // visible row accordingly.
3240         if (m_first_visible_row > 0 && num_rows < num_visible_rows)
3241             m_first_visible_row = 0;
3242         
3243         // Make sure the selected row is always visible
3244         if (m_selected_row_idx < m_first_visible_row)
3245             m_first_visible_row = m_selected_row_idx;
3246         else if (m_first_visible_row + num_visible_rows <= m_selected_row_idx)
3247             m_first_visible_row = m_selected_row_idx - num_visible_rows + 1;
3248         
3249         DisplayRows (window, m_rows, g_options);
3250         
3251         window.DeferredRefresh();
3252         
3253         // Get the selected row
3254         m_selected_row = GetRowForRowIndex (m_selected_row_idx);
3255         // Keep the cursor on the selected row so the highlight and the cursor
3256         // are always on the same line
3257         if (m_selected_row)
3258             window.MoveCursor (m_selected_row->x,
3259                                m_selected_row->y);
3260         
3261         return true; // Drawing handled
3262     }
3263     
3264     virtual KeyHelp *
3265     WindowDelegateGetKeyHelp ()
3266     {
3267         static curses::KeyHelp g_source_view_key_help[] = {
3268             { KEY_UP, "Select previous item" },
3269             { KEY_DOWN, "Select next item" },
3270             { KEY_RIGHT, "Expand selected item" },
3271             { KEY_LEFT, "Unexpand selected item or select parent if not expanded" },
3272             { KEY_PPAGE, "Page up" },
3273             { KEY_NPAGE, "Page down" },
3274             { 'A', "Format as annotated address" },
3275             { 'b', "Format as binary" },
3276             { 'B', "Format as hex bytes with ASCII" },
3277             { 'c', "Format as character" },
3278             { 'd', "Format as a signed integer" },
3279             { 'D', "Format selected value using the default format for the type" },
3280             { 'f', "Format as float" },
3281             { 'h', "Show help dialog" },
3282             { 'i', "Format as instructions" },
3283             { 'o', "Format as octal" },
3284             { 'p', "Format as pointer" },
3285             { 's', "Format as C string" },
3286             { 't', "Toggle showing/hiding type names" },
3287             { 'u', "Format as an unsigned integer" },
3288             { 'x', "Format as hex" },
3289             { 'X', "Format as uppercase hex" },
3290             { ' ', "Toggle item expansion" },
3291             { ',', "Page up" },
3292             { '.', "Page down" },
3293             { '\0', NULL }
3294         };
3295         return g_source_view_key_help;
3296     }
3297
3298     
3299     virtual HandleCharResult
3300     WindowDelegateHandleChar (Window &window, int c)
3301     {
3302         switch(c)
3303         {
3304             case 'x':
3305             case 'X':
3306             case 'o':
3307             case 's':
3308             case 'u':
3309             case 'd':
3310             case 'D':
3311             case 'i':
3312             case 'A':
3313             case 'p':
3314             case 'c':
3315             case 'b':
3316             case 'B':
3317             case 'f':
3318                 // Change the format for the currently selected item
3319                 if (m_selected_row)
3320                     m_selected_row->valobj->SetFormat (FormatForChar (c));
3321                 return eKeyHandled;
3322                 
3323             case 't':
3324                 // Toggle showing type names
3325                 g_options.show_types = !g_options.show_types;
3326                 return eKeyHandled;
3327                 
3328             case ',':
3329             case KEY_PPAGE:
3330                 // Page up key
3331                 if (m_first_visible_row > 0)
3332                 {
3333                     if (m_first_visible_row > m_max_y)
3334                         m_first_visible_row -= m_max_y;
3335                     else
3336                         m_first_visible_row = 0;
3337                     m_selected_row_idx = m_first_visible_row;
3338                 }
3339                 return eKeyHandled;
3340                 
3341             case '.':
3342             case KEY_NPAGE:
3343                 // Page down key
3344                 if (m_num_rows > m_max_y)
3345                 {
3346                     if (m_first_visible_row + m_max_y < m_num_rows)
3347                     {
3348                         m_first_visible_row += m_max_y;
3349                         m_selected_row_idx = m_first_visible_row;
3350                     }
3351                 }
3352                 return eKeyHandled;
3353                 
3354             case KEY_UP:
3355                 if (m_selected_row_idx > 0)
3356                     --m_selected_row_idx;
3357                 return eKeyHandled;
3358             case KEY_DOWN:
3359                 if (m_selected_row_idx + 1 < m_num_rows)
3360                     ++m_selected_row_idx;
3361                 return eKeyHandled;
3362                 
3363             case KEY_RIGHT:
3364                 if (m_selected_row)
3365                 {
3366                     if (!m_selected_row->expanded)
3367                         m_selected_row->Expand();
3368                 }
3369                 return eKeyHandled;
3370                 
3371             case KEY_LEFT:
3372                 if (m_selected_row)
3373                 {
3374                     if (m_selected_row->expanded)
3375                         m_selected_row->Unexpand();
3376                     else if (m_selected_row->parent)
3377                         m_selected_row_idx = m_selected_row->parent->row_idx;
3378                 }
3379                 return eKeyHandled;
3380                 
3381             case ' ':
3382                 // Toggle expansion state when SPACE is pressed
3383                 if (m_selected_row)
3384                 {
3385                     if (m_selected_row->expanded)
3386                         m_selected_row->Unexpand();
3387                     else
3388                         m_selected_row->Expand();
3389                 }
3390                 return eKeyHandled;
3391                 
3392             case 'h':
3393                 window.CreateHelpSubwindow ();
3394                 return eKeyHandled;
3395
3396             default:
3397                 break;
3398         }
3399         return eKeyNotHandled;
3400     }
3401     
3402 protected:
3403     ValueObjectList m_valobj_list;
3404     std::vector<Row> m_rows;
3405     Row *m_selected_row;
3406     uint32_t m_selected_row_idx;
3407     uint32_t m_first_visible_row;
3408     uint32_t m_num_rows;
3409     int m_min_x;
3410     int m_min_y;
3411     int m_max_x;
3412     int m_max_y;
3413
3414     static Format
3415     FormatForChar (int c)
3416     {
3417         switch (c)
3418         {
3419             case 'x': return eFormatHex;
3420             case 'X': return eFormatHexUppercase;
3421             case 'o': return eFormatOctal;
3422             case 's': return eFormatCString;
3423             case 'u': return eFormatUnsigned;
3424             case 'd': return eFormatDecimal;
3425             case 'D': return eFormatDefault;
3426             case 'i': return eFormatInstruction;
3427             case 'A': return eFormatAddressInfo;
3428             case 'p': return eFormatPointer;
3429             case 'c': return eFormatChar;
3430             case 'b': return eFormatBinary;
3431             case 'B': return eFormatBytesWithASCII;
3432             case 'f': return eFormatFloat;
3433         }
3434         return eFormatDefault;
3435     }
3436     
3437     bool
3438     DisplayRowObject (Window &window,
3439                       Row &row,
3440                       DisplayOptions &options,
3441                       bool highlight,
3442                       bool last_child)
3443     {
3444         ValueObject *valobj = row.valobj.get();
3445         
3446         if (valobj == NULL)
3447             return false;
3448     
3449         const char *type_name = options.show_types ? valobj->GetTypeName().GetCString() : NULL;
3450         const char *name = valobj->GetName().GetCString();
3451         const char *value = valobj->GetValueAsCString ();
3452         const char *summary = valobj->GetSummaryAsCString ();
3453         
3454         window.MoveCursor (row.x, row.y);
3455         
3456         row.DrawTree (window);
3457         
3458         if (highlight)
3459             window.AttributeOn(A_REVERSE);
3460         
3461         if (type_name && type_name[0])
3462             window.Printf ("(%s) ", type_name);
3463         
3464         if (name && name[0])
3465             window.PutCString(name);
3466         
3467         attr_t changd_attr = 0;
3468         if (valobj->GetValueDidChange())
3469             changd_attr = COLOR_PAIR(5) | A_BOLD;
3470         
3471         if (value && value[0])
3472         {
3473             window.PutCString(" = ");
3474             if (changd_attr)
3475                 window.AttributeOn(changd_attr);
3476             window.PutCString (value);
3477             if (changd_attr)
3478                 window.AttributeOff(changd_attr);
3479         }
3480         
3481         if (summary && summary[0])
3482         {
3483             window.PutChar(' ');
3484             if (changd_attr)
3485                 window.AttributeOn(changd_attr);
3486             window.PutCString(summary);
3487             if (changd_attr)
3488                 window.AttributeOff(changd_attr);
3489         }
3490         
3491         if (highlight)
3492             window.AttributeOff (A_REVERSE);
3493         
3494         return true;
3495     }
3496     void
3497     DisplayRows (Window &window,
3498                  std::vector<Row> &rows,
3499                  DisplayOptions &options)
3500     {
3501         // >   0x25B7
3502         // \/  0x25BD
3503         
3504         bool window_is_active = window.IsActive();
3505         for (auto &row : rows)
3506         {
3507             const bool last_child = row.parent && &rows[rows.size()-1] == &row;
3508             // Save the row index in each Row structure
3509             row.row_idx = m_num_rows;
3510             if ((m_num_rows >= m_first_visible_row) &&
3511                 ((m_num_rows - m_first_visible_row) < NumVisibleRows()))
3512             {
3513                 row.x = m_min_x;
3514                 row.y = m_num_rows - m_first_visible_row + 1;
3515                 if (DisplayRowObject (window,
3516                                       row,
3517                                       options,
3518                                       window_is_active && m_num_rows == m_selected_row_idx,
3519                                       last_child))
3520                 {
3521                     ++m_num_rows;
3522                 }
3523                 else
3524                 {
3525                     row.x = 0;
3526                     row.y = 0;
3527                 }
3528             }
3529             else
3530             {
3531                 row.x = 0;
3532                 row.y = 0;
3533                 ++m_num_rows;
3534             }
3535             
3536             if (row.expanded && !row.children.empty())
3537             {
3538                 DisplayRows (window,
3539                              row.children,
3540                              options);
3541             }
3542         }
3543     }
3544     
3545     int
3546     CalculateTotalNumberRows (const std::vector<Row> &rows)
3547     {
3548         int row_count = 0;
3549         for (const auto &row : rows)
3550         {
3551             ++row_count;
3552             if (row.expanded)
3553                 row_count += CalculateTotalNumberRows(row.children);
3554         }
3555         return row_count;
3556     }
3557     static Row *
3558     GetRowForRowIndexImpl (std::vector<Row> &rows, size_t &row_index)
3559     {
3560         for (auto &row : rows)
3561         {
3562             if (row_index == 0)
3563                 return &row;
3564             else
3565             {
3566                 --row_index;
3567                 if (row.expanded && !row.children.empty())
3568                 {
3569                     Row *result = GetRowForRowIndexImpl (row.children, row_index);
3570                     if (result)
3571                         return result;
3572                 }
3573             }
3574         }
3575         return NULL;
3576     }
3577     
3578     Row *
3579     GetRowForRowIndex (size_t row_index)
3580     {
3581         return GetRowForRowIndexImpl (m_rows, row_index);
3582     }
3583     
3584     int
3585     NumVisibleRows () const
3586     {
3587         return m_max_y - m_min_y;
3588     }
3589
3590     static DisplayOptions g_options;
3591 };
3592
3593 class FrameVariablesWindowDelegate : public ValueObjectListDelegate
3594 {
3595 public:
3596     FrameVariablesWindowDelegate (Debugger &debugger) :
3597         ValueObjectListDelegate (),
3598         m_debugger (debugger),
3599         m_frame_block (NULL)
3600     {
3601     }
3602     
3603     virtual
3604     ~FrameVariablesWindowDelegate()
3605     {
3606     }
3607     
3608     virtual const char *
3609     WindowDelegateGetHelpText ()
3610     {
3611         return "Frame variable window keyboard shortcuts:";
3612     }
3613     
3614     virtual bool
3615     WindowDelegateDraw (Window &window, bool force)
3616     {
3617         ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
3618         Process *process = exe_ctx.GetProcessPtr();
3619         Block *frame_block = NULL;
3620         StackFrame *frame = NULL;
3621         
3622         if (process)
3623         {
3624             StateType state = process->GetState();
3625             if (StateIsStoppedState(state, true))
3626             {
3627                 frame = exe_ctx.GetFramePtr();
3628                 if (frame)
3629                     frame_block = frame->GetFrameBlock ();
3630             }
3631             else if (StateIsRunningState(state))
3632             {
3633                 return true; // Don't do any updating when we are running
3634             }
3635         }
3636         
3637         ValueObjectList local_values;
3638         if (frame_block)
3639         {
3640             // Only update the variables if they have changed
3641             if (m_frame_block != frame_block)
3642             {
3643                 m_frame_block = frame_block;
3644
3645                 VariableList *locals = frame->GetVariableList(true);
3646                 if (locals)
3647                 {
3648                     const DynamicValueType use_dynamic = eDynamicDontRunTarget;
3649                     const size_t num_locals = locals->GetSize();
3650                     for (size_t i=0; i<num_locals; ++i)
3651                         local_values.Append(frame->GetValueObjectForFrameVariable (locals->GetVariableAtIndex(i), use_dynamic));
3652                     // Update the values
3653                     SetValues(local_values);
3654                 }
3655             }
3656         }
3657         else
3658         {
3659             m_frame_block = NULL;
3660             // Update the values with an empty list if there is no frame
3661             SetValues(local_values);
3662         }
3663         
3664         return ValueObjectListDelegate::WindowDelegateDraw (window, force);
3665
3666     }
3667
3668 protected:
3669     Debugger &m_debugger;
3670     Block *m_frame_block;
3671 };
3672
3673
3674 class RegistersWindowDelegate : public ValueObjectListDelegate
3675 {
3676 public:
3677     RegistersWindowDelegate (Debugger &debugger) :
3678         ValueObjectListDelegate (),
3679         m_debugger (debugger)
3680     {
3681     }
3682     
3683     virtual
3684     ~RegistersWindowDelegate()
3685     {
3686     }
3687     
3688     virtual const char *
3689     WindowDelegateGetHelpText ()
3690     {
3691         return "Register window keyboard shortcuts:";
3692     }
3693
3694     virtual bool
3695     WindowDelegateDraw (Window &window, bool force)
3696     {
3697         ExecutionContext exe_ctx (m_debugger.GetCommandInterpreter().GetExecutionContext());
3698         StackFrame *frame = exe_ctx.GetFramePtr();
3699         
3700         ValueObjectList value_list;
3701         if (frame)
3702         {
3703             if (frame->GetStackID() != m_stack_id)
3704             {
3705                 m_stack_id = frame->GetStackID();
3706                 RegisterContextSP reg_ctx (frame->GetRegisterContext());
3707                 if (reg_ctx)
3708                 {
3709                     const uint32_t num_sets = reg_ctx->GetRegisterSetCount();
3710                     for (uint32_t set_idx = 0; set_idx < num_sets; ++set_idx)
3711                     {
3712                         value_list.Append(ValueObjectRegisterSet::Create (frame, reg_ctx, set_idx));
3713                     }
3714                 }
3715                 SetValues(value_list);
3716             }
3717         }
3718         else
3719         {
3720             Process *process = exe_ctx.GetProcessPtr();
3721             if (process && process->IsAlive())
3722                 return true; // Don't do any updating if we are running
3723             else
3724             {
3725                 // Update the values with an empty list if there
3726                 // is no process or the process isn't alive anymore
3727                 SetValues(value_list);
3728             }
3729         }
3730         return ValueObjectListDelegate::WindowDelegateDraw (window, force);
3731     }
3732     
3733 protected:
3734     Debugger &m_debugger;
3735     StackID m_stack_id;
3736 };
3737
3738 static const char *
3739 CursesKeyToCString (int ch)
3740 {
3741     static char g_desc[32];
3742     if (ch >= KEY_F0 && ch < KEY_F0 + 64)
3743     {
3744         snprintf(g_desc, sizeof(g_desc), "F%u", ch - KEY_F0);
3745         return g_desc;
3746     }
3747     switch (ch)
3748     {
3749         case KEY_DOWN:  return "down";
3750         case KEY_UP:    return "up";
3751         case KEY_LEFT:  return "left";
3752         case KEY_RIGHT: return "right";
3753         case KEY_HOME:  return "home";
3754         case KEY_BACKSPACE: return "backspace";
3755         case KEY_DL:        return "delete-line";
3756         case KEY_IL:        return "insert-line";
3757         case KEY_DC:        return "delete-char";
3758         case KEY_IC:        return "insert-char";
3759         case KEY_CLEAR:     return "clear";
3760         case KEY_EOS:       return "clear-to-eos";
3761         case KEY_EOL:       return "clear-to-eol";
3762         case KEY_SF:        return "scroll-forward";
3763         case KEY_SR:        return "scroll-backward";
3764         case KEY_NPAGE:     return "page-down";
3765         case KEY_PPAGE:     return "page-up";
3766         case KEY_STAB:      return "set-tab";
3767         case KEY_CTAB:      return "clear-tab";
3768         case KEY_CATAB:     return "clear-all-tabs";
3769         case KEY_ENTER:     return "enter";
3770         case KEY_PRINT:     return "print";
3771         case KEY_LL:        return "lower-left key";
3772         case KEY_A1:        return "upper left of keypad";
3773         case KEY_A3:        return "upper right of keypad";
3774         case KEY_B2:        return "center of keypad";
3775         case KEY_C1:        return "lower left of keypad";
3776         case KEY_C3:        return "lower right of keypad";
3777         case KEY_BTAB:      return "back-tab key";
3778         case KEY_BEG:       return "begin key";
3779         case KEY_CANCEL:    return "cancel key";
3780         case KEY_CLOSE:     return "close key";
3781         case KEY_COMMAND:   return "command key";
3782         case KEY_COPY:      return "copy key";
3783         case KEY_CREATE:    return "create key";
3784         case KEY_END:       return "end key";
3785         case KEY_EXIT:      return "exit key";
3786         case KEY_FIND:      return "find key";
3787         case KEY_HELP:      return "help key";
3788         case KEY_MARK:      return "mark key";
3789         case KEY_MESSAGE:   return "message key";
3790         case KEY_MOVE:      return "move key";
3791         case KEY_NEXT:      return "next key";
3792         case KEY_OPEN:      return "open key";
3793         case KEY_OPTIONS:   return "options key";
3794         case KEY_PREVIOUS:  return "previous key";
3795         case KEY_REDO:      return "redo key";
3796         case KEY_REFERENCE: return "reference key";
3797         case KEY_REFRESH:   return "refresh key";
3798         case KEY_REPLACE:   return "replace key";
3799         case KEY_RESTART:   return "restart key";
3800         case KEY_RESUME:    return "resume key";
3801         case KEY_SAVE:      return "save key";
3802         case KEY_SBEG:      return "shifted begin key";
3803         case KEY_SCANCEL:   return "shifted cancel key";
3804         case KEY_SCOMMAND:  return "shifted command key";
3805         case KEY_SCOPY:     return "shifted copy key";
3806         case KEY_SCREATE:   return "shifted create key";
3807         case KEY_SDC:       return "shifted delete-character key";
3808         case KEY_SDL:       return "shifted delete-line key";
3809         case KEY_SELECT:    return "select key";
3810         case KEY_SEND:      return "shifted end key";
3811         case KEY_SEOL:      return "shifted clear-to-end-of-line key";
3812         case KEY_SEXIT:     return "shifted exit key";
3813         case KEY_SFIND:     return "shifted find key";
3814         case KEY_SHELP:     return "shifted help key";
3815         case KEY_SHOME:     return "shifted home key";
3816         case KEY_SIC:       return "shifted insert-character key";
3817         case KEY_SLEFT:     return "shifted left-arrow key";
3818         case KEY_SMESSAGE:  return "shifted message key";
3819         case KEY_SMOVE:     return "shifted move key";
3820         case KEY_SNEXT:     return "shifted next key";
3821         case KEY_SOPTIONS:  return "shifted options key";
3822         case KEY_SPREVIOUS: return "shifted previous key";
3823         case KEY_SPRINT:    return "shifted print key";
3824         case KEY_SREDO:     return "shifted redo key";
3825         case KEY_SREPLACE:  return "shifted replace key";
3826         case KEY_SRIGHT:    return "shifted right-arrow key";
3827         case KEY_SRSUME:    return "shifted resume key";
3828         case KEY_SSAVE:     return "shifted save key";
3829         case KEY_SSUSPEND:  return "shifted suspend key";
3830         case KEY_SUNDO:     return "shifted undo key";
3831         case KEY_SUSPEND:   return "suspend key";
3832         case KEY_UNDO:      return "undo key";
3833         case KEY_MOUSE:     return "Mouse event has occurred";
3834         case KEY_RESIZE:    return "Terminal resize event";
3835         case KEY_EVENT:     return "We were interrupted by an event";
3836         case KEY_RETURN:    return "return";
3837         case ' ':           return "space";
3838         case '\t':          return "tab";
3839         case KEY_ESCAPE:    return "escape";
3840         default:
3841             if (isprint(ch))
3842                 snprintf(g_desc, sizeof(g_desc), "%c", ch);
3843             else
3844                 snprintf(g_desc, sizeof(g_desc), "\\x%2.2x", ch);
3845             return g_desc;
3846     }
3847     return NULL;
3848 }
3849
3850 HelpDialogDelegate::HelpDialogDelegate (const char *text, KeyHelp *key_help_array) :
3851     m_text (),
3852     m_first_visible_line (0)
3853 {
3854     if (text && text[0])
3855     {
3856         m_text.SplitIntoLines(text);
3857         m_text.AppendString("");
3858     }
3859     if (key_help_array)
3860     {
3861         for (KeyHelp *key = key_help_array; key->ch; ++key)
3862         {
3863             StreamString key_description;
3864             key_description.Printf("%10s - %s", CursesKeyToCString(key->ch), key->description);
3865             m_text.AppendString(std::move(key_description.GetString()));
3866         }
3867     }
3868 }
3869
3870 HelpDialogDelegate::~HelpDialogDelegate()
3871 {
3872 }
3873     
3874 bool
3875 HelpDialogDelegate::WindowDelegateDraw (Window &window, bool force)
3876 {
3877     window.Erase();
3878     const int window_height = window.GetHeight();
3879     int x = 2;
3880     int y = 1;
3881     const int min_y = y;
3882     const int max_y = window_height - 1 - y;
3883     const int num_visible_lines = max_y - min_y + 1;
3884     const size_t num_lines = m_text.GetSize();
3885     const char *bottom_message;
3886     if (num_lines <= num_visible_lines)
3887         bottom_message = "Press any key to exit";
3888     else
3889         bottom_message = "Use arrows to scroll, any other key to exit";
3890     window.DrawTitleBox(window.GetName(), bottom_message);
3891     while (y <= max_y)
3892     {
3893         window.MoveCursor(x, y);
3894         window.PutCStringTruncated(m_text.GetStringAtIndex(m_first_visible_line + y - min_y), 1);
3895         ++y;
3896     }
3897     return true;
3898 }
3899
3900 HandleCharResult
3901 HelpDialogDelegate::WindowDelegateHandleChar (Window &window, int key)
3902 {
3903     bool done = false;
3904     const size_t num_lines = m_text.GetSize();
3905     const size_t num_visible_lines = window.GetHeight() - 2;
3906     
3907     if (num_lines <= num_visible_lines)
3908     {
3909         done = true;
3910         // If we have all lines visible and don't need scrolling, then any
3911         // key press will cause us to exit
3912     }
3913     else
3914     {
3915         switch (key)
3916         {
3917             case KEY_UP:
3918                 if (m_first_visible_line > 0)
3919                     --m_first_visible_line;
3920                 break;
3921
3922             case KEY_DOWN:
3923                 if (m_first_visible_line + num_visible_lines < num_lines)
3924                     ++m_first_visible_line;
3925                 break;
3926
3927             case KEY_PPAGE:
3928             case ',':
3929                 if (m_first_visible_line > 0)
3930                 {
3931                     if (m_first_visible_line >= num_visible_lines)
3932                         m_first_visible_line -= num_visible_lines;
3933                     else
3934                         m_first_visible_line = 0;
3935                 }
3936                 break;
3937             case KEY_NPAGE:
3938             case '.':
3939                 if (m_first_visible_line + num_visible_lines < num_lines)
3940                 {
3941                     m_first_visible_line += num_visible_lines;
3942                     if (m_first_visible_line > num_lines)
3943                         m_first_visible_line = num_lines - num_visible_lines;
3944                 }
3945                 break;
3946             default:
3947                 done = true;
3948                 break;
3949         }
3950     }
3951     if (done)
3952         window.GetParent()->RemoveSubWindow(&window);
3953     return eKeyHandled;
3954 }
3955
3956 class ApplicationDelegate :
3957     public WindowDelegate,
3958     public MenuDelegate
3959 {
3960 public:
3961     enum {
3962         eMenuID_LLDB = 1,
3963         eMenuID_LLDBAbout,
3964         eMenuID_LLDBExit,
3965         
3966         eMenuID_Target,
3967         eMenuID_TargetCreate,
3968         eMenuID_TargetDelete,
3969         
3970         eMenuID_Process,
3971         eMenuID_ProcessAttach,
3972         eMenuID_ProcessDetach,
3973         eMenuID_ProcessLaunch,
3974         eMenuID_ProcessContinue,
3975         eMenuID_ProcessHalt,
3976         eMenuID_ProcessKill,
3977         
3978         eMenuID_Thread,
3979         eMenuID_ThreadStepIn,
3980         eMenuID_ThreadStepOver,
3981         eMenuID_ThreadStepOut,
3982         
3983         eMenuID_View,
3984         eMenuID_ViewBacktrace,
3985         eMenuID_ViewRegisters,
3986         eMenuID_ViewSource,
3987         eMenuID_ViewVariables,
3988         
3989         eMenuID_Help,
3990         eMenuID_HelpGUIHelp
3991     };
3992
3993     ApplicationDelegate (Application &app, Debugger &debugger) :
3994         WindowDelegate (),
3995         MenuDelegate (),
3996         m_app (app),
3997         m_debugger (debugger)
3998     {
3999     }
4000     
4001     virtual
4002     ~ApplicationDelegate ()
4003     {
4004     }
4005     virtual bool
4006     WindowDelegateDraw (Window &window, bool force)
4007     {
4008         return false; // Drawing not handled, let standard window drawing happen
4009     }
4010     
4011     virtual HandleCharResult
4012     WindowDelegateHandleChar (Window &window, int key)
4013     {
4014         switch (key)
4015         {
4016             case '\t':
4017                 window.SelectNextWindowAsActive();
4018                 return eKeyHandled;
4019
4020             case 'h':
4021                 window.CreateHelpSubwindow();
4022                 return eKeyHandled;
4023
4024             case KEY_ESCAPE:
4025                 return eQuitApplication;
4026
4027             default:
4028                 break;
4029         }
4030         return eKeyNotHandled;
4031     }
4032     
4033     
4034     virtual const char *
4035     WindowDelegateGetHelpText ()
4036     {
4037         return "Welcome to the LLDB curses GUI.\n\n"
4038         "Press the TAB key to change the selected view.\n"
4039         "Each view has its own keyboard shortcuts, press 'h' to open a dialog to display them.\n\n"
4040         "Common key bindings for all views:";
4041     }
4042     
4043     virtual KeyHelp *
4044     WindowDelegateGetKeyHelp ()
4045     {
4046         static curses::KeyHelp g_source_view_key_help[] = {
4047             { '\t', "Select next view" },
4048             { 'h', "Show help dialog with view specific key bindings" },
4049             { ',', "Page up" },
4050             { '.', "Page down" },
4051             { KEY_UP, "Select previous" },
4052             { KEY_DOWN, "Select next" },
4053             { KEY_LEFT, "Unexpand or select parent" },
4054             { KEY_RIGHT, "Expand" },
4055             { KEY_PPAGE, "Page up" },
4056             { KEY_NPAGE, "Page down" },
4057             { '\0', NULL }
4058         };
4059         return g_source_view_key_help;
4060     }
4061     
4062     virtual MenuActionResult
4063     MenuDelegateAction (Menu &menu)
4064     {
4065         switch (menu.GetIdentifier())
4066         {
4067             case eMenuID_ThreadStepIn:
4068                 {
4069                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4070                     if (exe_ctx.HasThreadScope())
4071                     {
4072                         Process *process = exe_ctx.GetProcessPtr();
4073                         if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
4074                             exe_ctx.GetThreadRef().StepIn(true, true);
4075                     }
4076                 }
4077                 return MenuActionResult::Handled;
4078                 
4079             case eMenuID_ThreadStepOut:
4080                 {
4081                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4082                     if (exe_ctx.HasThreadScope())
4083                     {
4084                         Process *process = exe_ctx.GetProcessPtr();
4085                         if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
4086                             exe_ctx.GetThreadRef().StepOut();
4087                     }
4088                 }
4089                 return MenuActionResult::Handled;
4090                 
4091             case eMenuID_ThreadStepOver:
4092                 {
4093                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4094                     if (exe_ctx.HasThreadScope())
4095                     {
4096                         Process *process = exe_ctx.GetProcessPtr();
4097                         if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
4098                             exe_ctx.GetThreadRef().StepOver(true);
4099                     }
4100                 }
4101                 return MenuActionResult::Handled;
4102
4103             case eMenuID_ProcessContinue:
4104                 {
4105                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4106                     if (exe_ctx.HasProcessScope())
4107                     {
4108                         Process *process = exe_ctx.GetProcessPtr();
4109                         if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
4110                             process->Resume();
4111                     }
4112                 }
4113                 return MenuActionResult::Handled;
4114
4115             case eMenuID_ProcessKill:
4116                 {
4117                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4118                     if (exe_ctx.HasProcessScope())
4119                     {
4120                         Process *process = exe_ctx.GetProcessPtr();
4121                         if (process && process->IsAlive())
4122                             process->Destroy();
4123                     }
4124                 }
4125                 return MenuActionResult::Handled;
4126
4127             case eMenuID_ProcessHalt:
4128                 {
4129                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4130                     if (exe_ctx.HasProcessScope())
4131                     {
4132                         Process *process = exe_ctx.GetProcessPtr();
4133                         if (process && process->IsAlive())
4134                             process->Halt();
4135                     }
4136                 }
4137                 return MenuActionResult::Handled;
4138
4139             case eMenuID_ProcessDetach:
4140                 {
4141                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4142                     if (exe_ctx.HasProcessScope())
4143                     {
4144                         Process *process = exe_ctx.GetProcessPtr();
4145                         if (process && process->IsAlive())
4146                             process->Detach(false);
4147                     }
4148                 }
4149                 return MenuActionResult::Handled;
4150
4151             case eMenuID_Process:
4152                 {
4153                     // Populate the menu with all of the threads if the process is stopped when
4154                     // the Process menu gets selected and is about to display its submenu.
4155                     Menus &submenus = menu.GetSubmenus();
4156                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4157                     Process *process = exe_ctx.GetProcessPtr();
4158                     if (process && process->IsAlive() && StateIsStoppedState (process->GetState(), true))
4159                     {
4160                         if (submenus.size() == 7)
4161                             menu.AddSubmenu (MenuSP (new Menu(Menu::Type::Separator)));
4162                         else if (submenus.size() > 8)
4163                             submenus.erase (submenus.begin() + 8, submenus.end());
4164                         
4165                         ThreadList &threads = process->GetThreadList();
4166                         Mutex::Locker locker (threads.GetMutex());
4167                         size_t num_threads = threads.GetSize();
4168                         for (size_t i=0; i<num_threads; ++i)
4169                         {
4170                             ThreadSP thread_sp = threads.GetThreadAtIndex(i);
4171                             char menu_char = '\0';
4172                             if (i < 9)
4173                                 menu_char = '1' + i;
4174                             StreamString thread_menu_title;
4175                             thread_menu_title.Printf("Thread %u", thread_sp->GetIndexID());
4176                             const char *thread_name = thread_sp->GetName();
4177                             if (thread_name && thread_name[0])
4178                                 thread_menu_title.Printf (" %s", thread_name);
4179                             else
4180                             {
4181                                 const char *queue_name = thread_sp->GetQueueName();
4182                                 if (queue_name && queue_name[0])
4183                                     thread_menu_title.Printf (" %s", queue_name);
4184                             }
4185                             menu.AddSubmenu (MenuSP (new Menu(thread_menu_title.GetString().c_str(), NULL, menu_char, thread_sp->GetID())));
4186                         }
4187                     }
4188                     else if (submenus.size() > 7)
4189                     {
4190                         // Remove the separator and any other thread submenu items
4191                         // that were previously added
4192                         submenus.erase (submenus.begin() + 7, submenus.end());
4193                     }
4194                     // Since we are adding and removing items we need to recalculate the name lengths
4195                     menu.RecalculateNameLengths();
4196                 }
4197                 return MenuActionResult::Handled;
4198                 
4199             case eMenuID_ViewVariables:
4200                 {
4201                     WindowSP main_window_sp = m_app.GetMainWindow();
4202                     WindowSP source_window_sp = main_window_sp->FindSubWindow("Source");
4203                     WindowSP variables_window_sp = main_window_sp->FindSubWindow("Variables");
4204                     WindowSP registers_window_sp = main_window_sp->FindSubWindow("Registers");
4205                     const Rect source_bounds = source_window_sp->GetBounds();
4206
4207                     if (variables_window_sp)
4208                     {
4209                         const Rect variables_bounds = variables_window_sp->GetBounds();
4210
4211                         main_window_sp->RemoveSubWindow(variables_window_sp.get());
4212
4213                         if (registers_window_sp)
4214                         {
4215                             // We have a registers window, so give all the area back to the registers window
4216                             Rect registers_bounds = variables_bounds;
4217                             registers_bounds.size.width = source_bounds.size.width;
4218                             registers_window_sp->SetBounds(registers_bounds);
4219                         }
4220                         else
4221                         {
4222                             // We have no registers window showing so give the bottom
4223                             // area back to the source view
4224                             source_window_sp->Resize (source_bounds.size.width,
4225                                                       source_bounds.size.height + variables_bounds.size.height);
4226                         }
4227                     }
4228                     else
4229                     {
4230                         Rect new_variables_rect;
4231                         if (registers_window_sp)
4232                         {
4233                             // We have a registers window so split the area of the registers
4234                             // window into two columns where the left hand side will be the
4235                             // variables and the right hand side will be the registers
4236                             const Rect variables_bounds = registers_window_sp->GetBounds();
4237                             Rect new_registers_rect;
4238                             variables_bounds.VerticalSplitPercentage (0.50, new_variables_rect, new_registers_rect);
4239                             registers_window_sp->SetBounds (new_registers_rect);
4240                         }
4241                         else
4242                         {
4243                             // No variables window, grab the bottom part of the source window
4244                             Rect new_source_rect;
4245                             source_bounds.HorizontalSplitPercentage (0.70, new_source_rect, new_variables_rect);
4246                             source_window_sp->SetBounds (new_source_rect);
4247                         }
4248                         WindowSP new_window_sp = main_window_sp->CreateSubWindow ("Variables",
4249                                                                                   new_variables_rect,
4250                                                                                   false);
4251                         new_window_sp->SetDelegate (WindowDelegateSP(new FrameVariablesWindowDelegate(m_debugger)));
4252                     }
4253                     touchwin(stdscr);
4254                 }
4255                 return MenuActionResult::Handled;
4256
4257             case eMenuID_ViewRegisters:
4258                 {
4259                     WindowSP main_window_sp = m_app.GetMainWindow();
4260                     WindowSP source_window_sp = main_window_sp->FindSubWindow("Source");
4261                     WindowSP variables_window_sp = main_window_sp->FindSubWindow("Variables");
4262                     WindowSP registers_window_sp = main_window_sp->FindSubWindow("Registers");
4263                     const Rect source_bounds = source_window_sp->GetBounds();
4264
4265                     if (registers_window_sp)
4266                     {
4267                         if (variables_window_sp)
4268                         {
4269                             const Rect variables_bounds = variables_window_sp->GetBounds();
4270
4271                             // We have a variables window, so give all the area back to the variables window
4272                             variables_window_sp->Resize (variables_bounds.size.width + registers_window_sp->GetWidth(),
4273                                                          variables_bounds.size.height);
4274                         }
4275                         else
4276                         {
4277                             // We have no variables window showing so give the bottom
4278                             // area back to the source view
4279                             source_window_sp->Resize (source_bounds.size.width,
4280                                                       source_bounds.size.height + registers_window_sp->GetHeight());
4281                         }
4282                         main_window_sp->RemoveSubWindow(registers_window_sp.get());
4283                     }
4284                     else
4285                     {
4286                         Rect new_regs_rect;
4287                         if (variables_window_sp)
4288                         {
4289                             // We have a variables window, split it into two columns
4290                             // where the left hand side will be the variables and the
4291                             // right hand side will be the registers
4292                             const Rect variables_bounds = variables_window_sp->GetBounds();
4293                             Rect new_vars_rect;
4294                             variables_bounds.VerticalSplitPercentage (0.50, new_vars_rect, new_regs_rect);
4295                             variables_window_sp->SetBounds (new_vars_rect);
4296                         }
4297                         else
4298                         {
4299                             // No registers window, grab the bottom part of the source window
4300                             Rect new_source_rect;
4301                             source_bounds.HorizontalSplitPercentage (0.70, new_source_rect, new_regs_rect);
4302                             source_window_sp->SetBounds (new_source_rect);
4303                         }
4304                         WindowSP new_window_sp = main_window_sp->CreateSubWindow ("Registers",
4305                                                                                   new_regs_rect,
4306                                                                                   false);
4307                         new_window_sp->SetDelegate (WindowDelegateSP(new RegistersWindowDelegate(m_debugger)));
4308                     }
4309                     touchwin(stdscr);
4310                 }
4311                 return MenuActionResult::Handled;
4312                 
4313             case eMenuID_HelpGUIHelp:
4314                 m_app.GetMainWindow ()->CreateHelpSubwindow();
4315                 return MenuActionResult::Handled;
4316         
4317             default:
4318                 break;
4319         }
4320
4321         return MenuActionResult::NotHandled;
4322     }
4323 protected:
4324     Application &m_app;
4325     Debugger &m_debugger;
4326 };
4327
4328
4329 class StatusBarWindowDelegate : public WindowDelegate
4330 {
4331 public:
4332     StatusBarWindowDelegate (Debugger &debugger) :
4333         m_debugger (debugger)
4334     {
4335     }
4336     
4337     virtual
4338     ~StatusBarWindowDelegate ()
4339     {
4340     }
4341     virtual bool
4342     WindowDelegateDraw (Window &window, bool force)
4343     {
4344         ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4345         Process *process = exe_ctx.GetProcessPtr();
4346         Thread *thread = exe_ctx.GetThreadPtr();
4347         StackFrame *frame = exe_ctx.GetFramePtr();
4348         window.Erase();
4349         window.SetBackground(2);
4350         window.MoveCursor (0, 0);
4351         if (process)
4352         {
4353             const StateType state = process->GetState();
4354             window.Printf ("Process: %5" PRIu64 " %10s", process->GetID(), StateAsCString(state));
4355
4356             if (StateIsStoppedState(state, true))
4357             {
4358                 window.MoveCursor (40, 0);
4359                 if (thread)
4360                     window.Printf ("Thread: 0x%4.4" PRIx64, thread->GetID());
4361
4362                 window.MoveCursor (60, 0);
4363                 if (frame)
4364                     window.Printf ("Frame: %3u  PC = 0x%16.16" PRIx64, frame->GetFrameIndex(), frame->GetFrameCodeAddress().GetOpcodeLoadAddress (exe_ctx.GetTargetPtr()));
4365             }
4366             else if (state == eStateExited)
4367             {
4368                 const char *exit_desc = process->GetExitDescription();
4369                 const int exit_status = process->GetExitStatus();
4370                 if (exit_desc && exit_desc[0])
4371                     window.Printf (" with status = %i (%s)", exit_status, exit_desc);
4372                 else
4373                     window.Printf (" with status = %i", exit_status);
4374             }
4375         }
4376         window.DeferredRefresh();
4377         return true;
4378     }
4379
4380 protected:
4381     Debugger &m_debugger;
4382 };
4383
4384 class SourceFileWindowDelegate : public WindowDelegate
4385 {
4386 public:
4387     SourceFileWindowDelegate (Debugger &debugger) :
4388         WindowDelegate (),
4389         m_debugger (debugger),
4390         m_sc (),
4391         m_file_sp (),
4392         m_disassembly_scope (NULL),
4393         m_disassembly_sp (),
4394         m_disassembly_range (),
4395         m_line_width (4),
4396         m_selected_line (0),
4397         m_pc_line (0),
4398         m_stop_id (0),
4399         m_frame_idx (UINT32_MAX),
4400         m_first_visible_line (0),
4401         m_min_x (0),
4402         m_min_y (0),
4403         m_max_x (0),
4404         m_max_y (0)
4405     {
4406     }
4407     
4408     
4409     virtual
4410     ~SourceFileWindowDelegate()
4411     {
4412     }
4413     
4414     void
4415     Update (const SymbolContext &sc)
4416     {
4417         m_sc = sc;
4418     }
4419     
4420     uint32_t
4421     NumVisibleLines () const
4422     {
4423         return m_max_y - m_min_y;
4424     }
4425     
4426     virtual const char *
4427     WindowDelegateGetHelpText ()
4428     {
4429         return "Source/Disassembly window keyboard shortcuts:";
4430     }
4431     
4432     virtual KeyHelp *
4433     WindowDelegateGetKeyHelp ()
4434     {
4435         static curses::KeyHelp g_source_view_key_help[] = {
4436             { KEY_RETURN, "Run to selected line with one shot breakpoint" },
4437             { KEY_UP, "Select previous source line" },
4438             { KEY_DOWN, "Select next source line" },
4439             { KEY_PPAGE, "Page up" },
4440             { KEY_NPAGE, "Page down" },
4441             { 'b', "Set breakpoint on selected source/disassembly line" },
4442             { 'c', "Continue process" },
4443             { 'd', "Detach and resume process" },
4444             { 'D', "Detach with process suspended" },
4445             { 'h', "Show help dialog" },
4446             { 'k', "Kill process" },
4447             { 'n', "Step over (source line)" },
4448             { 'N', "Step over (single instruction)" },
4449             { 'o', "Step out" },
4450             { 's', "Step in (source line)" },
4451             { 'S', "Step in (single instruction)" },
4452             { ',', "Page up" },
4453             { '.', "Page down" },
4454             { '\0', NULL }
4455         };
4456         return g_source_view_key_help;
4457     }
4458     
4459     virtual bool
4460     WindowDelegateDraw (Window &window, bool force)
4461     {
4462         ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4463         Process *process = exe_ctx.GetProcessPtr();
4464         Thread *thread = NULL;
4465
4466         bool update_location = false;
4467         if (process)
4468         {
4469             StateType state = process->GetState();
4470             if (StateIsStoppedState(state, true))
4471             {
4472                 // We are stopped, so it is ok to
4473                 update_location = true;
4474             }
4475         }
4476         
4477         m_min_x = 1;
4478         m_min_y = 1;
4479         m_max_x = window.GetMaxX()-1;
4480         m_max_y = window.GetMaxY()-1;
4481         
4482         const uint32_t num_visible_lines = NumVisibleLines();
4483         StackFrameSP frame_sp;
4484         bool set_selected_line_to_pc = false;
4485
4486         
4487         if (update_location)
4488         {
4489             
4490             const bool process_alive = process ? process->IsAlive() : false;
4491             bool thread_changed = false;
4492             if (process_alive)
4493             {
4494                 thread = exe_ctx.GetThreadPtr();
4495                 if (thread)
4496                 {
4497                     frame_sp = thread->GetSelectedFrame();
4498                     auto tid = thread->GetID();
4499                     thread_changed = tid != m_tid;
4500                     m_tid = tid;
4501                 }
4502                 else
4503                 {
4504                     if (m_tid != LLDB_INVALID_THREAD_ID)
4505                     {
4506                         thread_changed = true;
4507                         m_tid = LLDB_INVALID_THREAD_ID;
4508                     }
4509                 }
4510             }
4511             const uint32_t stop_id = process ? process->GetStopID() : 0;
4512             const bool stop_id_changed = stop_id != m_stop_id;
4513             bool frame_changed = false;
4514             m_stop_id = stop_id;
4515             if (frame_sp)
4516             {
4517                 m_sc = frame_sp->GetSymbolContext(eSymbolContextEverything);
4518                 const uint32_t frame_idx = frame_sp->GetFrameIndex();
4519                 frame_changed = frame_idx != m_frame_idx;
4520                 m_frame_idx = frame_idx;
4521             }
4522             else
4523             {
4524                 m_sc.Clear(true);
4525                 frame_changed = m_frame_idx != UINT32_MAX;
4526                 m_frame_idx = UINT32_MAX;
4527             }
4528             
4529             const bool context_changed = thread_changed || frame_changed || stop_id_changed;
4530             
4531             if (process_alive)
4532             {
4533                 if (m_sc.line_entry.IsValid())
4534                 {
4535                     m_pc_line = m_sc.line_entry.line;
4536                     if (m_pc_line != UINT32_MAX)
4537                         --m_pc_line; // Convert to zero based line number...
4538                     // Update the selected line if the stop ID changed...
4539                     if (context_changed)
4540                         m_selected_line = m_pc_line;
4541
4542                     if (m_file_sp && m_file_sp->FileSpecMatches(m_sc.line_entry.file))
4543                     {
4544                         // Same file, nothing to do, we should either have the
4545                         // lines or not (source file missing)
4546                         if (m_selected_line >= m_first_visible_line)
4547                         {
4548                             if (m_selected_line >= m_first_visible_line + num_visible_lines)
4549                                 m_first_visible_line = m_selected_line - 10;
4550                         }
4551                         else
4552                         {
4553                             if (m_selected_line > 10)
4554                                 m_first_visible_line = m_selected_line - 10;
4555                             else
4556                                 m_first_visible_line = 0;
4557                         }
4558                     }
4559                     else
4560                     {
4561                         // File changed, set selected line to the line with the PC
4562                         m_selected_line = m_pc_line;
4563                         m_file_sp = m_debugger.GetSourceManager().GetFile(m_sc.line_entry.file);
4564                         if (m_file_sp)
4565                         {
4566                             const size_t num_lines = m_file_sp->GetNumLines();
4567                             int m_line_width = 1;
4568                             for (size_t n = num_lines; n >= 10; n = n / 10)
4569                                 ++m_line_width;
4570                             
4571                             snprintf (m_line_format, sizeof(m_line_format), " %%%iu ", m_line_width);
4572                             if (num_lines < num_visible_lines || m_selected_line < num_visible_lines)
4573                                 m_first_visible_line = 0;
4574                             else
4575                                 m_first_visible_line = m_selected_line - 10;
4576                         }
4577                     }
4578                 }
4579                 else
4580                 {
4581                     m_file_sp.reset();
4582                 }
4583                 
4584                 if (!m_file_sp || m_file_sp->GetNumLines() == 0)
4585                 {
4586                     // Show disassembly
4587                     bool prefer_file_cache = false;
4588                     if (m_sc.function)
4589                     {
4590                         if (m_disassembly_scope != m_sc.function)
4591                         {
4592                             m_disassembly_scope = m_sc.function;
4593                             m_disassembly_sp = m_sc.function->GetInstructions (exe_ctx, NULL, prefer_file_cache);
4594                             if (m_disassembly_sp)
4595                             {
4596                                 set_selected_line_to_pc = true;
4597                                 m_disassembly_range = m_sc.function->GetAddressRange();
4598                             }
4599                             else
4600                             {
4601                                 m_disassembly_range.Clear();
4602                             }
4603                         }
4604                         else
4605                         {
4606                             set_selected_line_to_pc = context_changed;
4607                         }
4608                     }
4609                     else if (m_sc.symbol)
4610                     {
4611                         if (m_disassembly_scope != m_sc.symbol)
4612                         {
4613                             m_disassembly_scope = m_sc.symbol;
4614                             m_disassembly_sp = m_sc.symbol->GetInstructions (exe_ctx, NULL, prefer_file_cache);
4615                             if (m_disassembly_sp)
4616                             {
4617                                 set_selected_line_to_pc = true;
4618                                 m_disassembly_range.GetBaseAddress() = m_sc.symbol->GetAddress();
4619                                 m_disassembly_range.SetByteSize(m_sc.symbol->GetByteSize());
4620                             }
4621                             else
4622                             {
4623                                 m_disassembly_range.Clear();
4624                             }
4625                         }
4626                         else
4627                         {
4628                             set_selected_line_to_pc = context_changed;
4629                         }
4630                     }
4631                 }
4632             }
4633             else
4634             {
4635                 m_pc_line = UINT32_MAX;
4636             }
4637         }
4638         
4639             
4640         window.Erase();
4641         window.DrawTitleBox ("Sources");
4642         
4643
4644         Target *target = exe_ctx.GetTargetPtr();
4645         const size_t num_source_lines = GetNumSourceLines();
4646         if (num_source_lines > 0)
4647         {
4648             // Display source
4649             BreakpointLines bp_lines;
4650             if (target)
4651             {
4652                 BreakpointList &bp_list = target->GetBreakpointList();
4653                 const size_t num_bps = bp_list.GetSize();
4654                 for (size_t bp_idx=0; bp_idx<num_bps; ++bp_idx)
4655                 {
4656                     BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx);
4657                     const size_t num_bps_locs = bp_sp->GetNumLocations();
4658                     for (size_t bp_loc_idx=0; bp_loc_idx<num_bps_locs; ++bp_loc_idx)
4659                     {
4660                         BreakpointLocationSP bp_loc_sp = bp_sp->GetLocationAtIndex(bp_loc_idx);
4661                         LineEntry bp_loc_line_entry;
4662                         if (bp_loc_sp->GetAddress().CalculateSymbolContextLineEntry (bp_loc_line_entry))
4663                         {
4664                             if (m_file_sp->GetFileSpec() == bp_loc_line_entry.file)
4665                             {
4666                                 bp_lines.insert(bp_loc_line_entry.line);
4667                             }
4668                         }
4669                     }
4670                 }
4671             }
4672             
4673         
4674             const attr_t selected_highlight_attr = A_REVERSE;
4675             const attr_t pc_highlight_attr = COLOR_PAIR(1);
4676
4677             for (int i=0; i<num_visible_lines; ++i)
4678             {
4679                 const uint32_t curr_line = m_first_visible_line + i;
4680                 if (curr_line < num_source_lines)
4681                 {
4682                     const int line_y = 1+i;
4683                     window.MoveCursor(1, line_y);
4684                     const bool is_pc_line = curr_line == m_pc_line;
4685                     const bool line_is_selected = m_selected_line == curr_line;
4686                     // Highlight the line as the PC line first, then if the selected line
4687                     // isn't the same as the PC line, highlight it differently
4688                     attr_t highlight_attr = 0;
4689                     attr_t bp_attr = 0;
4690                     if (is_pc_line)
4691                         highlight_attr = pc_highlight_attr;
4692                     else if (line_is_selected)
4693                         highlight_attr = selected_highlight_attr;
4694                     
4695                     if (bp_lines.find(curr_line+1) != bp_lines.end())
4696                         bp_attr = COLOR_PAIR(2);
4697
4698                     if (bp_attr)
4699                         window.AttributeOn(bp_attr);
4700                     
4701                     window.Printf (m_line_format, curr_line + 1);
4702
4703                     if (bp_attr)
4704                         window.AttributeOff(bp_attr);
4705
4706                     window.PutChar(ACS_VLINE);
4707                     // Mark the line with the PC with a diamond
4708                     if (is_pc_line)
4709                         window.PutChar(ACS_DIAMOND);
4710                     else
4711                         window.PutChar(' ');
4712                     
4713                     if (highlight_attr)
4714                         window.AttributeOn(highlight_attr);
4715                     const uint32_t line_len = m_file_sp->GetLineLength(curr_line + 1, false);
4716                     if (line_len > 0)
4717                         window.PutCString(m_file_sp->PeekLineData(curr_line + 1), line_len);
4718
4719                     if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0)
4720                     {
4721                         StopInfoSP stop_info_sp;
4722                         if (thread)
4723                             stop_info_sp = thread->GetStopInfo();
4724                         if (stop_info_sp)
4725                         {
4726                             const char *stop_description = stop_info_sp->GetDescription();
4727                             if (stop_description && stop_description[0])
4728                             {
4729                                 size_t stop_description_len = strlen(stop_description);
4730                                 int desc_x = window.GetWidth() - stop_description_len - 16;
4731                                 window.Printf ("%*s", desc_x - window.GetCursorX(), "");
4732                                 //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y);
4733                                 window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description);
4734                             }
4735                         }
4736                         else
4737                         {
4738                             window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, "");
4739                         }
4740                     }
4741                     if (highlight_attr)
4742                         window.AttributeOff(highlight_attr);
4743
4744                 }
4745                 else
4746                 {
4747                     break;
4748                 }
4749             }
4750         }
4751         else
4752         {
4753             size_t num_disassembly_lines = GetNumDisassemblyLines();
4754             if (num_disassembly_lines > 0)
4755             {
4756                 // Display disassembly
4757                 BreakpointAddrs bp_file_addrs;
4758                 Target *target = exe_ctx.GetTargetPtr();
4759                 if (target)
4760                 {
4761                     BreakpointList &bp_list = target->GetBreakpointList();
4762                     const size_t num_bps = bp_list.GetSize();
4763                     for (size_t bp_idx=0; bp_idx<num_bps; ++bp_idx)
4764                     {
4765                         BreakpointSP bp_sp = bp_list.GetBreakpointAtIndex(bp_idx);
4766                         const size_t num_bps_locs = bp_sp->GetNumLocations();
4767                         for (size_t bp_loc_idx=0; bp_loc_idx<num_bps_locs; ++bp_loc_idx)
4768                         {
4769                             BreakpointLocationSP bp_loc_sp = bp_sp->GetLocationAtIndex(bp_loc_idx);
4770                             LineEntry bp_loc_line_entry;
4771                             const lldb::addr_t file_addr = bp_loc_sp->GetAddress().GetFileAddress();
4772                             if (file_addr != LLDB_INVALID_ADDRESS)
4773                             {
4774                                 if (m_disassembly_range.ContainsFileAddress(file_addr))
4775                                     bp_file_addrs.insert(file_addr);
4776                             }
4777                         }
4778                     }
4779                 }
4780                 
4781                 
4782                 const attr_t selected_highlight_attr = A_REVERSE;
4783                 const attr_t pc_highlight_attr = COLOR_PAIR(1);
4784                 
4785                 StreamString strm;
4786
4787                 InstructionList &insts = m_disassembly_sp->GetInstructionList();
4788                 Address pc_address;
4789                 
4790                 if (frame_sp)
4791                     pc_address = frame_sp->GetFrameCodeAddress();
4792                 const uint32_t pc_idx = pc_address.IsValid() ? insts.GetIndexOfInstructionAtAddress (pc_address) : UINT32_MAX;
4793                 if (set_selected_line_to_pc)
4794                 {
4795                     m_selected_line = pc_idx;
4796                 }
4797
4798                 const uint32_t non_visible_pc_offset = (num_visible_lines / 5);
4799                 if (m_first_visible_line >= num_disassembly_lines)
4800                     m_first_visible_line = 0;
4801
4802                 if (pc_idx < num_disassembly_lines)
4803                 {
4804                     if (pc_idx < m_first_visible_line ||
4805                         pc_idx >= m_first_visible_line + num_visible_lines)
4806                         m_first_visible_line = pc_idx - non_visible_pc_offset;
4807                 }
4808
4809                 for (size_t i=0; i<num_visible_lines; ++i)
4810                 {
4811                     const uint32_t inst_idx = m_first_visible_line + i;
4812                     Instruction *inst = insts.GetInstructionAtIndex(inst_idx).get();
4813                     if (!inst)
4814                         break;
4815                     
4816                     window.MoveCursor(1, i+1);
4817                     const bool is_pc_line = frame_sp && inst_idx == pc_idx;
4818                     const bool line_is_selected = m_selected_line == inst_idx;
4819                     // Highlight the line as the PC line first, then if the selected line
4820                     // isn't the same as the PC line, highlight it differently
4821                     attr_t highlight_attr = 0;
4822                     attr_t bp_attr = 0;
4823                     if (is_pc_line)
4824                         highlight_attr = pc_highlight_attr;
4825                     else if (line_is_selected)
4826                         highlight_attr = selected_highlight_attr;
4827                     
4828                     if (bp_file_addrs.find(inst->GetAddress().GetFileAddress()) != bp_file_addrs.end())
4829                         bp_attr = COLOR_PAIR(2);
4830                     
4831                     if (bp_attr)
4832                         window.AttributeOn(bp_attr);
4833                     
4834                     window.Printf (" 0x%16.16llx ", inst->GetAddress().GetLoadAddress(target));
4835                         
4836                     if (bp_attr)
4837                         window.AttributeOff(bp_attr);
4838                         
4839                     window.PutChar(ACS_VLINE);
4840                     // Mark the line with the PC with a diamond
4841                     if (is_pc_line)
4842                         window.PutChar(ACS_DIAMOND);
4843                     else
4844                         window.PutChar(' ');
4845                     
4846                     if (highlight_attr)
4847                         window.AttributeOn(highlight_attr);
4848                     
4849                     const char *mnemonic = inst->GetMnemonic(&exe_ctx);
4850                     const char *operands = inst->GetOperands(&exe_ctx);
4851                     const char *comment = inst->GetComment(&exe_ctx);
4852
4853                     if (mnemonic && mnemonic[0] == '\0')
4854                         mnemonic = NULL;
4855                     if (operands && operands[0] == '\0')
4856                         operands = NULL;
4857                     if (comment && comment[0] == '\0')
4858                         comment = NULL;
4859                     
4860                     strm.Clear();
4861
4862                     if (mnemonic && operands && comment)
4863                         strm.Printf ("%-8s %-25s ; %s", mnemonic, operands, comment);
4864                     else if (mnemonic && operands)
4865                         strm.Printf ("%-8s %s", mnemonic, operands);
4866                     else if (mnemonic)
4867                         strm.Printf ("%s", mnemonic);
4868                     
4869                     int right_pad = 1;
4870                     window.PutCStringTruncated(strm.GetString().c_str(), right_pad);
4871                     
4872                     if (is_pc_line && frame_sp && frame_sp->GetConcreteFrameIndex() == 0)
4873                     {
4874                         StopInfoSP stop_info_sp;
4875                         if (thread)
4876                             stop_info_sp = thread->GetStopInfo();
4877                         if (stop_info_sp)
4878                         {
4879                             const char *stop_description = stop_info_sp->GetDescription();
4880                             if (stop_description && stop_description[0])
4881                             {
4882                                 size_t stop_description_len = strlen(stop_description);
4883                                 int desc_x = window.GetWidth() - stop_description_len - 16;
4884                                 window.Printf ("%*s", desc_x - window.GetCursorX(), "");
4885                                 //window.MoveCursor(window.GetWidth() - stop_description_len - 15, line_y);
4886                                 window.Printf ("<<< Thread %u: %s ", thread->GetIndexID(), stop_description);
4887                             }
4888                         }
4889                         else
4890                         {
4891                             window.Printf ("%*s", window.GetWidth() - window.GetCursorX() - 1, "");
4892                         }
4893                     }
4894                     if (highlight_attr)
4895                         window.AttributeOff(highlight_attr);
4896                 }
4897             }
4898         }
4899         window.DeferredRefresh();
4900         return true; // Drawing handled
4901     }
4902     
4903     size_t
4904     GetNumLines ()
4905     {
4906         size_t num_lines = GetNumSourceLines();
4907         if (num_lines == 0)
4908             num_lines = GetNumDisassemblyLines();
4909         return num_lines;
4910     }
4911     
4912     size_t
4913     GetNumSourceLines () const
4914     {
4915         if (m_file_sp)
4916             return m_file_sp->GetNumLines();
4917         return 0;
4918     }
4919     size_t
4920     GetNumDisassemblyLines () const
4921     {
4922         if (m_disassembly_sp)
4923             return m_disassembly_sp->GetInstructionList().GetSize();
4924         return 0;
4925     }
4926
4927     virtual HandleCharResult
4928     WindowDelegateHandleChar (Window &window, int c)
4929     {
4930         const uint32_t num_visible_lines = NumVisibleLines();
4931         const size_t num_lines = GetNumLines ();
4932
4933         switch (c)
4934         {
4935             case ',':
4936             case KEY_PPAGE:
4937                 // Page up key
4938                 if (m_first_visible_line > num_visible_lines)
4939                     m_first_visible_line -= num_visible_lines;
4940                 else
4941                     m_first_visible_line = 0;
4942                 m_selected_line = m_first_visible_line;
4943                 return eKeyHandled;
4944                 
4945             case '.':
4946             case KEY_NPAGE:
4947                 // Page down key
4948                 {
4949                     if (m_first_visible_line + num_visible_lines < num_lines)
4950                         m_first_visible_line += num_visible_lines;
4951                     else if (num_lines < num_visible_lines)
4952                         m_first_visible_line = 0;
4953                     else
4954                         m_first_visible_line = num_lines - num_visible_lines;
4955                     m_selected_line = m_first_visible_line;
4956                 }
4957                 return eKeyHandled;
4958                 
4959             case KEY_UP:
4960                 if (m_selected_line > 0)
4961                 {
4962                     m_selected_line--;
4963                     if (m_first_visible_line > m_selected_line)
4964                         m_first_visible_line = m_selected_line;
4965                 }
4966                 return eKeyHandled;
4967
4968             case KEY_DOWN:
4969                 if (m_selected_line + 1 < num_lines)
4970                 {
4971                     m_selected_line++;
4972                     if (m_first_visible_line + num_visible_lines < m_selected_line)
4973                         m_first_visible_line++;
4974                 }
4975                 return eKeyHandled;
4976                 
4977             case '\r':
4978             case '\n':
4979             case KEY_ENTER:
4980                 // Set a breakpoint and run to the line using a one shot breakpoint
4981                 if (GetNumSourceLines() > 0)
4982                 {
4983                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
4984                     if (exe_ctx.HasProcessScope() && exe_ctx.GetProcessRef().IsAlive())
4985                     {
4986                         BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (NULL,                      // Don't limit the breakpoint to certain modules
4987                                                                                       m_file_sp->GetFileSpec(),  // Source file
4988                                                                                       m_selected_line + 1,       // Source line number (m_selected_line is zero based)
4989                                                                                       eLazyBoolCalculate,        // Check inlines using global setting
4990                                                                                       eLazyBoolCalculate,        // Skip prologue using global setting,
4991                                                                                       false,                     // internal
4992                                                                                       false);                    // request_hardware
4993                         // Make breakpoint one shot
4994                         bp_sp->GetOptions()->SetOneShot(true);
4995                         exe_ctx.GetProcessRef().Resume();
4996                     }
4997                 }
4998                 else if (m_selected_line < GetNumDisassemblyLines())
4999                 {
5000                     const Instruction *inst = m_disassembly_sp->GetInstructionList().GetInstructionAtIndex(m_selected_line).get();
5001                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5002                     if (exe_ctx.HasTargetScope())
5003                     {
5004                         Address addr = inst->GetAddress();
5005                         BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (addr,     // lldb_private::Address
5006                                                                                       false,    // internal
5007                                                                                       false);   // request_hardware
5008                         // Make breakpoint one shot
5009                         bp_sp->GetOptions()->SetOneShot(true);
5010                         exe_ctx.GetProcessRef().Resume();
5011                     }
5012                 }
5013                 return eKeyHandled;
5014
5015             case 'b':   // 'b' == toggle breakpoint on currently selected line
5016                 if (m_selected_line < GetNumSourceLines())
5017                 {
5018                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5019                     if (exe_ctx.HasTargetScope())
5020                     {
5021                         BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (NULL,                      // Don't limit the breakpoint to certain modules
5022                                                                                       m_file_sp->GetFileSpec(),  // Source file
5023                                                                                       m_selected_line + 1,       // Source line number (m_selected_line is zero based)
5024                                                                                       eLazyBoolCalculate,        // Check inlines using global setting
5025                                                                                       eLazyBoolCalculate,        // Skip prologue using global setting,
5026                                                                                       false,                     // internal
5027                                                                                       false);                    // request_hardware
5028                     }
5029                 }
5030                 else if (m_selected_line < GetNumDisassemblyLines())
5031                 {
5032                     const Instruction *inst = m_disassembly_sp->GetInstructionList().GetInstructionAtIndex(m_selected_line).get();
5033                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5034                     if (exe_ctx.HasTargetScope())
5035                     {
5036                         Address addr = inst->GetAddress();
5037                         BreakpointSP bp_sp = exe_ctx.GetTargetRef().CreateBreakpoint (addr,     // lldb_private::Address
5038                                                                                       false,    // internal
5039                                                                                       false);   // request_hardware
5040                     }
5041                 }
5042                 return eKeyHandled;
5043
5044             case 'd':   // 'd' == detach and let run
5045             case 'D':   // 'D' == detach and keep stopped
5046                 {
5047                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5048                     if (exe_ctx.HasProcessScope())
5049                         exe_ctx.GetProcessRef().Detach(c == 'D');
5050                 }
5051                 return eKeyHandled;
5052
5053             case 'k':
5054                 // 'k' == kill
5055                 {
5056                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5057                     if (exe_ctx.HasProcessScope())
5058                         exe_ctx.GetProcessRef().Destroy();
5059                 }
5060                 return eKeyHandled;
5061
5062             case 'c':
5063                 // 'c' == continue
5064                 {
5065                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5066                     if (exe_ctx.HasProcessScope())
5067                         exe_ctx.GetProcessRef().Resume();
5068                 }
5069                 return eKeyHandled;
5070                 
5071             case 'o':
5072                 // 'o' == step out
5073                 {
5074                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5075                     if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
5076                     {
5077                         exe_ctx.GetThreadRef().StepOut();
5078                     }
5079                 }
5080                 return eKeyHandled;
5081             case 'n':   // 'n' == step over
5082             case 'N':   // 'N' == step over instruction
5083                 {
5084                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5085                     if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
5086                     {
5087                         bool source_step = (c == 'n');
5088                         exe_ctx.GetThreadRef().StepOver(source_step);
5089                     }
5090                 }
5091                 return eKeyHandled;
5092             case 's':   // 's' == step into
5093             case 'S':   // 'S' == step into instruction
5094                 {
5095                     ExecutionContext exe_ctx = m_debugger.GetCommandInterpreter().GetExecutionContext();
5096                     if (exe_ctx.HasThreadScope() && StateIsStoppedState (exe_ctx.GetProcessRef().GetState(), true))
5097                     {
5098                         bool source_step = (c == 's');
5099                         bool avoid_code_without_debug_info = true;
5100                         exe_ctx.GetThreadRef().StepIn(source_step, avoid_code_without_debug_info);
5101                     }
5102                 }
5103                 return eKeyHandled;
5104                 
5105             case 'h':
5106                 window.CreateHelpSubwindow ();
5107                 return eKeyHandled;
5108
5109             default:
5110                 break;
5111         }
5112         return eKeyNotHandled;
5113     }
5114     
5115 protected:
5116     typedef std::set<uint32_t> BreakpointLines;
5117     typedef std::set<lldb::addr_t> BreakpointAddrs;
5118
5119     Debugger &m_debugger;
5120     SymbolContext m_sc;
5121     SourceManager::FileSP m_file_sp;
5122     SymbolContextScope *m_disassembly_scope;
5123     lldb::DisassemblerSP m_disassembly_sp;
5124     AddressRange m_disassembly_range;
5125     lldb::user_id_t m_tid;
5126     char m_line_format[8];
5127     int m_line_width;
5128     uint32_t m_selected_line;       // The selected line
5129     uint32_t m_pc_line;             // The line with the PC
5130     uint32_t m_stop_id;
5131     uint32_t m_frame_idx;
5132     int m_first_visible_line;
5133     int m_min_x;
5134     int m_min_y;
5135     int m_max_x;
5136     int m_max_y;
5137
5138 };
5139
5140 DisplayOptions ValueObjectListDelegate::g_options = { true };
5141
5142 IOHandlerCursesGUI::IOHandlerCursesGUI (Debugger &debugger) :
5143     IOHandler (debugger)
5144 {
5145 }
5146
5147 void
5148 IOHandlerCursesGUI::Activate ()
5149 {
5150     IOHandler::Activate();
5151     if (!m_app_ap)
5152     {
5153         m_app_ap.reset (new Application (GetInputFILE(), GetOutputFILE()));
5154         
5155         
5156         // This is both a window and a menu delegate
5157         std::shared_ptr<ApplicationDelegate> app_delegate_sp(new ApplicationDelegate(*m_app_ap, m_debugger));
5158         
5159         MenuDelegateSP app_menu_delegate_sp = std::static_pointer_cast<MenuDelegate>(app_delegate_sp);
5160         MenuSP lldb_menu_sp(new Menu("LLDB" , "F1", KEY_F(1), ApplicationDelegate::eMenuID_LLDB));
5161         MenuSP exit_menuitem_sp(new Menu("Exit", NULL, 'x', ApplicationDelegate::eMenuID_LLDBExit));
5162         exit_menuitem_sp->SetCannedResult(MenuActionResult::Quit);
5163         lldb_menu_sp->AddSubmenu (MenuSP (new Menu("About LLDB", NULL, 'a', ApplicationDelegate::eMenuID_LLDBAbout)));
5164         lldb_menu_sp->AddSubmenu (MenuSP (new Menu(Menu::Type::Separator)));
5165         lldb_menu_sp->AddSubmenu (exit_menuitem_sp);
5166         
5167         MenuSP target_menu_sp(new Menu("Target" ,"F2", KEY_F(2), ApplicationDelegate::eMenuID_Target));
5168         target_menu_sp->AddSubmenu (MenuSP (new Menu("Create", NULL, 'c', ApplicationDelegate::eMenuID_TargetCreate)));
5169         target_menu_sp->AddSubmenu (MenuSP (new Menu("Delete", NULL, 'd', ApplicationDelegate::eMenuID_TargetDelete)));
5170         
5171         MenuSP process_menu_sp(new Menu("Process", "F3", KEY_F(3), ApplicationDelegate::eMenuID_Process));
5172         process_menu_sp->AddSubmenu (MenuSP (new Menu("Attach"  , NULL, 'a', ApplicationDelegate::eMenuID_ProcessAttach)));
5173         process_menu_sp->AddSubmenu (MenuSP (new Menu("Detach"  , NULL, 'd', ApplicationDelegate::eMenuID_ProcessDetach)));
5174         process_menu_sp->AddSubmenu (MenuSP (new Menu("Launch"  , NULL, 'l', ApplicationDelegate::eMenuID_ProcessLaunch)));
5175         process_menu_sp->AddSubmenu (MenuSP (new Menu(Menu::Type::Separator)));
5176         process_menu_sp->AddSubmenu (MenuSP (new Menu("Continue", NULL, 'c', ApplicationDelegate::eMenuID_ProcessContinue)));
5177         process_menu_sp->AddSubmenu (MenuSP (new Menu("Halt"    , NULL, 'h', ApplicationDelegate::eMenuID_ProcessHalt)));
5178         process_menu_sp->AddSubmenu (MenuSP (new Menu("Kill"    , NULL, 'k', ApplicationDelegate::eMenuID_ProcessKill)));
5179         
5180         MenuSP thread_menu_sp(new Menu("Thread", "F4", KEY_F(4), ApplicationDelegate::eMenuID_Thread));
5181         thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step In"  , NULL, 'i', ApplicationDelegate::eMenuID_ThreadStepIn)));
5182         thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step Over", NULL, 'v', ApplicationDelegate::eMenuID_ThreadStepOver)));
5183         thread_menu_sp->AddSubmenu (MenuSP (new Menu("Step Out" , NULL, 'o', ApplicationDelegate::eMenuID_ThreadStepOut)));
5184         
5185         MenuSP view_menu_sp(new Menu("View", "F5", KEY_F(5), ApplicationDelegate::eMenuID_View));
5186         view_menu_sp->AddSubmenu (MenuSP (new Menu("Backtrace", NULL, 'b', ApplicationDelegate::eMenuID_ViewBacktrace)));
5187         view_menu_sp->AddSubmenu (MenuSP (new Menu("Registers", NULL, 'r', ApplicationDelegate::eMenuID_ViewRegisters)));
5188         view_menu_sp->AddSubmenu (MenuSP (new Menu("Source"   , NULL, 's', ApplicationDelegate::eMenuID_ViewSource)));
5189         view_menu_sp->AddSubmenu (MenuSP (new Menu("Variables", NULL, 'v', ApplicationDelegate::eMenuID_ViewVariables)));
5190         
5191         MenuSP help_menu_sp(new Menu("Help", "F6", KEY_F(6), ApplicationDelegate::eMenuID_Help));
5192         help_menu_sp->AddSubmenu (MenuSP (new Menu("GUI Help", NULL, 'g', ApplicationDelegate::eMenuID_HelpGUIHelp)));
5193         
5194         m_app_ap->Initialize();
5195         WindowSP &main_window_sp = m_app_ap->GetMainWindow();
5196         
5197         MenuSP menubar_sp(new Menu(Menu::Type::Bar));
5198         menubar_sp->AddSubmenu (lldb_menu_sp);
5199         menubar_sp->AddSubmenu (target_menu_sp);
5200         menubar_sp->AddSubmenu (process_menu_sp);
5201         menubar_sp->AddSubmenu (thread_menu_sp);
5202         menubar_sp->AddSubmenu (view_menu_sp);
5203         menubar_sp->AddSubmenu (help_menu_sp);
5204         menubar_sp->SetDelegate(app_menu_delegate_sp);
5205         
5206         Rect content_bounds = main_window_sp->GetFrame();
5207         Rect menubar_bounds = content_bounds.MakeMenuBar();
5208         Rect status_bounds = content_bounds.MakeStatusBar();
5209         Rect source_bounds;
5210         Rect variables_bounds;
5211         Rect threads_bounds;
5212         Rect source_variables_bounds;
5213         content_bounds.VerticalSplitPercentage(0.80, source_variables_bounds, threads_bounds);
5214         source_variables_bounds.HorizontalSplitPercentage(0.70, source_bounds, variables_bounds);
5215         
5216         WindowSP menubar_window_sp = main_window_sp->CreateSubWindow("Menubar", menubar_bounds, false);
5217         // Let the menubar get keys if the active window doesn't handle the
5218         // keys that are typed so it can respond to menubar key presses.
5219         menubar_window_sp->SetCanBeActive(false); // Don't let the menubar become the active window
5220         menubar_window_sp->SetDelegate(menubar_sp);
5221         
5222         WindowSP source_window_sp (main_window_sp->CreateSubWindow("Source",
5223                                                                    source_bounds,
5224                                                                    true));
5225         WindowSP variables_window_sp (main_window_sp->CreateSubWindow("Variables",
5226                                                                       variables_bounds,
5227                                                                       false));
5228         WindowSP threads_window_sp (main_window_sp->CreateSubWindow("Threads",
5229                                                                       threads_bounds,
5230                                                                       false));
5231         WindowSP status_window_sp (main_window_sp->CreateSubWindow("Status",
5232                                                                    status_bounds,
5233                                                                    false));
5234         status_window_sp->SetCanBeActive(false); // Don't let the status bar become the active window
5235         main_window_sp->SetDelegate (std::static_pointer_cast<WindowDelegate>(app_delegate_sp));
5236         source_window_sp->SetDelegate (WindowDelegateSP(new SourceFileWindowDelegate(m_debugger)));
5237         variables_window_sp->SetDelegate (WindowDelegateSP(new FrameVariablesWindowDelegate(m_debugger)));
5238         TreeDelegateSP thread_delegate_sp (new ThreadTreeDelegate(m_debugger));
5239         threads_window_sp->SetDelegate (WindowDelegateSP(new TreeWindowDelegate(m_debugger, thread_delegate_sp)));
5240         status_window_sp->SetDelegate (WindowDelegateSP(new StatusBarWindowDelegate(m_debugger)));
5241
5242         // Show the main help window once the first time the curses GUI is launched
5243         static bool g_showed_help = false;
5244         if (!g_showed_help)
5245         {
5246             g_showed_help = true;
5247             main_window_sp->CreateHelpSubwindow();
5248         }
5249
5250         init_pair (1, COLOR_WHITE   , COLOR_BLUE  );
5251         init_pair (2, COLOR_BLACK   , COLOR_WHITE );
5252         init_pair (3, COLOR_MAGENTA , COLOR_WHITE );
5253         init_pair (4, COLOR_MAGENTA , COLOR_BLACK );
5254         init_pair (5, COLOR_RED     , COLOR_BLACK );
5255
5256     }
5257 }
5258
5259 void
5260 IOHandlerCursesGUI::Deactivate ()
5261 {
5262     m_app_ap->Terminate();
5263 }
5264
5265 void
5266 IOHandlerCursesGUI::Run ()
5267 {
5268     m_app_ap->Run(m_debugger);
5269     SetIsDone(true);
5270 }
5271
5272
5273 IOHandlerCursesGUI::~IOHandlerCursesGUI ()
5274 {
5275     
5276 }
5277
5278 void
5279 IOHandlerCursesGUI::Hide ()
5280 {
5281 }
5282
5283
5284 void
5285 IOHandlerCursesGUI::Refresh ()
5286 {
5287 }
5288
5289 void
5290 IOHandlerCursesGUI::Cancel ()
5291 {
5292 }
5293
5294 void
5295 IOHandlerCursesGUI::Interrupt ()
5296 {
5297 }
5298
5299
5300 void
5301 IOHandlerCursesGUI::GotEOF()
5302 {
5303 }
5304
5305 #endif // #ifndef LLDB_DISABLE_CURSES