]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/tui/tui-regs.c
2b093587d7e36d2d446f11840905d4551d5ca825
[thirdparty/binutils-gdb.git] / gdb / tui / tui-regs.c
1 /* TUI display registers in window.
2
3 Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2007, 2008, 2009,
4 2010, 2011 Free Software Foundation, Inc.
5
6 Contributed by Hewlett-Packard Company.
7
8 This file is part of GDB.
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22
23 #include "defs.h"
24 #include "arch-utils.h"
25 #include "tui/tui.h"
26 #include "tui/tui-data.h"
27 #include "symtab.h"
28 #include "gdbtypes.h"
29 #include "gdbcmd.h"
30 #include "frame.h"
31 #include "regcache.h"
32 #include "inferior.h"
33 #include "target.h"
34 #include "gdb_string.h"
35 #include "tui/tui-layout.h"
36 #include "tui/tui-win.h"
37 #include "tui/tui-windata.h"
38 #include "tui/tui-wingeneral.h"
39 #include "tui/tui-file.h"
40 #include "tui/tui-regs.h"
41 #include "reggroups.h"
42 #include "valprint.h"
43
44 #include "gdb_curses.h"
45
46
47 /*****************************************
48 ** STATIC LOCAL FUNCTIONS FORWARD DECLS **
49 ******************************************/
50 static void
51 tui_display_register (struct tui_data_element *data,
52 struct tui_gen_win_info *win_info);
53
54 static enum tui_status tui_show_register_group (struct reggroup *group,
55 struct frame_info *frame,
56 int refresh_values_only);
57
58 static enum tui_status tui_get_register (struct frame_info *frame,
59 struct tui_data_element *data,
60 int regnum, int *changedp);
61
62 static void tui_register_format (struct frame_info *,
63 struct tui_data_element*, int);
64
65 static void tui_scroll_regs_forward_command (char *, int);
66 static void tui_scroll_regs_backward_command (char *, int);
67
68
69
70 /*****************************************
71 ** PUBLIC FUNCTIONS **
72 ******************************************/
73
74 /* Answer the number of the last line in the regs display. If there
75 are no registers (-1) is returned. */
76 int
77 tui_last_regs_line_no (void)
78 {
79 int num_lines = (-1);
80
81 if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
82 {
83 num_lines = (TUI_DATA_WIN->detail.data_display_info.regs_content_count /
84 TUI_DATA_WIN->detail.data_display_info.regs_column_count);
85 if (TUI_DATA_WIN->detail.data_display_info.regs_content_count %
86 TUI_DATA_WIN->detail.data_display_info.regs_column_count)
87 num_lines++;
88 }
89 return num_lines;
90 }
91
92
93 /* Answer the line number that the register element at element_no is
94 on. If element_no is greater than the number of register elements
95 there are, -1 is returned. */
96 int
97 tui_line_from_reg_element_no (int element_no)
98 {
99 if (element_no < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
100 {
101 int i, line = (-1);
102
103 i = 1;
104 while (line == (-1))
105 {
106 if (element_no <
107 (TUI_DATA_WIN->detail.data_display_info.regs_column_count * i))
108 line = i - 1;
109 else
110 i++;
111 }
112
113 return line;
114 }
115 else
116 return (-1);
117 }
118
119
120 /* Answer the index of the first element in line_no. If line_no is
121 past the register area (-1) is returned. */
122 int
123 tui_first_reg_element_no_inline (int line_no)
124 {
125 if ((line_no * TUI_DATA_WIN->detail.data_display_info.regs_column_count)
126 <= TUI_DATA_WIN->detail.data_display_info.regs_content_count)
127 return ((line_no + 1) *
128 TUI_DATA_WIN->detail.data_display_info.regs_column_count) -
129 TUI_DATA_WIN->detail.data_display_info.regs_column_count;
130 else
131 return (-1);
132 }
133
134
135 /* Answer the index of the last element in line_no. If line_no is
136 past the register area (-1) is returned. */
137 int
138 tui_last_reg_element_no_in_line (int line_no)
139 {
140 if ((line_no * TUI_DATA_WIN->detail.data_display_info.regs_column_count) <=
141 TUI_DATA_WIN->detail.data_display_info.regs_content_count)
142 return ((line_no + 1) *
143 TUI_DATA_WIN->detail.data_display_info.regs_column_count) - 1;
144 else
145 return (-1);
146 }
147
148 /* Show the registers of the given group in the data window
149 and refresh the window. */
150 void
151 tui_show_registers (struct reggroup *group)
152 {
153 enum tui_status ret = TUI_FAILURE;
154 struct tui_data_info *display_info;
155
156 /* Make sure the curses mode is enabled. */
157 tui_enable ();
158
159 /* Make sure the register window is visible. If not, select an
160 appropriate layout. */
161 if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->generic.is_visible)
162 tui_set_layout_for_display_command (DATA_NAME);
163
164 display_info = &TUI_DATA_WIN->detail.data_display_info;
165 if (group == 0)
166 group = general_reggroup;
167
168 /* Say that registers should be displayed, even if there is a
169 problem. */
170 display_info->display_regs = TRUE;
171
172 if (target_has_registers && target_has_stack && target_has_memory)
173 {
174 ret = tui_show_register_group (group, get_current_frame (),
175 group == display_info->current_group);
176 }
177 if (ret == TUI_FAILURE)
178 {
179 display_info->current_group = 0;
180 tui_erase_data_content (NO_REGS_STRING);
181 }
182 else
183 {
184 int i;
185
186 /* Clear all notation of changed values. */
187 for (i = 0; i < display_info->regs_content_count; i++)
188 {
189 struct tui_gen_win_info *data_item_win;
190 struct tui_win_element *win;
191
192 data_item_win = &display_info->regs_content[i]
193 ->which_element.data_window;
194 win = (struct tui_win_element *) data_item_win->content[0];
195 win->which_element.data.highlight = FALSE;
196 }
197 display_info->current_group = group;
198 tui_display_all_data ();
199 }
200 }
201
202
203 /* Set the data window to display the registers of the register group
204 using the given frame. Values are refreshed only when
205 refresh_values_only is TRUE. */
206
207 static enum tui_status
208 tui_show_register_group (struct reggroup *group,
209 struct frame_info *frame,
210 int refresh_values_only)
211 {
212 struct gdbarch *gdbarch = get_frame_arch (frame);
213 enum tui_status ret = TUI_FAILURE;
214 int nr_regs;
215 int allocated_here = FALSE;
216 int regnum, pos;
217 char title[80];
218 struct tui_data_info *display_info = &TUI_DATA_WIN->detail.data_display_info;
219
220 /* Make a new title showing which group we display. */
221 snprintf (title, sizeof (title) - 1, "Register group: %s",
222 reggroup_name (group));
223 xfree (TUI_DATA_WIN->generic.title);
224 TUI_DATA_WIN->generic.title = xstrdup (title);
225
226 /* See how many registers must be displayed. */
227 nr_regs = 0;
228 for (regnum = 0;
229 regnum < gdbarch_num_regs (gdbarch)
230 + gdbarch_num_pseudo_regs (gdbarch);
231 regnum++)
232 {
233 const char *name;
234
235 /* Must be in the group. */
236 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
237 continue;
238
239 /* If the register name is empty, it is undefined for this
240 processor, so don't display anything. */
241 name = gdbarch_register_name (gdbarch, regnum);
242 if (name == 0 || *name == '\0')
243 continue;
244
245 nr_regs++;
246 }
247
248 if (display_info->regs_content_count > 0 && !refresh_values_only)
249 {
250 tui_free_data_content (display_info->regs_content,
251 display_info->regs_content_count);
252 display_info->regs_content_count = 0;
253 }
254
255 if (display_info->regs_content_count <= 0)
256 {
257 display_info->regs_content = tui_alloc_content (nr_regs, DATA_WIN);
258 allocated_here = TRUE;
259 refresh_values_only = FALSE;
260 }
261
262 if (display_info->regs_content != (tui_win_content) NULL)
263 {
264 if (!refresh_values_only || allocated_here)
265 {
266 TUI_DATA_WIN->generic.content = (void*) NULL;
267 TUI_DATA_WIN->generic.content_size = 0;
268 tui_add_content_elements (&TUI_DATA_WIN->generic, nr_regs);
269 display_info->regs_content
270 = (tui_win_content) TUI_DATA_WIN->generic.content;
271 display_info->regs_content_count = nr_regs;
272 }
273
274 /* Now set the register names and values. */
275 pos = 0;
276 for (regnum = 0;
277 regnum < gdbarch_num_regs (gdbarch)
278 + gdbarch_num_pseudo_regs (gdbarch);
279 regnum++)
280 {
281 struct tui_gen_win_info *data_item_win;
282 struct tui_data_element *data;
283 const char *name;
284
285 /* Must be in the group. */
286 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
287 continue;
288
289 /* If the register name is empty, it is undefined for this
290 processor, so don't display anything. */
291 name = gdbarch_register_name (gdbarch, regnum);
292 if (name == 0 || *name == '\0')
293 continue;
294
295 data_item_win =
296 &display_info->regs_content[pos]->which_element.data_window;
297 data = &((struct tui_win_element *)
298 data_item_win->content[0])->which_element.data;
299 if (data)
300 {
301 if (!refresh_values_only)
302 {
303 data->item_no = regnum;
304 data->name = name;
305 data->highlight = FALSE;
306 }
307 tui_get_register (frame, data, regnum, 0);
308 }
309 pos++;
310 }
311
312 TUI_DATA_WIN->generic.content_size =
313 display_info->regs_content_count + display_info->data_content_count;
314 ret = TUI_SUCCESS;
315 }
316
317 return ret;
318 }
319
320 /* Function to display the registers in the content from
321 'start_element_no' until the end of the register content or the end
322 of the display height. No checking for displaying past the end of
323 the registers is done here. */
324 void
325 tui_display_registers_from (int start_element_no)
326 {
327 struct tui_data_info *display_info = &TUI_DATA_WIN->detail.data_display_info;
328
329 if (display_info->regs_content != (tui_win_content) NULL
330 && display_info->regs_content_count > 0)
331 {
332 int i = start_element_no;
333 int j, item_win_width, cur_y;
334
335 int max_len = 0;
336 for (i = 0; i < display_info->regs_content_count; i++)
337 {
338 struct tui_data_element *data;
339 struct tui_gen_win_info *data_item_win;
340 char *p;
341 int len;
342
343 data_item_win
344 = &display_info->regs_content[i]->which_element.data_window;
345 data = &((struct tui_win_element *)
346 data_item_win->content[0])->which_element.data;
347 len = 0;
348 p = data->content;
349 if (p != 0)
350 while (*p)
351 {
352 if (*p++ == '\t')
353 len = 8 * ((len / 8) + 1);
354 else
355 len++;
356 }
357
358 if (len > max_len)
359 max_len = len;
360 }
361 item_win_width = max_len + 1;
362 i = start_element_no;
363
364 display_info->regs_column_count =
365 (TUI_DATA_WIN->generic.width - 2) / item_win_width;
366 if (display_info->regs_column_count == 0)
367 display_info->regs_column_count = 1;
368 item_win_width =
369 (TUI_DATA_WIN->generic.width - 2) / display_info->regs_column_count;
370
371 /* Now create each data "sub" window, and write the display into
372 it. */
373 cur_y = 1;
374 while (i < display_info->regs_content_count
375 && cur_y <= TUI_DATA_WIN->generic.viewport_height)
376 {
377 for (j = 0;
378 j < display_info->regs_column_count
379 && i < display_info->regs_content_count;
380 j++)
381 {
382 struct tui_gen_win_info *data_item_win;
383 struct tui_data_element *data_element_ptr;
384
385 /* Create the window if necessary. */
386 data_item_win = &display_info->regs_content[i]
387 ->which_element.data_window;
388 data_element_ptr = &((struct tui_win_element *)
389 data_item_win->content[0])->which_element.data;
390 if (data_item_win->handle != (WINDOW*) NULL
391 && (data_item_win->height != 1
392 || data_item_win->width != item_win_width
393 || data_item_win->origin.x != (item_win_width * j) + 1
394 || data_item_win->origin.y != cur_y))
395 {
396 tui_delete_win (data_item_win->handle);
397 data_item_win->handle = 0;
398 }
399
400 if (data_item_win->handle == (WINDOW *) NULL)
401 {
402 data_item_win->height = 1;
403 data_item_win->width = item_win_width;
404 data_item_win->origin.x = (item_win_width * j) + 1;
405 data_item_win->origin.y = cur_y;
406 tui_make_window (data_item_win, DONT_BOX_WINDOW);
407 scrollok (data_item_win->handle, FALSE);
408 }
409 touchwin (data_item_win->handle);
410
411 /* Get the printable representation of the register
412 and display it. */
413 tui_display_register (data_element_ptr, data_item_win);
414 i++; /* Next register. */
415 }
416 cur_y++; /* Next row. */
417 }
418 }
419 }
420
421
422 /* Function to display the registers in the content from
423 'start_element_no' on 'start_line_no' until the end of the register
424 content or the end of the display height. This function checks
425 that we won't display off the end of the register display. */
426 static void
427 tui_display_reg_element_at_line (int start_element_no,
428 int start_line_no)
429 {
430 if (TUI_DATA_WIN->detail.data_display_info.regs_content
431 != (tui_win_content) NULL
432 && TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
433 {
434 int element_no = start_element_no;
435
436 if (start_element_no != 0 && start_line_no != 0)
437 {
438 int last_line_no, first_line_on_last_page;
439
440 last_line_no = tui_last_regs_line_no ();
441 first_line_on_last_page
442 = last_line_no - (TUI_DATA_WIN->generic.height - 2);
443 if (first_line_on_last_page < 0)
444 first_line_on_last_page = 0;
445
446 /* If there is no other data displayed except registers, and
447 the element_no causes us to scroll past the end of the
448 registers, adjust what element to really start the
449 display at. */
450 if (TUI_DATA_WIN->detail.data_display_info.data_content_count <= 0
451 && start_line_no > first_line_on_last_page)
452 element_no
453 = tui_first_reg_element_no_inline (first_line_on_last_page);
454 }
455 tui_display_registers_from (element_no);
456 }
457 }
458
459
460
461 /* Function to display the registers starting at line line_no in the
462 data window. Answers the line number that the display actually
463 started from. If nothing is displayed (-1) is returned. */
464 int
465 tui_display_registers_from_line (int line_no,
466 int force_display)
467 {
468 if (TUI_DATA_WIN->detail.data_display_info.regs_content_count > 0)
469 {
470 int line, element_no;
471
472 if (line_no < 0)
473 line = 0;
474 else if (force_display)
475 { /* If we must display regs (force_display is true), then
476 make sure that we don't display off the end of the
477 registers. */
478 if (line_no >= tui_last_regs_line_no ())
479 {
480 if ((line = tui_line_from_reg_element_no (
481 TUI_DATA_WIN->detail.data_display_info.regs_content_count - 1)) < 0)
482 line = 0;
483 }
484 else
485 line = line_no;
486 }
487 else
488 line = line_no;
489
490 element_no = tui_first_reg_element_no_inline (line);
491 if (element_no
492 < TUI_DATA_WIN->detail.data_display_info.regs_content_count)
493 tui_display_reg_element_at_line (element_no, line);
494 else
495 line = (-1);
496
497 return line;
498 }
499
500 return (-1); /* Nothing was displayed. */
501 }
502
503
504 /* This function check all displayed registers for changes in values,
505 given a particular frame. If the values have changed, they are
506 updated with the new value and highlighted. */
507 void
508 tui_check_register_values (struct frame_info *frame)
509 {
510 if (TUI_DATA_WIN != NULL
511 && TUI_DATA_WIN->generic.is_visible)
512 {
513 struct tui_data_info *display_info
514 = &TUI_DATA_WIN->detail.data_display_info;
515
516 if (display_info->regs_content_count <= 0
517 && display_info->display_regs)
518 tui_show_registers (display_info->current_group);
519 else
520 {
521 int i;
522
523 for (i = 0; (i < display_info->regs_content_count); i++)
524 {
525 struct tui_data_element *data;
526 struct tui_gen_win_info *data_item_win_ptr;
527 int was_hilighted;
528
529 data_item_win_ptr = &display_info->regs_content[i]->
530 which_element.data_window;
531 data = &((struct tui_win_element *)
532 data_item_win_ptr->content[0])->which_element.data;
533 was_hilighted = data->highlight;
534
535 tui_get_register (frame, data,
536 data->item_no, &data->highlight);
537
538 if (data->highlight || was_hilighted)
539 {
540 tui_display_register (data, data_item_win_ptr);
541 }
542 }
543 }
544 }
545 }
546
547 /* Display a register in a window. If hilite is TRUE, then the value
548 will be displayed in reverse video. */
549 static void
550 tui_display_register (struct tui_data_element *data,
551 struct tui_gen_win_info *win_info)
552 {
553 if (win_info->handle != (WINDOW *) NULL)
554 {
555 int i;
556
557 if (data->highlight)
558 /* We ignore the return value, casting it to void in order to avoid
559 a compiler warning. The warning itself was introduced by a patch
560 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
561 to code that causes the compiler to generate an unused-value
562 warning. */
563 (void) wstandout (win_info->handle);
564
565 wmove (win_info->handle, 0, 0);
566 for (i = 1; i < win_info->width; i++)
567 waddch (win_info->handle, ' ');
568 wmove (win_info->handle, 0, 0);
569 if (data->content)
570 waddstr (win_info->handle, data->content);
571
572 if (data->highlight)
573 /* We ignore the return value, casting it to void in order to avoid
574 a compiler warning. The warning itself was introduced by a patch
575 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
576 to code that causes the compiler to generate an unused-value
577 warning. */
578 (void) wstandend (win_info->handle);
579 tui_refresh_win (win_info);
580 }
581 }
582
583 static void
584 tui_reg_next_command (char *arg, int from_tty)
585 {
586 struct gdbarch *gdbarch = get_current_arch ();
587
588 if (TUI_DATA_WIN != 0)
589 {
590 struct reggroup *group
591 = TUI_DATA_WIN->detail.data_display_info.current_group;
592
593 group = reggroup_next (gdbarch, group);
594 if (group == 0)
595 group = reggroup_next (gdbarch, 0);
596
597 if (group)
598 tui_show_registers (group);
599 }
600 }
601
602 static void
603 tui_reg_float_command (char *arg, int from_tty)
604 {
605 tui_show_registers (float_reggroup);
606 }
607
608 static void
609 tui_reg_general_command (char *arg, int from_tty)
610 {
611 tui_show_registers (general_reggroup);
612 }
613
614 static void
615 tui_reg_system_command (char *arg, int from_tty)
616 {
617 tui_show_registers (system_reggroup);
618 }
619
620 static struct cmd_list_element *tuireglist;
621
622 static void
623 tui_reg_command (char *args, int from_tty)
624 {
625 printf_unfiltered (_("\"tui reg\" must be followed by the name of a "
626 "tui reg command.\n"));
627 help_list (tuireglist, "tui reg ", -1, gdb_stdout);
628 }
629
630 /* Provide a prototype to silence -Wmissing-prototypes. */
631 extern initialize_file_ftype _initialize_tui_regs;
632
633 void
634 _initialize_tui_regs (void)
635 {
636 struct cmd_list_element **tuicmd;
637
638 tuicmd = tui_get_cmd_list ();
639
640 add_prefix_cmd ("reg", class_tui, tui_reg_command,
641 _("TUI commands to control the register window."),
642 &tuireglist, "tui reg ", 0,
643 tuicmd);
644
645 add_cmd ("float", class_tui, tui_reg_float_command,
646 _("Display only floating point registers."),
647 &tuireglist);
648 add_cmd ("general", class_tui, tui_reg_general_command,
649 _("Display only general registers."),
650 &tuireglist);
651 add_cmd ("system", class_tui, tui_reg_system_command,
652 _("Display only system registers."),
653 &tuireglist);
654 add_cmd ("next", class_tui, tui_reg_next_command,
655 _("Display next register group."),
656 &tuireglist);
657
658 if (xdb_commands)
659 {
660 add_com ("fr", class_tui, tui_reg_float_command,
661 _("Display only floating point registers\n"));
662 add_com ("gr", class_tui, tui_reg_general_command,
663 _("Display only general registers\n"));
664 add_com ("sr", class_tui, tui_reg_system_command,
665 _("Display only special registers\n"));
666 add_com ("+r", class_tui, tui_scroll_regs_forward_command,
667 _("Scroll the registers window forward\n"));
668 add_com ("-r", class_tui, tui_scroll_regs_backward_command,
669 _("Scroll the register window backward\n"));
670 }
671 }
672
673
674 /*****************************************
675 ** STATIC LOCAL FUNCTIONS **
676 ******************************************/
677
678 extern int pagination_enabled;
679
680 static void
681 tui_restore_gdbout (void *ui)
682 {
683 ui_file_delete (gdb_stdout);
684 gdb_stdout = (struct ui_file*) ui;
685 pagination_enabled = 1;
686 }
687
688 /* Get the register from the frame and make a printable representation
689 of it in the data element. */
690 static void
691 tui_register_format (struct frame_info *frame,
692 struct tui_data_element *data_element,
693 int regnum)
694 {
695 struct gdbarch *gdbarch = get_frame_arch (frame);
696 struct ui_file *stream;
697 struct ui_file *old_stdout;
698 const char *name;
699 struct cleanup *cleanups;
700 char *p, *s;
701
702 name = gdbarch_register_name (gdbarch, regnum);
703 if (name == 0 || *name == '\0')
704 return;
705
706 pagination_enabled = 0;
707 old_stdout = gdb_stdout;
708 stream = tui_sfileopen (256);
709 gdb_stdout = stream;
710 cleanups = make_cleanup (tui_restore_gdbout, (void*) old_stdout);
711 gdbarch_print_registers_info (gdbarch, stream, frame, regnum, 1);
712
713 /* Save formatted output in the buffer. */
714 p = tui_file_get_strbuf (stream);
715
716 /* Remove the possible \n. */
717 s = strrchr (p, '\n');
718 if (s && s[1] == 0)
719 *s = 0;
720
721 xfree (data_element->content);
722 data_element->content = xstrdup (p);
723 do_cleanups (cleanups);
724 }
725
726 /* Get the register value from the given frame and format it for the
727 display. When changep is set, check if the new register value has
728 changed with respect to the previous call. */
729 static enum tui_status
730 tui_get_register (struct frame_info *frame,
731 struct tui_data_element *data,
732 int regnum, int *changedp)
733 {
734 enum tui_status ret = TUI_FAILURE;
735
736 if (changedp)
737 *changedp = FALSE;
738 if (target_has_registers)
739 {
740 struct value *old_val = data->value;
741
742 data->value = get_frame_register_value (frame, regnum);
743 release_value (data->value);
744 if (changedp)
745 {
746 struct gdbarch *gdbarch = get_frame_arch (frame);
747 int size = register_size (gdbarch, regnum);
748
749 if (value_optimized_out (data->value) != value_optimized_out (old_val)
750 || !value_available_contents_eq (data->value, 0,
751 old_val, 0, size))
752 *changedp = TRUE;
753 }
754
755 value_free (old_val);
756
757 /* Reformat the data content if the value changed. */
758 if (changedp == 0 || *changedp == TRUE)
759 tui_register_format (frame, data, regnum);
760
761 ret = TUI_SUCCESS;
762 }
763 return ret;
764 }
765
766 static void
767 tui_scroll_regs_forward_command (char *arg, int from_tty)
768 {
769 tui_scroll (FORWARD_SCROLL, TUI_DATA_WIN, 1);
770 }
771
772
773 static void
774 tui_scroll_regs_backward_command (char *arg, int from_tty)
775 {
776 tui_scroll (BACKWARD_SCROLL, TUI_DATA_WIN, 1);
777 }