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