Simplify TUI boxing
[platform/upstream/binutils.git] / gdb / tui / tui-layout.c
1 /* TUI layout window management.
2
3    Copyright (C) 1998-2019 Free Software Foundation, Inc.
4
5    Contributed by Hewlett-Packard Company.
6
7    This file is part of GDB.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21
22 #include "defs.h"
23 #include "arch-utils.h"
24 #include "command.h"
25 #include "symtab.h"
26 #include "frame.h"
27 #include "source.h"
28 #include <ctype.h>
29
30 #include "tui/tui.h"
31 #include "tui/tui-command.h"
32 #include "tui/tui-data.h"
33 #include "tui/tui-wingeneral.h"
34 #include "tui/tui-stack.h"
35 #include "tui/tui-regs.h"
36 #include "tui/tui-win.h"
37 #include "tui/tui-winsource.h"
38 #include "tui/tui-disasm.h"
39 #include "tui/tui-layout.h"
40 #include "tui/tui-source.h"
41 #include "gdb_curses.h"
42
43 /*******************************
44 ** Static Local Decls
45 ********************************/
46 static void show_layout (enum tui_layout_type);
47 static void show_source_or_disasm_and_command (enum tui_layout_type);
48 static void show_source_command (void);
49 static void show_disasm_command (void);
50 static void show_source_disasm_command (void);
51 static void show_data (enum tui_layout_type);
52 static enum tui_layout_type next_layout (void);
53 static enum tui_layout_type prev_layout (void);
54 static void tui_layout_command (const char *, int);
55 static void extract_display_start_addr (struct gdbarch **, CORE_ADDR *);
56
57
58 static enum tui_layout_type current_layout = UNDEFINED_LAYOUT;
59
60 /* Accessor for the current layout.  */
61 enum tui_layout_type
62 tui_current_layout (void)
63 {
64   return current_layout;
65 }
66
67 /***************************************
68 ** DEFINITIONS
69 ***************************************/
70
71 /* Show the screen layout defined.  */
72 static void
73 show_layout (enum tui_layout_type layout)
74 {
75   enum tui_layout_type cur_layout = tui_current_layout ();
76
77   if (layout != cur_layout)
78     {
79       /* Since the new layout may cause changes in window size, we
80          should free the content and reallocate on next display of
81          source/asm.  */
82       tui_clear_source_windows ();
83       /* First make the current layout be invisible.  */
84       tui_make_all_invisible ();
85       tui_locator_win_info_ptr ()->make_visible (false);
86       switch (layout)
87         {
88         case SRC_DATA_COMMAND:
89         case DISASSEM_DATA_COMMAND:
90           show_data (layout);
91           tui_refresh_all ();
92           break;
93           /* Now show the new layout.  */
94         case SRC_COMMAND:
95           show_source_command ();
96           tui_add_to_source_windows (TUI_SRC_WIN);
97           break;
98         case DISASSEM_COMMAND:
99           show_disasm_command ();
100           tui_add_to_source_windows (TUI_DISASM_WIN);
101           break;
102         case SRC_DISASSEM_COMMAND:
103           show_source_disasm_command ();
104           tui_add_to_source_windows (TUI_SRC_WIN);
105           tui_add_to_source_windows (TUI_DISASM_WIN);
106           break;
107         default:
108           break;
109         }
110
111       tui_delete_invisible_windows ();
112     }
113 }
114
115
116 /* Function to set the layout to SRC_COMMAND, DISASSEM_COMMAND,
117    SRC_DISASSEM_COMMAND, SRC_DATA_COMMAND, or DISASSEM_DATA_COMMAND.  */
118 void
119 tui_set_layout (enum tui_layout_type layout_type)
120 {
121   gdb_assert (layout_type != UNDEFINED_LAYOUT);
122
123   enum tui_layout_type cur_layout = tui_current_layout ();
124   struct gdbarch *gdbarch;
125   CORE_ADDR addr;
126   struct tui_win_info *win_with_focus = tui_win_with_focus ();
127
128   extract_display_start_addr (&gdbarch, &addr);
129
130   enum tui_layout_type new_layout = layout_type;
131
132   if (new_layout != cur_layout)
133     {
134       show_layout (new_layout);
135
136       /* Now determine where focus should be.  */
137       if (win_with_focus != TUI_CMD_WIN)
138         {
139           switch (new_layout)
140             {
141             case SRC_COMMAND:
142               tui_set_win_focus_to (TUI_SRC_WIN);
143               break;
144             case DISASSEM_COMMAND:
145               /* The previous layout was not showing code.
146                  This can happen if there is no source
147                  available:
148
149                  1. if the source file is in another dir OR
150                  2. if target was compiled without -g
151                  We still want to show the assembly though!  */
152
153               tui_get_begin_asm_address (&gdbarch, &addr);
154               tui_set_win_focus_to (TUI_DISASM_WIN);
155               break;
156             case SRC_DISASSEM_COMMAND:
157               /* The previous layout was not showing code.
158                  This can happen if there is no source
159                  available:
160
161                  1. if the source file is in another dir OR
162                  2. if target was compiled without -g
163                  We still want to show the assembly though!  */
164
165               tui_get_begin_asm_address (&gdbarch, &addr);
166               if (win_with_focus == TUI_SRC_WIN)
167                 tui_set_win_focus_to (TUI_SRC_WIN);
168               else
169                 tui_set_win_focus_to (TUI_DISASM_WIN);
170               break;
171             case SRC_DATA_COMMAND:
172               if (win_with_focus != TUI_DATA_WIN)
173                 tui_set_win_focus_to (TUI_SRC_WIN);
174               else
175                 tui_set_win_focus_to (TUI_DATA_WIN);
176               break;
177             case DISASSEM_DATA_COMMAND:
178               /* The previous layout was not showing code.
179                  This can happen if there is no source
180                  available:
181
182                  1. if the source file is in another dir OR
183                  2. if target was compiled without -g
184                  We still want to show the assembly though!  */
185
186               tui_get_begin_asm_address (&gdbarch, &addr);
187               if (win_with_focus != TUI_DATA_WIN)
188                 tui_set_win_focus_to (TUI_DISASM_WIN);
189               else
190                 tui_set_win_focus_to (TUI_DATA_WIN);
191               break;
192             default:
193               break;
194             }
195         }
196       /*
197        * Now update the window content.
198        */
199       tui_update_source_windows_with_addr (gdbarch, addr);
200       if (new_layout == SRC_DATA_COMMAND
201           || new_layout == DISASSEM_DATA_COMMAND)
202         tui_show_registers (TUI_DATA_WIN->current_group);
203     }
204 }
205
206 /* Add the specified window to the layout in a logical way.  This
207    means setting up the most logical layout given the window to be
208    added.  */
209 void
210 tui_add_win_to_layout (enum tui_win_type type)
211 {
212   enum tui_layout_type cur_layout = tui_current_layout ();
213
214   switch (type)
215     {
216     case SRC_WIN:
217       if (cur_layout != SRC_COMMAND
218           && cur_layout != SRC_DISASSEM_COMMAND
219           && cur_layout != SRC_DATA_COMMAND)
220         {
221           tui_clear_source_windows_detail ();
222           if (cur_layout == DISASSEM_DATA_COMMAND)
223             show_layout (SRC_DATA_COMMAND);
224           else
225             show_layout (SRC_COMMAND);
226         }
227       break;
228     case DISASSEM_WIN:
229       if (cur_layout != DISASSEM_COMMAND
230           && cur_layout != SRC_DISASSEM_COMMAND
231           && cur_layout != DISASSEM_DATA_COMMAND)
232         {
233           tui_clear_source_windows_detail ();
234           if (cur_layout == SRC_DATA_COMMAND)
235             show_layout (DISASSEM_DATA_COMMAND);
236           else
237             show_layout (DISASSEM_COMMAND);
238         }
239       break;
240     case DATA_WIN:
241       if (cur_layout != SRC_DATA_COMMAND
242           && cur_layout != DISASSEM_DATA_COMMAND)
243         {
244           if (cur_layout == DISASSEM_COMMAND)
245             show_layout (DISASSEM_DATA_COMMAND);
246           else
247             show_layout (SRC_DATA_COMMAND);
248         }
249       break;
250     default:
251       break;
252     }
253 }
254
255
256 /* Answer the height of a window.  If it hasn't been created yet,
257    answer what the height of a window would be based upon its type and
258    the layout.  */
259 static int
260 tui_default_win_height (enum tui_win_type type, 
261                         enum tui_layout_type layout)
262 {
263   int h;
264
265   if (tui_win_list[type] != NULL)
266     h = tui_win_list[type]->height;
267   else
268     {
269       switch (layout)
270         {
271         case SRC_COMMAND:
272         case DISASSEM_COMMAND:
273           if (TUI_CMD_WIN == NULL)
274             h = tui_term_height () / 2;
275           else
276             h = tui_term_height () - TUI_CMD_WIN->height;
277           break;
278         case SRC_DISASSEM_COMMAND:
279         case SRC_DATA_COMMAND:
280         case DISASSEM_DATA_COMMAND:
281           if (TUI_CMD_WIN == NULL)
282             h = tui_term_height () / 3;
283           else
284             h = (tui_term_height () - TUI_CMD_WIN->height) / 2;
285           break;
286         default:
287           h = 0;
288           break;
289         }
290     }
291
292   return h;
293 }
294
295
296 /* Answer the height of a window.  If it hasn't been created yet,
297    answer what the height of a window would be based upon its type and
298    the layout.  */
299 int
300 tui_default_win_viewport_height (enum tui_win_type type,
301                                  enum tui_layout_type layout)
302 {
303   int h;
304
305   h = tui_default_win_height (type, layout);
306
307   if (tui_win_list[type] == TUI_CMD_WIN)
308     h -= 1;
309   else
310     h -= 2;
311
312   return h;
313 }
314
315 /* Complete possible layout names.  TEXT is the complete text entered so
316    far, WORD is the word currently being completed.  */
317
318 static void
319 layout_completer (struct cmd_list_element *ignore,
320                   completion_tracker &tracker,
321                   const char *text, const char *word)
322 {
323   static const char *layout_names [] =
324     { "src", "asm", "split", "regs", "next", "prev", NULL };
325
326   complete_on_enum (tracker, layout_names, text, word);
327 }
328
329 /* Function to initialize gdb commands, for tui window layout
330    manipulation.  */
331
332 void
333 _initialize_tui_layout (void)
334 {
335   struct cmd_list_element *cmd;
336
337   cmd = add_com ("layout", class_tui, tui_layout_command, _("\
338 Change the layout of windows.\n\
339 Usage: layout prev | next | LAYOUT-NAME\n\
340 Layout names are:\n\
341    src   : Displays source and command windows.\n\
342    asm   : Displays disassembly and command windows.\n\
343    split : Displays source, disassembly and command windows.\n\
344    regs  : Displays register window. If existing layout\n\
345            is source/command or assembly/command, the \n\
346            register window is displayed. If the\n\
347            source/assembly/command (split) is displayed, \n\
348            the register window is displayed with \n\
349            the window that has current logical focus."));
350   set_cmd_completer (cmd, layout_completer);
351 }
352
353
354 /*************************
355 ** STATIC LOCAL FUNCTIONS
356 **************************/
357
358
359 /* Function to set the layout to SRC, ASM, SPLIT, NEXT, PREV, DATA, or
360    REGS. */
361 static void
362 tui_layout_command (const char *layout_name, int from_tty)
363 {
364   int i;
365   enum tui_layout_type new_layout = UNDEFINED_LAYOUT;
366   enum tui_layout_type cur_layout = tui_current_layout ();
367
368   if (layout_name == NULL)
369     error (_("Usage: layout prev | next | LAYOUT-NAME"));
370
371   std::string copy = layout_name;
372   for (i = 0; i < copy.size (); i++)
373     copy[i] = toupper (copy[i]);
374   const char *buf_ptr = copy.c_str ();
375
376   /* First check for ambiguous input.  */
377   if (strlen (buf_ptr) <= 1 && *buf_ptr == 'S')
378     error (_("Ambiguous command input."));
379
380   if (subset_compare (buf_ptr, "SRC"))
381     new_layout = SRC_COMMAND;
382   else if (subset_compare (buf_ptr, "ASM"))
383     new_layout = DISASSEM_COMMAND;
384   else if (subset_compare (buf_ptr, "SPLIT"))
385     new_layout = SRC_DISASSEM_COMMAND;
386   else if (subset_compare (buf_ptr, "REGS"))
387     {
388       if (cur_layout == SRC_COMMAND
389           || cur_layout == SRC_DATA_COMMAND)
390         new_layout = SRC_DATA_COMMAND;
391       else
392         new_layout = DISASSEM_DATA_COMMAND;
393     }
394   else if (subset_compare (buf_ptr, "NEXT"))
395     new_layout = next_layout ();
396   else if (subset_compare (buf_ptr, "PREV"))
397     new_layout = prev_layout ();
398   else
399     error (_("Unrecognized layout: %s"), layout_name);
400
401   /* Make sure the curses mode is enabled.  */
402   tui_enable ();
403   tui_set_layout (new_layout);
404 }
405
406
407 static void
408 extract_display_start_addr (struct gdbarch **gdbarch_p, CORE_ADDR *addr_p)
409 {
410   enum tui_layout_type cur_layout = tui_current_layout ();
411   struct gdbarch *gdbarch = get_current_arch ();
412   CORE_ADDR addr;
413   CORE_ADDR pc;
414   struct symtab_and_line cursal = get_current_source_symtab_and_line ();
415
416   switch (cur_layout)
417     {
418     case SRC_COMMAND:
419     case SRC_DATA_COMMAND:
420       gdbarch = TUI_SRC_WIN->gdbarch;
421       find_line_pc (cursal.symtab,
422                     TUI_SRC_WIN->start_line_or_addr.u.line_no,
423                     &pc);
424       addr = pc;
425       break;
426     case DISASSEM_COMMAND:
427     case SRC_DISASSEM_COMMAND:
428     case DISASSEM_DATA_COMMAND:
429       gdbarch = TUI_DISASM_WIN->gdbarch;
430       addr = TUI_DISASM_WIN->start_line_or_addr.u.addr;
431       break;
432     default:
433       addr = 0;
434       break;
435     }
436
437   *gdbarch_p = gdbarch;
438   *addr_p = addr;
439 }
440
441
442 /* Answer the previous layout to cycle to.  */
443 static enum tui_layout_type
444 next_layout (void)
445 {
446   int new_layout;
447
448   new_layout = tui_current_layout ();
449   if (new_layout == UNDEFINED_LAYOUT)
450     new_layout = SRC_COMMAND;
451   else
452     {
453       new_layout++;
454       if (new_layout == UNDEFINED_LAYOUT)
455         new_layout = SRC_COMMAND;
456     }
457
458   return (enum tui_layout_type) new_layout;
459 }
460
461
462 /* Answer the next layout to cycle to.  */
463 static enum tui_layout_type
464 prev_layout (void)
465 {
466   int new_layout;
467
468   new_layout = tui_current_layout ();
469   if (new_layout == SRC_COMMAND)
470     new_layout = DISASSEM_DATA_COMMAND;
471   else
472     {
473       new_layout--;
474       if (new_layout == UNDEFINED_LAYOUT)
475         new_layout = DISASSEM_DATA_COMMAND;
476     }
477
478   return (enum tui_layout_type) new_layout;
479 }
480
481 /* Show the Source/Command layout.  */
482 static void
483 show_source_command (void)
484 {
485   show_source_or_disasm_and_command (SRC_COMMAND);
486 }
487
488
489 /* Show the Dissassem/Command layout.  */
490 static void
491 show_disasm_command (void)
492 {
493   show_source_or_disasm_and_command (DISASSEM_COMMAND);
494 }
495
496
497 /* Show the Source/Disassem/Command layout.  */
498 static void
499 show_source_disasm_command (void)
500 {
501   int cmd_height, src_height, asm_height;
502
503   if (TUI_CMD_WIN != NULL)
504     cmd_height = TUI_CMD_WIN->height;
505   else
506     cmd_height = tui_term_height () / 3;
507
508   src_height = (tui_term_height () - cmd_height) / 2;
509   asm_height = tui_term_height () - (src_height + cmd_height);
510
511   if (TUI_SRC_WIN == NULL)
512     tui_win_list[SRC_WIN] = new tui_source_window ();
513   TUI_SRC_WIN->reset (src_height,
514                       tui_term_width (),
515                       0,
516                       0);
517   TUI_SRC_WIN->make_visible (true);
518   TUI_SRC_WIN->m_has_locator = false;
519
520   struct tui_locator_window *locator = tui_locator_win_info_ptr ();
521   gdb_assert (locator != nullptr);
522
523   TUI_SRC_WIN->show_source_content ();
524   if (TUI_DISASM_WIN == NULL)
525     tui_win_list[DISASSEM_WIN] = new tui_disasm_window ();
526   TUI_DISASM_WIN->reset (asm_height,
527                          tui_term_width (),
528                          0,
529                          src_height - 1);
530   TUI_DISASM_WIN->make_visible (true);
531   locator->reset (2 /* 1 */ ,
532                   tui_term_width (),
533                   0,
534                   (src_height + asm_height) - 1);
535   TUI_SRC_WIN->m_has_locator = false;
536   TUI_DISASM_WIN->m_has_locator = true;
537   locator->make_visible (true);
538   tui_show_locator_content ();
539   TUI_DISASM_WIN->show_source_content ();
540
541   if (TUI_CMD_WIN == NULL)
542     tui_win_list[CMD_WIN] = new tui_cmd_window ();
543   TUI_CMD_WIN->reset (cmd_height,
544                       tui_term_width (),
545                       0,
546                       tui_term_height () - cmd_height);
547   /* FIXME tui_cmd_window won't recreate the handle on
548      make_visible, so we need this instead.  */
549   tui_make_window (TUI_CMD_WIN);
550   current_layout = SRC_DISASSEM_COMMAND;
551 }
552
553
554 /* Show the Source/Data/Command or the Dissassembly/Data/Command
555    layout.  */
556 static void
557 show_data (enum tui_layout_type new_layout)
558 {
559   int total_height = (tui_term_height () - TUI_CMD_WIN->height);
560   int src_height, data_height;
561   enum tui_win_type win_type;
562
563   struct tui_locator_window *locator = tui_locator_win_info_ptr ();
564   gdb_assert (locator != nullptr);
565
566   data_height = total_height / 2;
567   src_height = total_height - data_height;
568   if (tui_win_list[DATA_WIN] == nullptr)
569     tui_win_list[DATA_WIN] = new tui_data_window ();
570   tui_win_list[DATA_WIN]->reset (data_height, tui_term_width (), 0, 0);
571   tui_win_list[DATA_WIN]->make_visible (true);
572
573   if (new_layout == SRC_DATA_COMMAND)
574     win_type = SRC_WIN;
575   else
576     win_type = DISASSEM_WIN;
577
578   if (tui_win_list[win_type] == NULL)
579     {
580       if (win_type == SRC_WIN)
581         tui_win_list[win_type] = new tui_source_window ();
582       else
583         tui_win_list[win_type] = new tui_disasm_window ();
584     }
585
586   tui_source_window_base *base
587     = (tui_source_window_base *) tui_win_list[win_type];
588   tui_win_list[win_type]->reset (src_height,
589                                  tui_term_width (),
590                                  0,
591                                  data_height - 1);
592   locator->reset (2 /* 1 */ ,
593                   tui_term_width (),
594                   0,
595                   total_height - 1);
596   base->make_visible (true);
597   base->m_has_locator = true;
598   locator->make_visible (true);
599   tui_show_locator_content ();
600   tui_add_to_source_windows (base);
601   TUI_CMD_WIN->make_visible (true);
602   current_layout = new_layout;
603 }
604
605 void
606 tui_gen_win_info::reset (int height_, int width_,
607                          int origin_x_, int origin_y_)
608 {
609   int h = height_;
610
611   width = width_;
612   height = h;
613   if (h > 1)
614     {
615       viewport_height = h - 1;
616       if (type != CMD_WIN)
617         viewport_height--;
618     }
619   else
620     viewport_height = 1;
621   origin.x = origin_x_;
622   origin.y = origin_y_;
623 }
624
625 /* Show the Source/Command or the Disassem layout.  */
626 static void
627 show_source_or_disasm_and_command (enum tui_layout_type layout_type)
628 {
629   struct tui_source_window_base *win_info;
630   int src_height, cmd_height;
631   struct tui_locator_window *locator = tui_locator_win_info_ptr ();
632   gdb_assert (locator != nullptr);
633
634   if (TUI_CMD_WIN != NULL)
635     cmd_height = TUI_CMD_WIN->height;
636   else
637     cmd_height = tui_term_height () / 3;
638   src_height = tui_term_height () - cmd_height;
639
640   if (layout_type == SRC_COMMAND)
641     {
642       if (tui_win_list[SRC_WIN] == nullptr)
643         tui_win_list[SRC_WIN] = new tui_source_window ();
644       win_info = TUI_SRC_WIN;
645     }
646   else
647     {
648       if (tui_win_list[DISASSEM_WIN] == nullptr)
649         tui_win_list[DISASSEM_WIN] = new tui_disasm_window ();
650       win_info = TUI_DISASM_WIN;
651     }
652
653   locator->reset (2 /* 1 */ ,
654                   tui_term_width (),
655                   0,
656                   src_height - 1);
657   win_info->reset (src_height - 1,
658                    tui_term_width (),
659                    0,
660                    0);
661   win_info->make_visible (true);
662
663
664   win_info->m_has_locator = true;
665   locator->make_visible (true);
666   tui_show_locator_content ();
667   win_info->show_source_content ();
668
669   if (TUI_CMD_WIN == NULL)
670     tui_win_list[CMD_WIN] = new tui_cmd_window ();
671   TUI_CMD_WIN->reset (cmd_height,
672                       tui_term_width (),
673                       0,
674                       src_height);
675   /* FIXME tui_cmd_window won't recreate the handle on
676      make_visible, so we need this instead.  */
677   tui_make_window (TUI_CMD_WIN);
678   current_layout = layout_type;
679 }