xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/tui/tui-win.c (revision 7863ba460b0a05b553c754e5dbc29247dddec322)
1 /* TUI window generic functions.
2 
3    Copyright (C) 1998-2016 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 /* This module contains procedures for handling tui window functions
23    like resize, scrolling, scrolling, changing focus, etc.
24 
25    Author: Susan B. Macchia  */
26 
27 #include "defs.h"
28 #include "command.h"
29 #include "symtab.h"
30 #include "breakpoint.h"
31 #include "frame.h"
32 #include "cli/cli-cmds.h"
33 #include "top.h"
34 #include "source.h"
35 #include "event-loop.h"
36 
37 #include "tui/tui.h"
38 #include "tui/tui-io.h"
39 #include "tui/tui-data.h"
40 #include "tui/tui-wingeneral.h"
41 #include "tui/tui-stack.h"
42 #include "tui/tui-regs.h"
43 #include "tui/tui-disasm.h"
44 #include "tui/tui-source.h"
45 #include "tui/tui-winsource.h"
46 #include "tui/tui-windata.h"
47 #include "tui/tui-win.h"
48 
49 #include "gdb_curses.h"
50 #include <ctype.h>
51 #include "readline/readline.h"
52 
53 #include <signal.h>
54 
55 /*******************************
56 ** Static Local Decls
57 ********************************/
58 static void make_visible_with_new_height (struct tui_win_info *);
59 static void make_invisible_and_set_new_height (struct tui_win_info *,
60 					       int);
61 static enum tui_status tui_adjust_win_heights (struct tui_win_info *,
62 					       int);
63 static int new_height_ok (struct tui_win_info *, int);
64 static void tui_set_tab_width_command (char *, int);
65 static void tui_refresh_all_command (char *, int);
66 static void tui_set_win_height_command (char *, int);
67 static void tui_all_windows_info (char *, int);
68 static void tui_set_focus_command (char *, int);
69 static void tui_scroll_forward_command (char *, int);
70 static void tui_scroll_backward_command (char *, int);
71 static void tui_scroll_left_command (char *, int);
72 static void tui_scroll_right_command (char *, int);
73 static void parse_scrolling_args (char *,
74 				  struct tui_win_info **,
75 				  int *);
76 
77 
78 /***************************************
79 ** DEFINITIONS
80 ***************************************/
81 #define WIN_HEIGHT_USAGE    "Usage: winheight <win_name> [+ | -] <#lines>\n"
82 #define XDBWIN_HEIGHT_USAGE "Usage: w <#lines>\n"
83 #define FOCUS_USAGE         "Usage: focus {<win> | next | prev}\n"
84 
85 /***************************************
86 ** PUBLIC FUNCTIONS
87 ***************************************/
88 
89 #ifndef ACS_LRCORNER
90 #  define ACS_LRCORNER '+'
91 #endif
92 #ifndef ACS_LLCORNER
93 #  define ACS_LLCORNER '+'
94 #endif
95 #ifndef ACS_ULCORNER
96 #  define ACS_ULCORNER '+'
97 #endif
98 #ifndef ACS_URCORNER
99 #  define ACS_URCORNER '+'
100 #endif
101 #ifndef ACS_HLINE
102 #  define ACS_HLINE '-'
103 #endif
104 #ifndef ACS_VLINE
105 #  define ACS_VLINE '|'
106 #endif
107 
108 /* Possible values for tui-border-kind variable.  */
109 static const char *const tui_border_kind_enums[] = {
110   "space",
111   "ascii",
112   "acs",
113   NULL
114 };
115 
116 /* Possible values for tui-border-mode and tui-active-border-mode.  */
117 static const char *const tui_border_mode_enums[] = {
118   "normal",
119   "standout",
120   "reverse",
121   "half",
122   "half-standout",
123   "bold",
124   "bold-standout",
125   NULL
126 };
127 
128 struct tui_translate
129 {
130   const char *name;
131   int value;
132 };
133 
134 /* Translation table for border-mode variables.
135    The list of values must be terminated by a NULL.
136    After the NULL value, an entry defines the default.  */
137 struct tui_translate tui_border_mode_translate[] = {
138   { "normal",		A_NORMAL },
139   { "standout",		A_STANDOUT },
140   { "reverse",		A_REVERSE },
141   { "half",		A_DIM },
142   { "half-standout",	A_DIM | A_STANDOUT },
143   { "bold",		A_BOLD },
144   { "bold-standout",	A_BOLD | A_STANDOUT },
145   { 0, 0 },
146   { "normal",		A_NORMAL }
147 };
148 
149 /* Translation tables for border-kind, one for each border
150    character (see wborder, border curses operations).
151    -1 is used to indicate the ACS because ACS characters
152    are determined at run time by curses (depends on terminal).  */
153 struct tui_translate tui_border_kind_translate_vline[] = {
154   { "space",    ' ' },
155   { "ascii",    '|' },
156   { "acs",      -1 },
157   { 0, 0 },
158   { "ascii",    '|' }
159 };
160 
161 struct tui_translate tui_border_kind_translate_hline[] = {
162   { "space",    ' ' },
163   { "ascii",    '-' },
164   { "acs",      -1 },
165   { 0, 0 },
166   { "ascii",    '-' }
167 };
168 
169 struct tui_translate tui_border_kind_translate_ulcorner[] = {
170   { "space",    ' ' },
171   { "ascii",    '+' },
172   { "acs",      -1 },
173   { 0, 0 },
174   { "ascii",    '+' }
175 };
176 
177 struct tui_translate tui_border_kind_translate_urcorner[] = {
178   { "space",    ' ' },
179   { "ascii",    '+' },
180   { "acs",      -1 },
181   { 0, 0 },
182   { "ascii",    '+' }
183 };
184 
185 struct tui_translate tui_border_kind_translate_llcorner[] = {
186   { "space",    ' ' },
187   { "ascii",    '+' },
188   { "acs",      -1 },
189   { 0, 0 },
190   { "ascii",    '+' }
191 };
192 
193 struct tui_translate tui_border_kind_translate_lrcorner[] = {
194   { "space",    ' ' },
195   { "ascii",    '+' },
196   { "acs",      -1 },
197   { 0, 0 },
198   { "ascii",    '+' }
199 };
200 
201 
202 /* Tui configuration variables controlled with set/show command.  */
203 const char *tui_active_border_mode = "bold-standout";
204 static void
205 show_tui_active_border_mode (struct ui_file *file,
206 			     int from_tty,
207 			     struct cmd_list_element *c,
208 			     const char *value)
209 {
210   fprintf_filtered (file, _("\
211 The attribute mode to use for the active TUI window border is \"%s\".\n"),
212 		    value);
213 }
214 
215 const char *tui_border_mode = "normal";
216 static void
217 show_tui_border_mode (struct ui_file *file,
218 		      int from_tty,
219 		      struct cmd_list_element *c,
220 		      const char *value)
221 {
222   fprintf_filtered (file, _("\
223 The attribute mode to use for the TUI window borders is \"%s\".\n"),
224 		    value);
225 }
226 
227 const char *tui_border_kind = "acs";
228 static void
229 show_tui_border_kind (struct ui_file *file,
230 		      int from_tty,
231 		      struct cmd_list_element *c,
232 		      const char *value)
233 {
234   fprintf_filtered (file, _("The kind of border for TUI windows is \"%s\".\n"),
235 		    value);
236 }
237 
238 
239 /* Tui internal configuration variables.  These variables are updated
240    by tui_update_variables to reflect the tui configuration
241    variables.  */
242 chtype tui_border_vline;
243 chtype tui_border_hline;
244 chtype tui_border_ulcorner;
245 chtype tui_border_urcorner;
246 chtype tui_border_llcorner;
247 chtype tui_border_lrcorner;
248 
249 int tui_border_attrs;
250 int tui_active_border_attrs;
251 
252 /* Identify the item in the translation table.
253    When the item is not recognized, use the default entry.  */
254 static struct tui_translate *
255 translate (const char *name, struct tui_translate *table)
256 {
257   while (table->name)
258     {
259       if (name && strcmp (table->name, name) == 0)
260         return table;
261       table++;
262     }
263 
264   /* Not found, return default entry.  */
265   table++;
266   return table;
267 }
268 
269 /* Update the tui internal configuration according to gdb settings.
270    Returns 1 if the configuration has changed and the screen should
271    be redrawn.  */
272 int
273 tui_update_variables (void)
274 {
275   int need_redraw = 0;
276   struct tui_translate *entry;
277 
278   entry = translate (tui_border_mode, tui_border_mode_translate);
279   if (tui_border_attrs != entry->value)
280     {
281       tui_border_attrs = entry->value;
282       need_redraw = 1;
283     }
284   entry = translate (tui_active_border_mode, tui_border_mode_translate);
285   if (tui_active_border_attrs != entry->value)
286     {
287       tui_active_border_attrs = entry->value;
288       need_redraw = 1;
289     }
290 
291   /* If one corner changes, all characters are changed.
292      Only check the first one.  The ACS characters are determined at
293      run time by curses terminal management.  */
294   entry = translate (tui_border_kind, tui_border_kind_translate_lrcorner);
295   if (tui_border_lrcorner != (chtype) entry->value)
296     {
297       tui_border_lrcorner = (entry->value < 0) ? ACS_LRCORNER : entry->value;
298       need_redraw = 1;
299     }
300   entry = translate (tui_border_kind, tui_border_kind_translate_llcorner);
301   tui_border_llcorner = (entry->value < 0) ? ACS_LLCORNER : entry->value;
302 
303   entry = translate (tui_border_kind, tui_border_kind_translate_ulcorner);
304   tui_border_ulcorner = (entry->value < 0) ? ACS_ULCORNER : entry->value;
305 
306   entry = translate (tui_border_kind, tui_border_kind_translate_urcorner);
307   tui_border_urcorner = (entry->value < 0) ? ACS_URCORNER : entry->value;
308 
309   entry = translate (tui_border_kind, tui_border_kind_translate_hline);
310   tui_border_hline = (entry->value < 0) ? ACS_HLINE : entry->value;
311 
312   entry = translate (tui_border_kind, tui_border_kind_translate_vline);
313   tui_border_vline = (entry->value < 0) ? ACS_VLINE : entry->value;
314 
315   return need_redraw;
316 }
317 
318 static void
319 set_tui_cmd (char *args, int from_tty)
320 {
321 }
322 
323 static void
324 show_tui_cmd (char *args, int from_tty)
325 {
326 }
327 
328 static struct cmd_list_element *tuilist;
329 
330 static void
331 tui_command (char *args, int from_tty)
332 {
333   printf_unfiltered (_("\"tui\" must be followed by the name of a "
334                      "tui command.\n"));
335   help_list (tuilist, "tui ", all_commands, gdb_stdout);
336 }
337 
338 struct cmd_list_element **
339 tui_get_cmd_list (void)
340 {
341   if (tuilist == 0)
342     add_prefix_cmd ("tui", class_tui, tui_command,
343                     _("Text User Interface commands."),
344                     &tuilist, "tui ", 0, &cmdlist);
345   return &tuilist;
346 }
347 
348 /* The set_func hook of "set tui ..." commands that affect the window
349    borders on the TUI display.  */
350 void
351 tui_set_var_cmd (char *null_args, int from_tty, struct cmd_list_element *c)
352 {
353   if (tui_update_variables () && tui_active)
354     tui_rehighlight_all ();
355 }
356 
357 /* Generic window name completion function.  Complete window name pointed
358    to by TEXT and WORD.  If INCLUDE_NEXT_PREV_P is true then the special
359    window names 'next' and 'prev' will also be considered as possible
360    completions of the window name.  */
361 
362 static VEC (char_ptr) *
363 window_name_completer (int include_next_prev_p,
364 		       const char *text, const char *word)
365 {
366   VEC (const_char_ptr) *completion_name_vec = NULL;
367   VEC (char_ptr) *matches_vec;
368   int win_type;
369 
370   for (win_type = SRC_WIN; win_type < MAX_MAJOR_WINDOWS; win_type++)
371     {
372       const char *completion_name = NULL;
373 
374       /* We can't focus on an invisible window.  */
375       if (tui_win_list[win_type] == NULL
376 	  || !tui_win_list[win_type]->generic.is_visible)
377 	continue;
378 
379       completion_name = tui_win_name (&tui_win_list [win_type]->generic);
380       gdb_assert (completion_name != NULL);
381       VEC_safe_push (const_char_ptr, completion_name_vec, completion_name);
382     }
383 
384   /* If no windows are considered visible then the TUI has not yet been
385      initialized.  But still "focus src" and "focus cmd" will work because
386      invoking the focus command will entail initializing the TUI which sets the
387      default layout to SRC_COMMAND.  */
388   if (VEC_length (const_char_ptr, completion_name_vec) == 0)
389     {
390       VEC_safe_push (const_char_ptr, completion_name_vec, SRC_NAME);
391       VEC_safe_push (const_char_ptr, completion_name_vec, CMD_NAME);
392     }
393 
394   if (include_next_prev_p)
395     {
396       VEC_safe_push (const_char_ptr, completion_name_vec, "next");
397       VEC_safe_push (const_char_ptr, completion_name_vec, "prev");
398     }
399 
400   VEC_safe_push (const_char_ptr, completion_name_vec, NULL);
401   matches_vec
402     = complete_on_enum (VEC_address (const_char_ptr, completion_name_vec),
403 			text, word);
404 
405   VEC_free (const_char_ptr, completion_name_vec);
406 
407   return matches_vec;
408 }
409 
410 /* Complete possible window names to focus on.  TEXT is the complete text
411    entered so far, WORD is the word currently being completed.  */
412 
413 static VEC (char_ptr) *
414 focus_completer (struct cmd_list_element *ignore,
415 		  const char *text, const char *word)
416 {
417   return window_name_completer (1, text, word);
418 }
419 
420 /* Complete possible window names for winheight command.  TEXT is the
421    complete text entered so far, WORD is the word currently being
422    completed.  */
423 
424 static VEC (char_ptr) *
425 winheight_completer (struct cmd_list_element *ignore,
426 		     const char *text, const char *word)
427 {
428   /* The first word is the window name.  That we can complete.  Subsequent
429      words can't be completed.  */
430   if (word != text)
431     return NULL;
432 
433   return window_name_completer (0, text, word);
434 }
435 
436 /* Function to initialize gdb commands, for tui window
437    manipulation.  */
438 
439 /* Provide a prototype to silence -Wmissing-prototypes.  */
440 extern initialize_file_ftype _initialize_tui_win;
441 
442 void
443 _initialize_tui_win (void)
444 {
445   static struct cmd_list_element *tui_setlist;
446   static struct cmd_list_element *tui_showlist;
447   struct cmd_list_element *cmd;
448 
449   /* Define the classes of commands.
450      They will appear in the help list in the reverse of this order.  */
451   add_prefix_cmd ("tui", class_tui, set_tui_cmd,
452                   _("TUI configuration variables"),
453 		  &tui_setlist, "set tui ",
454 		  0 /* allow-unknown */, &setlist);
455   add_prefix_cmd ("tui", class_tui, show_tui_cmd,
456                   _("TUI configuration variables"),
457 		  &tui_showlist, "show tui ",
458 		  0 /* allow-unknown */, &showlist);
459 
460   add_com ("refresh", class_tui, tui_refresh_all_command,
461            _("Refresh the terminal display.\n"));
462   add_com ("tabset", class_tui, tui_set_tab_width_command, _("\
463 Set the width (in characters) of tab stops.\n\
464 Usage: tabset <n>\n"));
465   cmd = add_com ("winheight", class_tui, tui_set_win_height_command, _("\
466 Set or modify the height of a specified window.\n\
467 Usage: winheight <win_name> [+ | -] <#lines>\n\
468 Window names are:\n\
469 src  : the source window\n\
470 cmd  : the command window\n\
471 asm  : the disassembly window\n\
472 regs : the register display\n"));
473   add_com_alias ("wh", "winheight", class_tui, 0);
474   set_cmd_completer (cmd, winheight_completer);
475   add_info ("win", tui_all_windows_info,
476 	    _("List of all displayed windows.\n"));
477   cmd = add_com ("focus", class_tui, tui_set_focus_command, _("\
478 Set focus to named window or next/prev window.\n\
479 Usage: focus {<win> | next | prev}\n\
480 Valid Window names are:\n\
481 src  : the source window\n\
482 asm  : the disassembly window\n\
483 regs : the register display\n\
484 cmd  : the command window\n"));
485   add_com_alias ("fs", "focus", class_tui, 0);
486   set_cmd_completer (cmd, focus_completer);
487   add_com ("+", class_tui, tui_scroll_forward_command, _("\
488 Scroll window forward.\n\
489 Usage: + [win] [n]\n"));
490   add_com ("-", class_tui, tui_scroll_backward_command, _("\
491 Scroll window backward.\n\
492 Usage: - [win] [n]\n"));
493   add_com ("<", class_tui, tui_scroll_left_command, _("\
494 Scroll window text to the left.\n\
495 Usage: < [win] [n]\n"));
496   add_com (">", class_tui, tui_scroll_right_command, _("\
497 Scroll window text to the right.\n\
498 Usage: > [win] [n]\n"));
499 
500   /* Define the tui control variables.  */
501   add_setshow_enum_cmd ("border-kind", no_class, tui_border_kind_enums,
502 			&tui_border_kind, _("\
503 Set the kind of border for TUI windows."), _("\
504 Show the kind of border for TUI windows."), _("\
505 This variable controls the border of TUI windows:\n\
506 space           use a white space\n\
507 ascii           use ascii characters + - | for the border\n\
508 acs             use the Alternate Character Set"),
509 			tui_set_var_cmd,
510 			show_tui_border_kind,
511 			&tui_setlist, &tui_showlist);
512 
513   add_setshow_enum_cmd ("border-mode", no_class, tui_border_mode_enums,
514 			&tui_border_mode, _("\
515 Set the attribute mode to use for the TUI window borders."), _("\
516 Show the attribute mode to use for the TUI window borders."), _("\
517 This variable controls the attributes to use for the window borders:\n\
518 normal          normal display\n\
519 standout        use highlight mode of terminal\n\
520 reverse         use reverse video mode\n\
521 half            use half bright\n\
522 half-standout   use half bright and standout mode\n\
523 bold            use extra bright or bold\n\
524 bold-standout   use extra bright or bold with standout mode"),
525 			tui_set_var_cmd,
526 			show_tui_border_mode,
527 			&tui_setlist, &tui_showlist);
528 
529   add_setshow_enum_cmd ("active-border-mode", no_class, tui_border_mode_enums,
530 			&tui_active_border_mode, _("\
531 Set the attribute mode to use for the active TUI window border."), _("\
532 Show the attribute mode to use for the active TUI window border."), _("\
533 This variable controls the attributes to use for the active window border:\n\
534 normal          normal display\n\
535 standout        use highlight mode of terminal\n\
536 reverse         use reverse video mode\n\
537 half            use half bright\n\
538 half-standout   use half bright and standout mode\n\
539 bold            use extra bright or bold\n\
540 bold-standout   use extra bright or bold with standout mode"),
541 			tui_set_var_cmd,
542 			show_tui_active_border_mode,
543 			&tui_setlist, &tui_showlist);
544 }
545 
546 /* Update gdb's knowledge of the terminal size.  */
547 void
548 tui_update_gdb_sizes (void)
549 {
550   int width, height;
551 
552   if (tui_active)
553     {
554       width = TUI_CMD_WIN->generic.width;
555       height = TUI_CMD_WIN->generic.height;
556     }
557   else
558     {
559       width = tui_term_width ();
560       height = tui_term_height ();
561     }
562 
563   set_screen_width_and_height (width, height);
564 }
565 
566 
567 /* Set the logical focus to win_info.  */
568 void
569 tui_set_win_focus_to (struct tui_win_info *win_info)
570 {
571   if (win_info != NULL)
572     {
573       struct tui_win_info *win_with_focus = tui_win_with_focus ();
574 
575       if (win_with_focus != NULL
576 	  && win_with_focus->generic.type != CMD_WIN)
577 	tui_unhighlight_win (win_with_focus);
578       tui_set_win_with_focus (win_info);
579       if (win_info->generic.type != CMD_WIN)
580 	tui_highlight_win (win_info);
581     }
582 }
583 
584 
585 void
586 tui_scroll_forward (struct tui_win_info *win_to_scroll,
587 		    int num_to_scroll)
588 {
589   if (win_to_scroll != TUI_CMD_WIN)
590     {
591       int _num_to_scroll = num_to_scroll;
592 
593       if (num_to_scroll == 0)
594 	_num_to_scroll = win_to_scroll->generic.height - 3;
595 
596       /* If we are scrolling the source or disassembly window, do a
597          "psuedo" scroll since not all of the source is in memory,
598          only what is in the viewport.  If win_to_scroll is the
599          command window do nothing since the term should handle
600          it.  */
601       if (win_to_scroll == TUI_SRC_WIN)
602 	tui_vertical_source_scroll (FORWARD_SCROLL, _num_to_scroll);
603       else if (win_to_scroll == TUI_DISASM_WIN)
604 	tui_vertical_disassem_scroll (FORWARD_SCROLL, _num_to_scroll);
605       else if (win_to_scroll == TUI_DATA_WIN)
606 	tui_vertical_data_scroll (FORWARD_SCROLL, _num_to_scroll);
607     }
608 }
609 
610 void
611 tui_scroll_backward (struct tui_win_info *win_to_scroll,
612 		     int num_to_scroll)
613 {
614   if (win_to_scroll != TUI_CMD_WIN)
615     {
616       int _num_to_scroll = num_to_scroll;
617 
618       if (num_to_scroll == 0)
619 	_num_to_scroll = win_to_scroll->generic.height - 3;
620 
621       /* If we are scrolling the source or disassembly window, do a
622          "psuedo" scroll since not all of the source is in memory,
623          only what is in the viewport.  If win_to_scroll is the
624          command window do nothing since the term should handle
625          it.  */
626       if (win_to_scroll == TUI_SRC_WIN)
627 	tui_vertical_source_scroll (BACKWARD_SCROLL, _num_to_scroll);
628       else if (win_to_scroll == TUI_DISASM_WIN)
629 	tui_vertical_disassem_scroll (BACKWARD_SCROLL, _num_to_scroll);
630       else if (win_to_scroll == TUI_DATA_WIN)
631 	tui_vertical_data_scroll (BACKWARD_SCROLL, _num_to_scroll);
632     }
633 }
634 
635 
636 void
637 tui_scroll_left (struct tui_win_info *win_to_scroll,
638 		 int num_to_scroll)
639 {
640   if (win_to_scroll != TUI_CMD_WIN)
641     {
642       int _num_to_scroll = num_to_scroll;
643 
644       if (_num_to_scroll == 0)
645 	_num_to_scroll = 1;
646 
647       /* If we are scrolling the source or disassembly window, do a
648          "psuedo" scroll since not all of the source is in memory,
649          only what is in the viewport. If win_to_scroll is the command
650          window do nothing since the term should handle it.  */
651       if (win_to_scroll == TUI_SRC_WIN
652 	  || win_to_scroll == TUI_DISASM_WIN)
653 	tui_horizontal_source_scroll (win_to_scroll, LEFT_SCROLL,
654 				      _num_to_scroll);
655     }
656 }
657 
658 
659 void
660 tui_scroll_right (struct tui_win_info *win_to_scroll,
661 		  int num_to_scroll)
662 {
663   if (win_to_scroll != TUI_CMD_WIN)
664     {
665       int _num_to_scroll = num_to_scroll;
666 
667       if (_num_to_scroll == 0)
668 	_num_to_scroll = 1;
669 
670       /* If we are scrolling the source or disassembly window, do a
671          "psuedo" scroll since not all of the source is in memory,
672          only what is in the viewport. If win_to_scroll is the command
673          window do nothing since the term should handle it.  */
674       if (win_to_scroll == TUI_SRC_WIN
675 	  || win_to_scroll == TUI_DISASM_WIN)
676 	tui_horizontal_source_scroll (win_to_scroll, RIGHT_SCROLL,
677 				      _num_to_scroll);
678     }
679 }
680 
681 
682 /* Scroll a window.  Arguments are passed through a va_list.  */
683 void
684 tui_scroll (enum tui_scroll_direction direction,
685 	    struct tui_win_info *win_to_scroll,
686 	    int num_to_scroll)
687 {
688   switch (direction)
689     {
690     case FORWARD_SCROLL:
691       tui_scroll_forward (win_to_scroll, num_to_scroll);
692       break;
693     case BACKWARD_SCROLL:
694       tui_scroll_backward (win_to_scroll, num_to_scroll);
695       break;
696     case LEFT_SCROLL:
697       tui_scroll_left (win_to_scroll, num_to_scroll);
698       break;
699     case RIGHT_SCROLL:
700       tui_scroll_right (win_to_scroll, num_to_scroll);
701       break;
702     default:
703       break;
704     }
705 }
706 
707 
708 void
709 tui_refresh_all_win (void)
710 {
711   int type;
712 
713   clearok (curscr, TRUE);
714   tui_refresh_all (tui_win_list);
715   for (type = SRC_WIN; type < MAX_MAJOR_WINDOWS; type++)
716     {
717       if (tui_win_list[type]
718 	  && tui_win_list[type]->generic.is_visible)
719 	{
720 	  switch (type)
721 	    {
722 	    case SRC_WIN:
723 	    case DISASSEM_WIN:
724 	      tui_show_source_content (tui_win_list[type]);
725 	      tui_check_and_display_highlight_if_needed (tui_win_list[type]);
726 	      tui_erase_exec_info_content (tui_win_list[type]);
727 	      tui_update_exec_info (tui_win_list[type]);
728 	      break;
729 	    case DATA_WIN:
730 	      tui_refresh_data_win ();
731 	      break;
732 	    default:
733 	      break;
734 	    }
735 	}
736     }
737   tui_show_locator_content ();
738 }
739 
740 void
741 tui_rehighlight_all (void)
742 {
743   int type;
744 
745   for (type = SRC_WIN; type < MAX_MAJOR_WINDOWS; type++)
746     tui_check_and_display_highlight_if_needed (tui_win_list[type]);
747 }
748 
749 /* Resize all the windows based on the terminal size.  This function
750    gets called from within the readline sinwinch handler.  */
751 void
752 tui_resize_all (void)
753 {
754   int height_diff, width_diff;
755   int screenheight, screenwidth;
756 
757   rl_get_screen_size (&screenheight, &screenwidth);
758   width_diff = screenwidth - tui_term_width ();
759   height_diff = screenheight - tui_term_height ();
760   if (height_diff || width_diff)
761     {
762       enum tui_layout_type cur_layout = tui_current_layout ();
763       struct tui_win_info *win_with_focus = tui_win_with_focus ();
764       struct tui_win_info *first_win;
765       struct tui_win_info *second_win;
766       struct tui_gen_win_info *locator = tui_locator_win_info_ptr ();
767       int win_type;
768       int new_height, split_diff, cmd_split_diff, num_wins_displayed = 2;
769 
770 #ifdef HAVE_RESIZE_TERM
771       resize_term (screenheight, screenwidth);
772 #endif
773       /* Turn keypad off while we resize.  */
774       if (win_with_focus != TUI_CMD_WIN)
775 	keypad (TUI_CMD_WIN->generic.handle, FALSE);
776       tui_update_gdb_sizes ();
777       tui_set_term_height_to (screenheight);
778       tui_set_term_width_to (screenwidth);
779       if (cur_layout == SRC_DISASSEM_COMMAND
780 	  || cur_layout == SRC_DATA_COMMAND
781 	  || cur_layout == DISASSEM_DATA_COMMAND)
782 	num_wins_displayed++;
783       split_diff = height_diff / num_wins_displayed;
784       cmd_split_diff = split_diff;
785       if (height_diff % num_wins_displayed)
786 	{
787 	  if (height_diff < 0)
788 	    cmd_split_diff--;
789 	  else
790            cmd_split_diff++;
791        }
792       /* Now adjust each window.  */
793       /* erase + clearok are used instead of a straightforward clear as
794          AIX 5.3 does not define clear.  */
795       erase ();
796       clearok (curscr, TRUE);
797       refresh ();
798       switch (cur_layout)
799        {
800 	case SRC_COMMAND:
801 	case DISASSEM_COMMAND:
802 	  first_win = (struct tui_win_info *) (tui_source_windows ())->list[0];
803 	  first_win->generic.width += width_diff;
804 	  locator->width += width_diff;
805 	  /* Check for invalid heights.  */
806 	  if (height_diff == 0)
807 	    new_height = first_win->generic.height;
808 	  else if ((first_win->generic.height + split_diff) >=
809 		   (screenheight - MIN_CMD_WIN_HEIGHT - 1))
810 	    new_height = screenheight - MIN_CMD_WIN_HEIGHT - 1;
811 	  else if ((first_win->generic.height + split_diff) <= 0)
812 	    new_height = MIN_WIN_HEIGHT;
813 	  else
814 	    new_height = first_win->generic.height + split_diff;
815 
816 	  locator->origin.y = new_height + 1;
817 	  make_invisible_and_set_new_height (first_win, new_height);
818 	  TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1;
819 	  TUI_CMD_WIN->generic.width += width_diff;
820 	  new_height = screenheight - TUI_CMD_WIN->generic.origin.y;
821 	  make_invisible_and_set_new_height (TUI_CMD_WIN, new_height);
822 	  make_visible_with_new_height (first_win);
823 	  make_visible_with_new_height (TUI_CMD_WIN);
824 	  if (first_win->generic.content_size <= 0)
825 	    tui_erase_source_content (first_win, EMPTY_SOURCE_PROMPT);
826 	  break;
827 	default:
828 	  if (cur_layout == SRC_DISASSEM_COMMAND)
829 	    {
830 	      first_win = TUI_SRC_WIN;
831 	      first_win->generic.width += width_diff;
832 	      second_win = TUI_DISASM_WIN;
833 	      second_win->generic.width += width_diff;
834 	    }
835 	  else
836 	    {
837 	      first_win = TUI_DATA_WIN;
838 	      first_win->generic.width += width_diff;
839 	      second_win = (struct tui_win_info *)
840 		(tui_source_windows ())->list[0];
841 	      second_win->generic.width += width_diff;
842 	    }
843 	  /* Change the first window's height/width.  */
844 	  /* Check for invalid heights.  */
845 	  if (height_diff == 0)
846 	    new_height = first_win->generic.height;
847 	  else if ((first_win->generic.height +
848 		    second_win->generic.height + (split_diff * 2)) >=
849 		   (screenheight - MIN_CMD_WIN_HEIGHT - 1))
850 	    new_height = (screenheight - MIN_CMD_WIN_HEIGHT - 1) / 2;
851 	  else if ((first_win->generic.height + split_diff) <= 0)
852 	    new_height = MIN_WIN_HEIGHT;
853 	  else
854 	    new_height = first_win->generic.height + split_diff;
855 	  make_invisible_and_set_new_height (first_win, new_height);
856 
857 	  locator->width += width_diff;
858 
859 	  /* Change the second window's height/width.  */
860 	  /* Check for invalid heights.  */
861 	  if (height_diff == 0)
862 	    new_height = second_win->generic.height;
863 	  else if ((first_win->generic.height +
864 		    second_win->generic.height + (split_diff * 2)) >=
865 		   (screenheight - MIN_CMD_WIN_HEIGHT - 1))
866 	    {
867 	      new_height = screenheight - MIN_CMD_WIN_HEIGHT - 1;
868 	      if (new_height % 2)
869 		new_height = (new_height / 2) + 1;
870 	      else
871 		new_height /= 2;
872 	    }
873 	  else if ((second_win->generic.height + split_diff) <= 0)
874 	    new_height = MIN_WIN_HEIGHT;
875 	  else
876 	    new_height = second_win->generic.height + split_diff;
877 	  second_win->generic.origin.y = first_win->generic.height - 1;
878 	  make_invisible_and_set_new_height (second_win, new_height);
879 
880 	  /* Change the command window's height/width.  */
881 	  TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1;
882 	  make_invisible_and_set_new_height (TUI_CMD_WIN,
883 					     TUI_CMD_WIN->generic.height
884 					     + cmd_split_diff);
885 	  make_visible_with_new_height (first_win);
886 	  make_visible_with_new_height (second_win);
887 	  make_visible_with_new_height (TUI_CMD_WIN);
888 	  if (first_win->generic.content_size <= 0)
889 	    tui_erase_source_content (first_win, EMPTY_SOURCE_PROMPT);
890 	  if (second_win->generic.content_size <= 0)
891 	    tui_erase_source_content (second_win, EMPTY_SOURCE_PROMPT);
892 	  break;
893 	}
894       /* Now remove all invisible windows, and their content so that
895          they get created again when called for with the new size.  */
896       for (win_type = SRC_WIN; (win_type < MAX_MAJOR_WINDOWS); win_type++)
897 	{
898 	  if (win_type != CMD_WIN
899 	      && (tui_win_list[win_type] != NULL)
900 	      && !tui_win_list[win_type]->generic.is_visible)
901 	    {
902 	      tui_free_window (tui_win_list[win_type]);
903 	      tui_win_list[win_type] = NULL;
904 	    }
905 	}
906       /* Turn keypad back on, unless focus is in the command
907 	 window.  */
908       if (win_with_focus != TUI_CMD_WIN)
909 	keypad (TUI_CMD_WIN->generic.handle, TRUE);
910     }
911 }
912 
913 #ifdef SIGWINCH
914 /* Token for use by TUI's asynchronous SIGWINCH handler.  */
915 static struct async_signal_handler *tui_sigwinch_token;
916 
917 /* TUI's SIGWINCH signal handler.  */
918 static void
919 tui_sigwinch_handler (int signal)
920 {
921   mark_async_signal_handler (tui_sigwinch_token);
922   tui_set_win_resized_to (TRUE);
923 }
924 
925 /* Callback for asynchronously resizing TUI following a SIGWINCH signal.  */
926 static void
927 tui_async_resize_screen (gdb_client_data arg)
928 {
929   rl_resize_terminal ();
930 
931   if (!tui_active)
932     {
933       int screen_height, screen_width;
934 
935       rl_get_screen_size (&screen_height, &screen_width);
936       set_screen_width_and_height (screen_width, screen_height);
937 
938       /* win_resized is left set so that the next call to tui_enable()
939 	 resizes the TUI windows.  */
940     }
941   else
942     {
943       tui_set_win_resized_to (FALSE);
944       tui_resize_all ();
945       tui_refresh_all_win ();
946       tui_update_gdb_sizes ();
947       tui_redisplay_readline ();
948     }
949 }
950 #endif
951 
952 /* Initialize TUI's SIGWINCH signal handler.  Note that the handler is not
953    uninstalled when we exit TUI, so the handler should not assume that TUI is
954    always active.  */
955 void
956 tui_initialize_win (void)
957 {
958 #ifdef SIGWINCH
959   tui_sigwinch_token
960     = create_async_signal_handler (tui_async_resize_screen, NULL);
961 
962   {
963 #ifdef HAVE_SIGACTION
964     struct sigaction old_winch;
965 
966     memset (&old_winch, 0, sizeof (old_winch));
967     old_winch.sa_handler = &tui_sigwinch_handler;
968 #ifdef SA_RESTART
969     old_winch.sa_flags = SA_RESTART;
970 #endif
971     sigaction (SIGWINCH, &old_winch, NULL);
972 #else
973     signal (SIGWINCH, &tui_sigwinch_handler);
974 #endif
975   }
976 #endif
977 }
978 
979 
980 /*************************
981 ** STATIC LOCAL FUNCTIONS
982 **************************/
983 
984 
985 static void
986 tui_scroll_forward_command (char *arg, int from_tty)
987 {
988   int num_to_scroll = 1;
989   struct tui_win_info *win_to_scroll;
990 
991   /* Make sure the curses mode is enabled.  */
992   tui_enable ();
993   if (arg == (char *) NULL)
994     parse_scrolling_args (arg, &win_to_scroll, (int *) NULL);
995   else
996     parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
997   tui_scroll (FORWARD_SCROLL, win_to_scroll, num_to_scroll);
998 }
999 
1000 
1001 static void
1002 tui_scroll_backward_command (char *arg, int from_tty)
1003 {
1004   int num_to_scroll = 1;
1005   struct tui_win_info *win_to_scroll;
1006 
1007   /* Make sure the curses mode is enabled.  */
1008   tui_enable ();
1009   if (arg == (char *) NULL)
1010     parse_scrolling_args (arg, &win_to_scroll, (int *) NULL);
1011   else
1012     parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
1013   tui_scroll (BACKWARD_SCROLL, win_to_scroll, num_to_scroll);
1014 }
1015 
1016 
1017 static void
1018 tui_scroll_left_command (char *arg, int from_tty)
1019 {
1020   int num_to_scroll;
1021   struct tui_win_info *win_to_scroll;
1022 
1023   /* Make sure the curses mode is enabled.  */
1024   tui_enable ();
1025   parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
1026   tui_scroll (LEFT_SCROLL, win_to_scroll, num_to_scroll);
1027 }
1028 
1029 
1030 static void
1031 tui_scroll_right_command (char *arg, int from_tty)
1032 {
1033   int num_to_scroll;
1034   struct tui_win_info *win_to_scroll;
1035 
1036   /* Make sure the curses mode is enabled.  */
1037   tui_enable ();
1038   parse_scrolling_args (arg, &win_to_scroll, &num_to_scroll);
1039   tui_scroll (RIGHT_SCROLL, win_to_scroll, num_to_scroll);
1040 }
1041 
1042 
1043 /* Set focus to the window named by 'arg'.  */
1044 static void
1045 tui_set_focus (char *arg, int from_tty)
1046 {
1047   if (arg != (char *) NULL)
1048     {
1049       char *buf_ptr = (char *) xstrdup (arg);
1050       int i;
1051       struct tui_win_info *win_info = NULL;
1052 
1053       for (i = 0; (i < strlen (buf_ptr)); i++)
1054 	buf_ptr[i] = tolower (arg[i]);
1055 
1056       if (subset_compare (buf_ptr, "next"))
1057 	win_info = tui_next_win (tui_win_with_focus ());
1058       else if (subset_compare (buf_ptr, "prev"))
1059 	win_info = tui_prev_win (tui_win_with_focus ());
1060       else
1061 	win_info = tui_partial_win_by_name (buf_ptr);
1062 
1063       if (win_info == (struct tui_win_info *) NULL
1064 	  || !win_info->generic.is_visible)
1065 	warning (_("Invalid window specified. \n\
1066 The window name specified must be valid and visible.\n"));
1067       else
1068 	{
1069 	  tui_set_win_focus_to (win_info);
1070 	  keypad (TUI_CMD_WIN->generic.handle, (win_info != TUI_CMD_WIN));
1071 	}
1072 
1073       if (TUI_DATA_WIN && TUI_DATA_WIN->generic.is_visible)
1074 	tui_refresh_data_win ();
1075       xfree (buf_ptr);
1076       printf_filtered (_("Focus set to %s window.\n"),
1077 		       tui_win_name (&tui_win_with_focus ()->generic));
1078     }
1079   else
1080     warning (_("Incorrect Number of Arguments.\n%s"), FOCUS_USAGE);
1081 }
1082 
1083 static void
1084 tui_set_focus_command (char *arg, int from_tty)
1085 {
1086   /* Make sure the curses mode is enabled.  */
1087   tui_enable ();
1088   tui_set_focus (arg, from_tty);
1089 }
1090 
1091 
1092 static void
1093 tui_all_windows_info (char *arg, int from_tty)
1094 {
1095   int type;
1096   struct tui_win_info *win_with_focus = tui_win_with_focus ();
1097 
1098   for (type = SRC_WIN; (type < MAX_MAJOR_WINDOWS); type++)
1099     if (tui_win_list[type]
1100 	&& tui_win_list[type]->generic.is_visible)
1101       {
1102 	if (win_with_focus == tui_win_list[type])
1103 	  printf_filtered ("        %s\t(%d lines)  <has focus>\n",
1104 			   tui_win_name (&tui_win_list[type]->generic),
1105 			   tui_win_list[type]->generic.height);
1106 	else
1107 	  printf_filtered ("        %s\t(%d lines)\n",
1108 			   tui_win_name (&tui_win_list[type]->generic),
1109 			   tui_win_list[type]->generic.height);
1110       }
1111 }
1112 
1113 
1114 static void
1115 tui_refresh_all_command (char *arg, int from_tty)
1116 {
1117   /* Make sure the curses mode is enabled.  */
1118   tui_enable ();
1119 
1120   tui_refresh_all_win ();
1121 }
1122 
1123 
1124 /* Set the tab width of the specified window.  */
1125 static void
1126 tui_set_tab_width_command (char *arg, int from_tty)
1127 {
1128   /* Make sure the curses mode is enabled.  */
1129   tui_enable ();
1130   if (arg != (char *) NULL)
1131     {
1132       int ts;
1133 
1134       ts = atoi (arg);
1135       if (ts > 0)
1136 	{
1137 	  tui_set_default_tab_len (ts);
1138 	  /* We don't really change the height of any windows, but
1139 	     calling these 2 functions causes a complete regeneration
1140 	     and redisplay of the window's contents, which will take
1141 	     the new tab width into account.  */
1142 	  if (tui_win_list[SRC_WIN]
1143 	      && tui_win_list[SRC_WIN]->generic.is_visible)
1144 	    {
1145 	      make_invisible_and_set_new_height (TUI_SRC_WIN,
1146 						 TUI_SRC_WIN->generic.height);
1147 	      make_visible_with_new_height (TUI_SRC_WIN);
1148 	    }
1149 	  if (tui_win_list[DISASSEM_WIN]
1150 	      && tui_win_list[DISASSEM_WIN]->generic.is_visible)
1151 	    {
1152 	      make_invisible_and_set_new_height (TUI_DISASM_WIN,
1153 						 TUI_DISASM_WIN->generic.height);
1154 	      make_visible_with_new_height (TUI_DISASM_WIN);
1155 	    }
1156 	}
1157       else
1158 	warning (_("Tab widths greater than 0 must be specified."));
1159     }
1160 }
1161 
1162 
1163 /* Set the height of the specified window.  */
1164 static void
1165 tui_set_win_height (char *arg, int from_tty)
1166 {
1167   /* Make sure the curses mode is enabled.  */
1168   tui_enable ();
1169   if (arg != (char *) NULL)
1170     {
1171       char *buf = xstrdup (arg);
1172       char *buf_ptr = buf;
1173       char *wname = NULL;
1174       int new_height, i;
1175       struct tui_win_info *win_info;
1176       struct cleanup *old_chain;
1177 
1178       old_chain = make_cleanup (xfree, buf);
1179       wname = buf_ptr;
1180       buf_ptr = strchr (buf_ptr, ' ');
1181       if (buf_ptr != (char *) NULL)
1182 	{
1183 	  *buf_ptr = (char) 0;
1184 
1185 	  /* Validate the window name.  */
1186 	  for (i = 0; i < strlen (wname); i++)
1187 	    wname[i] = tolower (wname[i]);
1188 	  win_info = tui_partial_win_by_name (wname);
1189 
1190 	  if (win_info == (struct tui_win_info *) NULL
1191 	      || !win_info->generic.is_visible)
1192 	    warning (_("Invalid window specified. \n\
1193 The window name specified must be valid and visible.\n"));
1194 	  else
1195 	    {
1196 	      /* Process the size.  */
1197 	      while (*(++buf_ptr) == ' ')
1198 		;
1199 
1200 	      if (*buf_ptr != (char) 0)
1201 		{
1202 		  int negate = FALSE;
1203 		  int fixed_size = TRUE;
1204 		  int input_no;;
1205 
1206 		  if (*buf_ptr == '+' || *buf_ptr == '-')
1207 		    {
1208 		      if (*buf_ptr == '-')
1209 			negate = TRUE;
1210 		      fixed_size = FALSE;
1211 		      buf_ptr++;
1212 		    }
1213 		  input_no = atoi (buf_ptr);
1214 		  if (input_no > 0)
1215 		    {
1216 		      if (negate)
1217 			input_no *= (-1);
1218 		      if (fixed_size)
1219 			new_height = input_no;
1220 		      else
1221 			new_height = win_info->generic.height + input_no;
1222 
1223 		      /* Now change the window's height, and adjust
1224 		         all other windows around it.  */
1225 		      if (tui_adjust_win_heights (win_info,
1226 						new_height) == TUI_FAILURE)
1227 			warning (_("Invalid window height specified.\n%s"),
1228 				 WIN_HEIGHT_USAGE);
1229 		      else
1230                         tui_update_gdb_sizes ();
1231 		    }
1232 		  else
1233 		    warning (_("Invalid window height specified.\n%s"),
1234 			     WIN_HEIGHT_USAGE);
1235 		}
1236 	    }
1237 	}
1238       else
1239 	printf_filtered (WIN_HEIGHT_USAGE);
1240 
1241       do_cleanups (old_chain);
1242     }
1243   else
1244     printf_filtered (WIN_HEIGHT_USAGE);
1245 }
1246 
1247 /* Set the height of the specified window, with va_list.  */
1248 static void
1249 tui_set_win_height_command (char *arg, int from_tty)
1250 {
1251   /* Make sure the curses mode is enabled.  */
1252   tui_enable ();
1253   tui_set_win_height (arg, from_tty);
1254 }
1255 
1256 /* Function to adjust all window heights around the primary.   */
1257 static enum tui_status
1258 tui_adjust_win_heights (struct tui_win_info *primary_win_info,
1259 			int new_height)
1260 {
1261   enum tui_status status = TUI_FAILURE;
1262 
1263   if (new_height_ok (primary_win_info, new_height))
1264     {
1265       status = TUI_SUCCESS;
1266       if (new_height != primary_win_info->generic.height)
1267 	{
1268 	  int diff;
1269 	  struct tui_win_info *win_info;
1270 	  struct tui_gen_win_info *locator = tui_locator_win_info_ptr ();
1271 	  enum tui_layout_type cur_layout = tui_current_layout ();
1272 
1273 	  diff = (new_height - primary_win_info->generic.height) * (-1);
1274 	  if (cur_layout == SRC_COMMAND
1275 	      || cur_layout == DISASSEM_COMMAND)
1276 	    {
1277 	      struct tui_win_info *src_win_info;
1278 
1279 	      make_invisible_and_set_new_height (primary_win_info, new_height);
1280 	      if (primary_win_info->generic.type == CMD_WIN)
1281 		{
1282 		  win_info = (tui_source_windows ())->list[0];
1283 		  src_win_info = win_info;
1284 		}
1285 	      else
1286 		{
1287 		  win_info = tui_win_list[CMD_WIN];
1288 		  src_win_info = primary_win_info;
1289 		}
1290 	      make_invisible_and_set_new_height (win_info,
1291 					     win_info->generic.height + diff);
1292 	      TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1;
1293 	      make_visible_with_new_height (win_info);
1294 	      make_visible_with_new_height (primary_win_info);
1295 	      if (src_win_info->generic.content_size <= 0)
1296 		tui_erase_source_content (src_win_info, EMPTY_SOURCE_PROMPT);
1297 	    }
1298 	  else
1299 	    {
1300 	      struct tui_win_info *first_win;
1301 	      struct tui_win_info *second_win;
1302 
1303 	      if (cur_layout == SRC_DISASSEM_COMMAND)
1304 		{
1305 		  first_win = TUI_SRC_WIN;
1306 		  second_win = TUI_DISASM_WIN;
1307 		}
1308 	      else
1309 		{
1310 		  first_win = TUI_DATA_WIN;
1311 		  second_win = (tui_source_windows ())->list[0];
1312 		}
1313 	      if (primary_win_info == TUI_CMD_WIN)
1314 		{ /* Split the change in height accross the 1st & 2nd
1315 		     windows, adjusting them as well.  */
1316 		  /* Subtract the locator.  */
1317 		  int first_split_diff = diff / 2;
1318 		  int second_split_diff = first_split_diff;
1319 
1320 		  if (diff % 2)
1321 		    {
1322 		      if (first_win->generic.height >
1323 			  second_win->generic.height)
1324 			if (diff < 0)
1325 			  first_split_diff--;
1326 			else
1327 			  first_split_diff++;
1328 		      else
1329 			{
1330 			  if (diff < 0)
1331 			    second_split_diff--;
1332 			  else
1333 			    second_split_diff++;
1334 			}
1335 		    }
1336 		  /* Make sure that the minimum hieghts are
1337 		     honored.  */
1338 		  while ((first_win->generic.height + first_split_diff) < 3)
1339 		    {
1340 		      first_split_diff++;
1341 		      second_split_diff--;
1342 		    }
1343 		  while ((second_win->generic.height + second_split_diff) < 3)
1344 		    {
1345 		      second_split_diff++;
1346 		      first_split_diff--;
1347 		    }
1348 		  make_invisible_and_set_new_height (
1349 						  first_win,
1350 				 first_win->generic.height + first_split_diff);
1351 		  second_win->generic.origin.y = first_win->generic.height - 1;
1352 		  make_invisible_and_set_new_height (second_win,
1353 						     second_win->generic.height
1354 						     + second_split_diff);
1355 		  TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1;
1356 		  make_invisible_and_set_new_height (TUI_CMD_WIN, new_height);
1357 		}
1358 	      else
1359 		{
1360 		  if ((TUI_CMD_WIN->generic.height + diff) < 1)
1361 		    { /* If there is no way to increase the command
1362 			 window take real estate from the 1st or 2nd
1363 			 window.  */
1364 		      if ((TUI_CMD_WIN->generic.height + diff) < 1)
1365 			{
1366 			  int i;
1367 
1368 			  for (i = TUI_CMD_WIN->generic.height + diff;
1369 			       (i < 1); i++)
1370 			    if (primary_win_info == first_win)
1371 			      second_win->generic.height--;
1372 			    else
1373 			      first_win->generic.height--;
1374 			}
1375 		    }
1376 		  if (primary_win_info == first_win)
1377 		    make_invisible_and_set_new_height (first_win, new_height);
1378 		  else
1379 		    make_invisible_and_set_new_height (
1380 						    first_win,
1381 						  first_win->generic.height);
1382 		  second_win->generic.origin.y = first_win->generic.height - 1;
1383 		  if (primary_win_info == second_win)
1384 		    make_invisible_and_set_new_height (second_win, new_height);
1385 		  else
1386 		    make_invisible_and_set_new_height (
1387 				      second_win, second_win->generic.height);
1388 		  TUI_CMD_WIN->generic.origin.y = locator->origin.y + 1;
1389 		  if ((TUI_CMD_WIN->generic.height + diff) < 1)
1390 		    make_invisible_and_set_new_height (TUI_CMD_WIN, 1);
1391 		  else
1392 		    make_invisible_and_set_new_height (TUI_CMD_WIN,
1393 						       TUI_CMD_WIN->generic.height + diff);
1394 		}
1395 	      make_visible_with_new_height (TUI_CMD_WIN);
1396 	      make_visible_with_new_height (second_win);
1397 	      make_visible_with_new_height (first_win);
1398 	      if (first_win->generic.content_size <= 0)
1399 		tui_erase_source_content (first_win, EMPTY_SOURCE_PROMPT);
1400 	      if (second_win->generic.content_size <= 0)
1401 		tui_erase_source_content (second_win, EMPTY_SOURCE_PROMPT);
1402 	    }
1403 	}
1404     }
1405 
1406   return status;
1407 }
1408 
1409 
1410 /* Function make the target window (and auxillary windows associated
1411    with the targer) invisible, and set the new height and
1412    location.  */
1413 static void
1414 make_invisible_and_set_new_height (struct tui_win_info *win_info,
1415 				   int height)
1416 {
1417   int i;
1418   struct tui_gen_win_info *gen_win_info;
1419 
1420   tui_make_invisible (&win_info->generic);
1421   win_info->generic.height = height;
1422   if (height > 1)
1423     win_info->generic.viewport_height = height - 1;
1424   else
1425     win_info->generic.viewport_height = height;
1426   if (win_info != TUI_CMD_WIN)
1427     win_info->generic.viewport_height--;
1428 
1429   /* Now deal with the auxillary windows associated with win_info.  */
1430   switch (win_info->generic.type)
1431     {
1432     case SRC_WIN:
1433     case DISASSEM_WIN:
1434       gen_win_info = win_info->detail.source_info.execution_info;
1435       tui_make_invisible (gen_win_info);
1436       gen_win_info->height = height;
1437       gen_win_info->origin.y = win_info->generic.origin.y;
1438       if (height > 1)
1439 	gen_win_info->viewport_height = height - 1;
1440       else
1441 	gen_win_info->viewport_height = height;
1442       if (win_info != TUI_CMD_WIN)
1443 	gen_win_info->viewport_height--;
1444 
1445       if (tui_win_has_locator (win_info))
1446 	{
1447 	  gen_win_info = tui_locator_win_info_ptr ();
1448 	  tui_make_invisible (gen_win_info);
1449 	  gen_win_info->origin.y = win_info->generic.origin.y + height;
1450 	}
1451       break;
1452     case DATA_WIN:
1453       /* Delete all data item windows.  */
1454       for (i = 0; i < win_info->generic.content_size; i++)
1455 	{
1456 	  gen_win_info = (struct tui_gen_win_info *)
1457 	    &((struct tui_win_element *)
1458 	      win_info->generic.content[i])->which_element.data_window;
1459 	  tui_delete_win (gen_win_info->handle);
1460 	  gen_win_info->handle = NULL;
1461 	}
1462       break;
1463     default:
1464       break;
1465     }
1466 }
1467 
1468 
1469 /* Function to make the windows with new heights visible.  This means
1470    re-creating the windows' content since the window had to be
1471    destroyed to be made invisible.  */
1472 static void
1473 make_visible_with_new_height (struct tui_win_info *win_info)
1474 {
1475   struct symtab *s;
1476 
1477   tui_make_visible (&win_info->generic);
1478   tui_check_and_display_highlight_if_needed (win_info);
1479   switch (win_info->generic.type)
1480     {
1481     case SRC_WIN:
1482     case DISASSEM_WIN:
1483       tui_free_win_content (win_info->detail.source_info.execution_info);
1484       tui_make_visible (win_info->detail.source_info.execution_info);
1485       if (win_info->generic.content != NULL)
1486 	{
1487 	  struct gdbarch *gdbarch = win_info->detail.source_info.gdbarch;
1488 	  struct tui_line_or_address line_or_addr;
1489 	  struct symtab_and_line cursal
1490 	    = get_current_source_symtab_and_line ();
1491 
1492 	  line_or_addr = win_info->detail.source_info.start_line_or_addr;
1493 	  tui_free_win_content (&win_info->generic);
1494 	  tui_update_source_window (win_info, gdbarch,
1495 				    cursal.symtab, line_or_addr, TRUE);
1496 	}
1497       else if (deprecated_safe_get_selected_frame () != NULL)
1498 	{
1499 	  struct tui_line_or_address line;
1500 	  struct symtab_and_line cursal
1501 	    = get_current_source_symtab_and_line ();
1502 	  struct frame_info *frame = deprecated_safe_get_selected_frame ();
1503 	  struct gdbarch *gdbarch = get_frame_arch (frame);
1504 
1505 	  s = find_pc_line_symtab (get_frame_pc (frame));
1506 	  if (win_info->generic.type == SRC_WIN)
1507 	    {
1508 	      line.loa = LOA_LINE;
1509 	      line.u.line_no = cursal.line;
1510 	    }
1511 	  else
1512 	    {
1513 	      line.loa = LOA_ADDRESS;
1514 	      find_line_pc (s, cursal.line, &line.u.addr);
1515 	    }
1516 	  tui_update_source_window (win_info, gdbarch, s, line, TRUE);
1517 	}
1518       if (tui_win_has_locator (win_info))
1519 	{
1520 	  tui_make_visible (tui_locator_win_info_ptr ());
1521 	  tui_show_locator_content ();
1522 	}
1523       break;
1524     case DATA_WIN:
1525       tui_display_all_data ();
1526       break;
1527     case CMD_WIN:
1528 #ifdef HAVE_WRESIZE
1529       wresize (TUI_CMD_WIN->generic.handle,
1530 	       TUI_CMD_WIN->generic.height,
1531 	       TUI_CMD_WIN->generic.width);
1532 #endif
1533       mvwin (TUI_CMD_WIN->generic.handle,
1534 	     TUI_CMD_WIN->generic.origin.y,
1535 	     TUI_CMD_WIN->generic.origin.x);
1536       wmove (win_info->generic.handle, 0, 0);
1537       break;
1538     default:
1539       break;
1540     }
1541 }
1542 
1543 
1544 static int
1545 new_height_ok (struct tui_win_info *primary_win_info,
1546 	       int new_height)
1547 {
1548   int ok = (new_height < tui_term_height ());
1549 
1550   if (ok)
1551     {
1552       int diff;
1553       enum tui_layout_type cur_layout = tui_current_layout ();
1554 
1555       diff = (new_height - primary_win_info->generic.height) * (-1);
1556       if (cur_layout == SRC_COMMAND || cur_layout == DISASSEM_COMMAND)
1557 	{
1558 	  ok = ((primary_win_info->generic.type == CMD_WIN
1559 		 && new_height <= (tui_term_height () - 4)
1560 		 && new_height >= MIN_CMD_WIN_HEIGHT)
1561 		|| (primary_win_info->generic.type != CMD_WIN
1562 		    && new_height <= (tui_term_height () - 2)
1563 		    && new_height >= MIN_WIN_HEIGHT));
1564 	  if (ok)
1565 	    {			/* Check the total height.  */
1566 	      struct tui_win_info *win_info;
1567 
1568 	      if (primary_win_info == TUI_CMD_WIN)
1569 		win_info = (tui_source_windows ())->list[0];
1570 	      else
1571 		win_info = TUI_CMD_WIN;
1572 	      ok = ((new_height +
1573 		     (win_info->generic.height + diff)) <= tui_term_height ());
1574 	    }
1575 	}
1576       else
1577 	{
1578 	  int cur_total_height, total_height, min_height = 0;
1579 	  struct tui_win_info *first_win;
1580 	  struct tui_win_info *second_win;
1581 
1582 	  if (cur_layout == SRC_DISASSEM_COMMAND)
1583 	    {
1584 	      first_win = TUI_SRC_WIN;
1585 	      second_win = TUI_DISASM_WIN;
1586 	    }
1587 	  else
1588 	    {
1589 	      first_win = TUI_DATA_WIN;
1590 	      second_win = (tui_source_windows ())->list[0];
1591 	    }
1592 	  /* We could simply add all the heights to obtain the same
1593 	     result but below is more explicit since we subtract 1 for
1594 	     the line that the first and second windows share, and add
1595 	     one for the locator.  */
1596 	  total_height = cur_total_height =
1597 	    (first_win->generic.height + second_win->generic.height - 1)
1598 	    + TUI_CMD_WIN->generic.height + 1;	/* Locator. */
1599 	  if (primary_win_info == TUI_CMD_WIN)
1600 	    {
1601 	      /* Locator included since first & second win share a line.  */
1602 	      ok = ((first_win->generic.height +
1603 		     second_win->generic.height + diff) >=
1604 		    (MIN_WIN_HEIGHT * 2)
1605 		    && new_height >= MIN_CMD_WIN_HEIGHT);
1606 	      if (ok)
1607 		{
1608 		  total_height = new_height +
1609 		    (first_win->generic.height +
1610 		     second_win->generic.height + diff);
1611 		  min_height = MIN_CMD_WIN_HEIGHT;
1612 		}
1613 	    }
1614 	  else
1615 	    {
1616 	      min_height = MIN_WIN_HEIGHT;
1617 
1618 	      /* First see if we can increase/decrease the command
1619 	         window.  And make sure that the command window is at
1620 	         least 1 line.  */
1621 	      ok = ((TUI_CMD_WIN->generic.height + diff) > 0);
1622 	      if (!ok)
1623 		{ /* Looks like we have to increase/decrease one of
1624 		     the other windows.  */
1625 		  if (primary_win_info == first_win)
1626 		    ok = (second_win->generic.height + diff) >= min_height;
1627 		  else
1628 		    ok = (first_win->generic.height + diff) >= min_height;
1629 		}
1630 	      if (ok)
1631 		{
1632 		  if (primary_win_info == first_win)
1633 		    total_height = new_height +
1634 		      second_win->generic.height +
1635 		      TUI_CMD_WIN->generic.height + diff;
1636 		  else
1637 		    total_height = new_height +
1638 		      first_win->generic.height +
1639 		      TUI_CMD_WIN->generic.height + diff;
1640 		}
1641 	    }
1642 	  /* Now make sure that the proposed total height doesn't
1643 	     exceed the old total height.  */
1644 	  if (ok)
1645 	    ok = (new_height >= min_height
1646 		  && total_height <= cur_total_height);
1647 	}
1648     }
1649 
1650   return ok;
1651 }
1652 
1653 
1654 static void
1655 parse_scrolling_args (char *arg,
1656 		      struct tui_win_info **win_to_scroll,
1657 		      int *num_to_scroll)
1658 {
1659   if (num_to_scroll)
1660     *num_to_scroll = 0;
1661   *win_to_scroll = tui_win_with_focus ();
1662 
1663   /* First set up the default window to scroll, in case there is no
1664      window name arg.  */
1665   if (arg != (char *) NULL)
1666     {
1667       char *buf, *buf_ptr;
1668       struct cleanup *old_chain;
1669 
1670       /* Process the number of lines to scroll.  */
1671       buf = buf_ptr = xstrdup (arg);
1672       old_chain = make_cleanup (xfree, buf);
1673       if (isdigit (*buf_ptr))
1674 	{
1675 	  char *num_str;
1676 
1677 	  num_str = buf_ptr;
1678 	  buf_ptr = strchr (buf_ptr, ' ');
1679 	  if (buf_ptr != (char *) NULL)
1680 	    {
1681 	      *buf_ptr = (char) 0;
1682 	      if (num_to_scroll)
1683 		*num_to_scroll = atoi (num_str);
1684 	      buf_ptr++;
1685 	    }
1686 	  else if (num_to_scroll)
1687 	    *num_to_scroll = atoi (num_str);
1688 	}
1689 
1690       /* Process the window name if one is specified.  */
1691       if (buf_ptr != (char *) NULL)
1692 	{
1693 	  char *wname;
1694 	  int i;
1695 
1696 	  if (*buf_ptr == ' ')
1697 	    while (*(++buf_ptr) == ' ')
1698 	      ;
1699 
1700 	  if (*buf_ptr != (char) 0)
1701 	    {
1702 	      wname = buf_ptr;
1703 
1704 	      /* Validate the window name.  */
1705 	      for (i = 0; i < strlen (wname); i++)
1706 		wname[i] = tolower (wname[i]);
1707 	    }
1708 	  else
1709 	    wname = "?";
1710 
1711 	  *win_to_scroll = tui_partial_win_by_name (wname);
1712 
1713 	  if (*win_to_scroll == (struct tui_win_info *) NULL
1714 	      || !(*win_to_scroll)->generic.is_visible)
1715 	    error (_("Invalid window specified. \n\
1716 The window name specified must be valid and visible.\n"));
1717 	  else if (*win_to_scroll == TUI_CMD_WIN)
1718 	    *win_to_scroll = (tui_source_windows ())->list[0];
1719 	}
1720       do_cleanups (old_chain);
1721     }
1722 }
1723