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