/* TUI window generic functions. Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. Contributed by Hewlett-Packard Company. This file is part of GDB. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This module contains procedures for handling tui window functions like resize, scrolling, scrolling, changing focus, etc. Author: Susan B. Macchia */ /* FIXME: cagney/2002-02-28: The GDB coding standard indicates that "defs.h" should be included first. Unfortunatly some systems (currently Debian GNU/Linux) include the via and they clash with "bfd.h"'s definiton of true/false. The correct fix is to remove true/false from "bfd.h", however, until that happens, hack around it by including "config.h" and first. */ #include "config.h" #ifdef HAVE_NCURSES_H #include #else #ifdef HAVE_CURSES_H #include #endif #endif #include #include #include #include "defs.h" #include "command.h" #include "symtab.h" #include "breakpoint.h" #include "frame.h" #include "cli/cli-cmds.h" #include "top.h" #include "source.h" #include "tui.h" #include "tuiData.h" #include "tuiGeneralWin.h" #include "tuiStack.h" #include "tuiRegs.h" #include "tuiDisassem.h" #include "tuiSource.h" #include "tuiSourceWin.h" #include "tuiDataWin.h" /******************************* ** Static Local Decls ********************************/ static void _makeVisibleWithNewHeight (TuiWinInfoPtr); static void _makeInvisibleAndSetNewHeight (TuiWinInfoPtr, int); static TuiStatus _tuiAdjustWinHeights (TuiWinInfoPtr, int); static int _newHeightOk (TuiWinInfoPtr, int); static void _tuiSetTabWidth_command (char *, int); static void _tuiRefreshAll_command (char *, int); static void _tuiSetWinHeight_command (char *, int); static void _tuiXDBsetWinHeight_command (char *, int); static void _tuiAllWindowsInfo (char *, int); static void _tuiSetFocus_command (char *, int); static void _tuiScrollForward_command (char *, int); static void _tuiScrollBackward_command (char *, int); static void _tuiScrollLeft_command (char *, int); static void _tuiScrollRight_command (char *, int); static void _parseScrollingArgs (char *, TuiWinInfoPtr *, int *); /*************************************** ** DEFINITIONS ***************************************/ #define WIN_HEIGHT_USAGE "Usage: winheight [+ | -] <#lines>\n" #define XDBWIN_HEIGHT_USAGE "Usage: w <#lines>\n" #define FOCUS_USAGE "Usage: focus { | next | prev}\n" /*************************************** ** PUBLIC FUNCTIONS ***************************************/ #ifndef ACS_LRCORNER # define ACS_LRCORNER '+' #endif #ifndef ACS_LLCORNER # define ACS_LLCORNER '+' #endif #ifndef ACS_ULCORNER # define ACS_ULCORNER '+' #endif #ifndef ACS_URCORNER # define ACS_URCORNER '+' #endif #ifndef ACS_HLINE # define ACS_HLINE '-' #endif #ifndef ACS_VLINE # define ACS_VLINE '|' #endif /* Possible values for tui-border-kind variable. */ static const char *tui_border_kind_enums[] = { "space", "ascii", "acs", NULL }; /* Possible values for tui-border-mode and tui-active-border-mode. */ static const char *tui_border_mode_enums[] = { "normal", "standout", "reverse", "half", "half-standout", "bold", "bold-standout", NULL }; struct tui_translate { const char *name; int value; }; /* Translation table for border-mode variables. The list of values must be terminated by a NULL. After the NULL value, an entry defines the default. */ struct tui_translate tui_border_mode_translate[] = { { "normal", A_NORMAL }, { "standout", A_STANDOUT }, { "reverse", A_REVERSE }, { "half", A_DIM }, { "half-standout", A_DIM | A_STANDOUT }, { "bold", A_BOLD }, { "bold-standout", A_BOLD | A_STANDOUT }, { 0, 0 }, { "normal", A_NORMAL } }; /* Translation tables for border-kind, one for each border character (see wborder, border curses operations). -1 is used to indicate the ACS because ACS characters are determined at run time by curses (depends on terminal). */ struct tui_translate tui_border_kind_translate_vline[] = { { "space", ' ' }, { "ascii", '|' }, { "acs", -1 }, { 0, 0 }, { "ascii", '|' } }; struct tui_translate tui_border_kind_translate_hline[] = { { "space", ' ' }, { "ascii", '-' }, { "acs", -1 }, { 0, 0 }, { "ascii", '-' } }; struct tui_translate tui_border_kind_translate_ulcorner[] = { { "space", ' ' }, { "ascii", '+' }, { "acs", -1 }, { 0, 0 }, { "ascii", '+' } }; struct tui_translate tui_border_kind_translate_urcorner[] = { { "space", ' ' }, { "ascii", '+' }, { "acs", -1 }, { 0, 0 }, { "ascii", '+' } }; struct tui_translate tui_border_kind_translate_llcorner[] = { { "space", ' ' }, { "ascii", '+' }, { "acs", -1 }, { 0, 0 }, { "ascii", '+' } }; struct tui_translate tui_border_kind_translate_lrcorner[] = { { "space", ' ' }, { "ascii", '+' }, { "acs", -1 }, { 0, 0 }, { "ascii", '+' } }; /* Tui configuration variables controlled with set/show command. */ const char *tui_active_border_mode = "bold-standout"; const char *tui_border_mode = "normal"; const char *tui_border_kind = "acs"; /* Tui internal configuration variables. These variables are updated by tui_update_variables to reflect the tui configuration variables. */ chtype tui_border_vline; chtype tui_border_hline; chtype tui_border_ulcorner; chtype tui_border_urcorner; chtype tui_border_llcorner; chtype tui_border_lrcorner; int tui_border_attrs; int tui_active_border_attrs; /* Identify the item in the translation table. When the item is not recognized, use the default entry. */ static struct tui_translate * translate (const char *name, struct tui_translate *table) { while (table->name) { if (name && strcmp (table->name, name) == 0) return table; table++; } /* Not found, return default entry. */ table++; return table; } /* Update the tui internal configuration according to gdb settings. Returns 1 if the configuration has changed and the screen should be redrawn. */ int tui_update_variables () { int need_redraw = 0; struct tui_translate *entry; entry = translate (tui_border_mode, tui_border_mode_translate); if (tui_border_attrs != entry->value) { tui_border_attrs = entry->value; need_redraw = 1; } entry = translate (tui_active_border_mode, tui_border_mode_translate); if (tui_active_border_attrs != entry->value) { tui_active_border_attrs = entry->value; need_redraw = 1; } /* If one corner changes, all characters are changed. Only check the first one. The ACS characters are determined at run time by curses terminal management. */ entry = translate (tui_border_kind, tui_border_kind_translate_lrcorner); if (tui_border_lrcorner != (chtype) entry->value) { tui_border_lrcorner = (entry->value < 0) ? ACS_LRCORNER : entry->value; need_redraw = 1; } entry = translate (tui_border_kind, tui_border_kind_translate_llcorner); tui_border_llcorner = (entry->value < 0) ? ACS_LLCORNER : entry->value; entry = translate (tui_border_kind, tui_border_kind_translate_ulcorner); tui_border_ulcorner = (entry->value < 0) ? ACS_ULCORNER : entry->value; entry = translate (tui_border_kind, tui_border_kind_translate_urcorner); tui_border_urcorner = (entry->value < 0) ? ACS_URCORNER : entry->value; entry = translate (tui_border_kind, tui_border_kind_translate_hline); tui_border_hline = (entry->value < 0) ? ACS_HLINE : entry->value; entry = translate (tui_border_kind, tui_border_kind_translate_vline); tui_border_vline = (entry->value < 0) ? ACS_VLINE : entry->value; return need_redraw; } static void set_tui_cmd (char *args, int from_tty) { } static void show_tui_cmd (char *args, int from_tty) { } /* ** _initialize_tuiWin(). ** Function to initialize gdb commands, for tui window manipulation. */ void _initialize_tuiWin (void) { struct cmd_list_element *c; static struct cmd_list_element *tui_setlist; static struct cmd_list_element *tui_showlist; /* Define the classes of commands. They will appear in the help list in the reverse of this order. */ add_cmd ("tui", class_tui, NULL, "Text User Interface commands.", &cmdlist); add_prefix_cmd ("tui", class_tui, set_tui_cmd, "TUI configuration variables", &tui_setlist, "set tui ", 0/*allow-unknown*/, &setlist); add_prefix_cmd ("tui", class_tui, show_tui_cmd, "TUI configuration variables", &tui_showlist, "show tui ", 0/*allow-unknown*/, &showlist); add_com ("refresh", class_tui, _tuiRefreshAll_command, "Refresh the terminal display.\n"); if (xdb_commands) add_com_alias ("U", "refresh", class_tui, 0); add_com ("tabset", class_tui, _tuiSetTabWidth_command, "Set the width (in characters) of tab stops.\n\ Usage: tabset \n"); add_com ("winheight", class_tui, _tuiSetWinHeight_command, "Set the height of a specified window.\n\ Usage: winheight [+ | -] <#lines>\n\ Window names are:\n\ src : the source window\n\ cmd : the command window\n\ asm : the disassembly window\n\ regs : the register display\n"); add_com_alias ("wh", "winheight", class_tui, 0); add_info ("win", _tuiAllWindowsInfo, "List of all displayed windows.\n"); add_com ("focus", class_tui, _tuiSetFocus_command, "Set focus to named window or next/prev window.\n\ Usage: focus { | next | prev}\n\ Valid Window names are:\n\ src : the source window\n\ asm : the disassembly window\n\ regs : the register display\n\ cmd : the command window\n"); add_com_alias ("fs", "focus", class_tui, 0); add_com ("+", class_tui, _tuiScrollForward_command, "Scroll window forward.\nUsage: + [win] [n]\n"); add_com ("-", class_tui, _tuiScrollBackward_command, "Scroll window backward.\nUsage: - [win] [n]\n"); add_com ("<", class_tui, _tuiScrollLeft_command, "Scroll window forward.\nUsage: < [win] [n]\n"); add_com (">", class_tui, _tuiScrollRight_command, "Scroll window backward.\nUsage: > [win] [n]\n"); if (xdb_commands) add_com ("w", class_xdb, _tuiXDBsetWinHeight_command, "XDB compatibility command for setting the height of a command window.\n\ Usage: w <#lines>\n"); /* Define the tui control variables. */ c = add_set_enum_cmd ("border-kind", no_class, tui_border_kind_enums, &tui_border_kind, "Set the kind of border for TUI windows.\n" "This variable controls the border of TUI windows:\n" "space use a white space\n" "ascii use ascii characters + - | for the border\n" "acs use the Alternate Character Set\n", &tui_setlist); add_show_from_set (c, &tui_showlist); c = add_set_enum_cmd ("border-mode", no_class, tui_border_mode_enums, &tui_border_mode, "Set the attribute mode to use for the TUI window borders.\n" "This variable controls the attributes to use for the window borders:\n" "normal normal display\n" "standout use highlight mode of terminal\n" "reverse use reverse video mode\n" "half use half bright\n" "half-standout use half bright and standout mode\n" "bold use extra bright or bold\n" "bold-standout use extra bright or bold with standout mode\n", &tui_setlist); add_show_from_set (c, &tui_showlist); c = add_set_enum_cmd ("active-border-mode", no_class, tui_border_mode_enums, &tui_active_border_mode, "Set the attribute mode to use for the active TUI window border.\n" "This variable controls the attributes to use for the active window border:\n" "normal normal display\n" "standout use highlight mode of terminal\n" "reverse use reverse video mode\n" "half use half bright\n" "half-standout use half bright and standout mode\n" "bold use extra bright or bold\n" "bold-standout use extra bright or bold with standout mode\n", &tui_setlist); add_show_from_set (c, &tui_showlist); } /* Update gdb's knowledge of the terminal size. */ void tui_update_gdb_sizes () { char cmd[50]; int screenheight, screenwidth; rl_get_screen_size (&screenheight, &screenwidth); /* Set to TUI command window dimension or use readline values. */ sprintf (cmd, "set width %d", tui_active ? cmdWin->generic.width : screenwidth); execute_command (cmd, 0); sprintf (cmd, "set height %d", tui_active ? cmdWin->generic.height : screenheight); execute_command (cmd, 0); } /* ** tuiSetWinFocusTo ** Set the logical focus to winInfo */ void tuiSetWinFocusTo (TuiWinInfoPtr winInfo) { if (m_winPtrNotNull (winInfo)) { TuiWinInfoPtr winWithFocus = tuiWinWithFocus (); if (m_winPtrNotNull (winWithFocus) && winWithFocus->generic.type != CMD_WIN) unhighlightWin (winWithFocus); tuiSetWinWithFocus (winInfo); if (winInfo->generic.type != CMD_WIN) highlightWin (winInfo); } return; } /* tuiSetWinFocusTo */ /* ** tuiScrollForward(). */ void tuiScrollForward (TuiWinInfoPtr winToScroll, int numToScroll) { if (winToScroll != cmdWin) { int _numToScroll = numToScroll; if (numToScroll == 0) _numToScroll = winToScroll->generic.height - 3; /* ** If we are scrolling the source or disassembly window, do a ** "psuedo" scroll since not all of the source is in memory, ** only what is in the viewport. If winToScroll is the ** command window do nothing since the term should handle it. */ if (winToScroll == srcWin) tuiVerticalSourceScroll (FORWARD_SCROLL, _numToScroll); else if (winToScroll == disassemWin) tuiVerticalDisassemScroll (FORWARD_SCROLL, _numToScroll); else if (winToScroll == dataWin) tuiVerticalDataScroll (FORWARD_SCROLL, _numToScroll); } return; } /* tuiScrollForward */ /* ** tuiScrollBackward(). */ void tuiScrollBackward (TuiWinInfoPtr winToScroll, int numToScroll) { if (winToScroll != cmdWin) { int _numToScroll = numToScroll; if (numToScroll == 0) _numToScroll = winToScroll->generic.height - 3; /* ** If we are scrolling the source or disassembly window, do a ** "psuedo" scroll since not all of the source is in memory, ** only what is in the viewport. If winToScroll is the ** command window do nothing since the term should handle it. */ if (winToScroll == srcWin) tuiVerticalSourceScroll (BACKWARD_SCROLL, _numToScroll); else if (winToScroll == disassemWin) tuiVerticalDisassemScroll (BACKWARD_SCROLL, _numToScroll); else if (winToScroll == dataWin) tuiVerticalDataScroll (BACKWARD_SCROLL, _numToScroll); } return; } /* tuiScrollBackward */ /* ** tuiScrollLeft(). */ void tuiScrollLeft (TuiWinInfoPtr winToScroll, int numToScroll) { if (winToScroll != cmdWin) { int _numToScroll = numToScroll; if (_numToScroll == 0) _numToScroll = 1; /* ** If we are scrolling the source or disassembly window, do a ** "psuedo" scroll since not all of the source is in memory, ** only what is in the viewport. If winToScroll is the ** command window do nothing since the term should handle it. */ if (winToScroll == srcWin || winToScroll == disassemWin) tuiHorizontalSourceScroll (winToScroll, LEFT_SCROLL, _numToScroll); } return; } /* tuiScrollLeft */ /* ** tuiScrollRight(). */ void tuiScrollRight (TuiWinInfoPtr winToScroll, int numToScroll) { if (winToScroll != cmdWin) { int _numToScroll = numToScroll; if (_numToScroll == 0) _numToScroll = 1; /* ** If we are scrolling the source or disassembly window, do a ** "psuedo" scroll since not all of the source is in memory, ** only what is in the viewport. If winToScroll is the ** command window do nothing since the term should handle it. */ if (winToScroll == srcWin || winToScroll == disassemWin) tuiHorizontalSourceScroll (winToScroll, RIGHT_SCROLL, _numToScroll); } return; } /* tuiScrollRight */ /* ** tui_scroll(). ** Scroll a window. Arguments are passed through a va_list. */ void tui_scroll (TuiScrollDirection direction, TuiWinInfoPtr winToScroll, int numToScroll) { switch (direction) { case FORWARD_SCROLL: tuiScrollForward (winToScroll, numToScroll); break; case BACKWARD_SCROLL: tuiScrollBackward (winToScroll, numToScroll); break; case LEFT_SCROLL: tuiScrollLeft (winToScroll, numToScroll); break; case RIGHT_SCROLL: tuiScrollRight (winToScroll, numToScroll); break; default: break; } } /* ** tuiRefreshAll(). */ void tuiRefreshAll (void) { TuiWinType type; clearok (curscr, TRUE); refreshAll (winList); for (type = SRC_WIN; type < MAX_MAJOR_WINDOWS; type++) { if (winList[type] && winList[type]->generic.isVisible) { switch (type) { case SRC_WIN: case DISASSEM_WIN: tuiShowSourceContent (winList[type]); checkAndDisplayHighlightIfNeeded (winList[type]); tuiEraseExecInfoContent (winList[type]); tuiUpdateExecInfo (winList[type]); break; case DATA_WIN: tuiRefreshDataWin (); break; default: break; } } } tuiShowLocatorContent (); } /* ** tuiResizeAll(). ** Resize all the windows based on the the terminal size. This ** function gets called from within the readline sinwinch handler. */ void tuiResizeAll (void) { int heightDiff, widthDiff; int screenheight, screenwidth; rl_get_screen_size (&screenheight, &screenwidth); widthDiff = screenwidth - termWidth (); heightDiff = screenheight - termHeight (); if (heightDiff || widthDiff) { TuiLayoutType curLayout = currentLayout (); TuiWinInfoPtr winWithFocus = tuiWinWithFocus (); TuiWinInfoPtr firstWin, secondWin; TuiGenWinInfoPtr locator = locatorWinInfoPtr (); TuiWinType winType; int newHeight, splitDiff, cmdSplitDiff, numWinsDisplayed = 2; /* turn keypad off while we resize */ if (winWithFocus != cmdWin) keypad (cmdWin->generic.handle, FALSE); tui_update_gdb_sizes (); setTermHeightTo (screenheight); setTermWidthTo (screenwidth); if (curLayout == SRC_DISASSEM_COMMAND || curLayout == SRC_DATA_COMMAND || curLayout == DISASSEM_DATA_COMMAND) numWinsDisplayed++; splitDiff = heightDiff / numWinsDisplayed; cmdSplitDiff = splitDiff; if (heightDiff % numWinsDisplayed) { if (heightDiff < 0) cmdSplitDiff--; else cmdSplitDiff++; } /* now adjust each window */ clear (); refresh (); switch (curLayout) { case SRC_COMMAND: case DISASSEM_COMMAND: firstWin = (TuiWinInfoPtr) (sourceWindows ())->list[0]; firstWin->generic.width += widthDiff; locator->width += widthDiff; /* check for invalid heights */ if (heightDiff == 0) newHeight = firstWin->generic.height; else if ((firstWin->generic.height + splitDiff) >= (screenheight - MIN_CMD_WIN_HEIGHT - 1)) newHeight = screenheight - MIN_CMD_WIN_HEIGHT - 1; else if ((firstWin->generic.height + splitDiff) <= 0) newHeight = MIN_WIN_HEIGHT; else newHeight = firstWin->generic.height + splitDiff; _makeInvisibleAndSetNewHeight (firstWin, newHeight); cmdWin->generic.origin.y = locator->origin.y + 1; cmdWin->generic.width += widthDiff; newHeight = screenheight - cmdWin->generic.origin.y; _makeInvisibleAndSetNewHeight (cmdWin, newHeight); _makeVisibleWithNewHeight (firstWin); _makeVisibleWithNewHeight (cmdWin); if (firstWin->generic.contentSize <= 0) tuiEraseSourceContent (firstWin, EMPTY_SOURCE_PROMPT); break; default: if (curLayout == SRC_DISASSEM_COMMAND) { firstWin = srcWin; firstWin->generic.width += widthDiff; secondWin = disassemWin; secondWin->generic.width += widthDiff; } else { firstWin = dataWin; firstWin->generic.width += widthDiff; secondWin = (TuiWinInfoPtr) (sourceWindows ())->list[0]; secondWin->generic.width += widthDiff; } /* Change the first window's height/width */ /* check for invalid heights */ if (heightDiff == 0) newHeight = firstWin->generic.height; else if ((firstWin->generic.height + secondWin->generic.height + (splitDiff * 2)) >= (screenheight - MIN_CMD_WIN_HEIGHT - 1)) newHeight = (screenheight - MIN_CMD_WIN_HEIGHT - 1) / 2; else if ((firstWin->generic.height + splitDiff) <= 0) newHeight = MIN_WIN_HEIGHT; else newHeight = firstWin->generic.height + splitDiff; _makeInvisibleAndSetNewHeight (firstWin, newHeight); if (firstWin == dataWin && widthDiff != 0) firstWin->detail.dataDisplayInfo.regsColumnCount = tuiCalculateRegsColumnCount ( firstWin->detail.dataDisplayInfo.regsDisplayType); locator->width += widthDiff; /* Change the second window's height/width */ /* check for invalid heights */ if (heightDiff == 0) newHeight = secondWin->generic.height; else if ((firstWin->generic.height + secondWin->generic.height + (splitDiff * 2)) >= (screenheight - MIN_CMD_WIN_HEIGHT - 1)) { newHeight = screenheight - MIN_CMD_WIN_HEIGHT - 1; if (newHeight % 2) newHeight = (newHeight / 2) + 1; else newHeight /= 2; } else if ((secondWin->generic.height + splitDiff) <= 0) newHeight = MIN_WIN_HEIGHT; else newHeight = secondWin->generic.height + splitDiff; secondWin->generic.origin.y = firstWin->generic.height - 1; _makeInvisibleAndSetNewHeight (secondWin, newHeight); /* Change the command window's height/width */ cmdWin->generic.origin.y = locator->origin.y + 1; _makeInvisibleAndSetNewHeight ( cmdWin, cmdWin->generic.height + cmdSplitDiff); _makeVisibleWithNewHeight (firstWin); _makeVisibleWithNewHeight (secondWin); _makeVisibleWithNewHeight (cmdWin); if (firstWin->generic.contentSize <= 0) tuiEraseSourceContent (firstWin, EMPTY_SOURCE_PROMPT); if (secondWin->generic.contentSize <= 0) tuiEraseSourceContent (secondWin, EMPTY_SOURCE_PROMPT); break; } /* ** Now remove all invisible windows, and their content so that they get ** created again when called for with the new size */ for (winType = SRC_WIN; (winType < MAX_MAJOR_WINDOWS); winType++) { if (winType != CMD_WIN && m_winPtrNotNull (winList[winType]) && !winList[winType]->generic.isVisible) { freeWindow (winList[winType]); winList[winType] = (TuiWinInfoPtr) NULL; } } tuiSetWinResizedTo (TRUE); /* turn keypad back on, unless focus is in the command window */ if (winWithFocus != cmdWin) keypad (cmdWin->generic.handle, TRUE); } return; } /* tuiResizeAll */ /* ** tuiSigwinchHandler() ** SIGWINCH signal handler for the tui. This signal handler is ** always called, even when the readline package clears signals ** because it is set as the old_sigwinch() (TUI only) */ void tuiSigwinchHandler (int signal) { /* ** Say that a resize was done so that the readline can do it ** later when appropriate. */ tuiSetWinResizedTo (TRUE); return; } /* tuiSigwinchHandler */ /************************* ** STATIC LOCAL FUNCTIONS **************************/ /* ** _tuiScrollForward_command(). */ static void _tuiScrollForward_command (char *arg, int fromTTY) { int numToScroll = 1; TuiWinInfoPtr winToScroll; /* Make sure the curses mode is enabled. */ tui_enable (); if (arg == (char *) NULL) _parseScrollingArgs (arg, &winToScroll, (int *) NULL); else _parseScrollingArgs (arg, &winToScroll, &numToScroll); tui_scroll (FORWARD_SCROLL, winToScroll, numToScroll); } /* ** _tuiScrollBackward_command(). */ static void _tuiScrollBackward_command (char *arg, int fromTTY) { int numToScroll = 1; TuiWinInfoPtr winToScroll; /* Make sure the curses mode is enabled. */ tui_enable (); if (arg == (char *) NULL) _parseScrollingArgs (arg, &winToScroll, (int *) NULL); else _parseScrollingArgs (arg, &winToScroll, &numToScroll); tui_scroll (BACKWARD_SCROLL, winToScroll, numToScroll); } /* ** _tuiScrollLeft_command(). */ static void _tuiScrollLeft_command (char *arg, int fromTTY) { int numToScroll; TuiWinInfoPtr winToScroll; /* Make sure the curses mode is enabled. */ tui_enable (); _parseScrollingArgs (arg, &winToScroll, &numToScroll); tui_scroll (LEFT_SCROLL, winToScroll, numToScroll); } /* ** _tuiScrollRight_command(). */ static void _tuiScrollRight_command (char *arg, int fromTTY) { int numToScroll; TuiWinInfoPtr winToScroll; /* Make sure the curses mode is enabled. */ tui_enable (); _parseScrollingArgs (arg, &winToScroll, &numToScroll); tui_scroll (RIGHT_SCROLL, winToScroll, numToScroll); } /* ** _tuiSetFocus(). ** Set focus to the window named by 'arg' */ static void _tuiSetFocus (char *arg, int fromTTY) { if (arg != (char *) NULL) { char *bufPtr = (char *) xstrdup (arg); int i; TuiWinInfoPtr winInfo = (TuiWinInfoPtr) NULL; for (i = 0; (i < strlen (bufPtr)); i++) bufPtr[i] = toupper (arg[i]); if (subset_compare (bufPtr, "NEXT")) winInfo = tuiNextWin (tuiWinWithFocus ()); else if (subset_compare (bufPtr, "PREV")) winInfo = tuiPrevWin (tuiWinWithFocus ()); else winInfo = partialWinByName (bufPtr); if (winInfo == (TuiWinInfoPtr) NULL || !winInfo->generic.isVisible) warning ("Invalid window specified. \n\ The window name specified must be valid and visible.\n"); else { tuiSetWinFocusTo (winInfo); keypad (cmdWin->generic.handle, (winInfo != cmdWin)); } if (dataWin && dataWin->generic.isVisible) tuiRefreshDataWin (); tuiFree (bufPtr); printf_filtered ("Focus set to %s window.\n", winName ((TuiGenWinInfoPtr) tuiWinWithFocus ())); } else warning ("Incorrect Number of Arguments.\n%s", FOCUS_USAGE); return; } /* _tuiSetFocus */ /* ** _tuiSetFocus_command() */ static void _tuiSetFocus_command (char *arg, int fromTTY) { /* Make sure the curses mode is enabled. */ tui_enable (); _tuiSetFocus (arg, fromTTY); } /* ** _tuiAllWindowsInfo(). */ static void _tuiAllWindowsInfo (char *arg, int fromTTY) { TuiWinType type; TuiWinInfoPtr winWithFocus = tuiWinWithFocus (); for (type = SRC_WIN; (type < MAX_MAJOR_WINDOWS); type++) if (winList[type] && winList[type]->generic.isVisible) { if (winWithFocus == winList[type]) printf_filtered (" %s\t(%d lines) \n", winName (&winList[type]->generic), winList[type]->generic.height); else printf_filtered (" %s\t(%d lines)\n", winName (&winList[type]->generic), winList[type]->generic.height); } return; } /* _tuiAllWindowsInfo */ /* ** _tuiRefreshAll_command(). */ static void _tuiRefreshAll_command (char *arg, int fromTTY) { /* Make sure the curses mode is enabled. */ tui_enable (); tuiRefreshAll (); } /* ** _tuiSetWinTabWidth_command(). ** Set the height of the specified window. */ static void _tuiSetTabWidth_command (char *arg, int fromTTY) { /* Make sure the curses mode is enabled. */ tui_enable (); if (arg != (char *) NULL) { int ts; ts = atoi (arg); if (ts > 0) tuiSetDefaultTabLen (ts); else warning ("Tab widths greater than 0 must be specified.\n"); } return; } /* _tuiSetTabWidth_command */ /* ** _tuiSetWinHeight(). ** Set the height of the specified window. */ static void _tuiSetWinHeight (char *arg, int fromTTY) { /* Make sure the curses mode is enabled. */ tui_enable (); if (arg != (char *) NULL) { char *buf = xstrdup (arg); char *bufPtr = buf; char *wname = (char *) NULL; int newHeight, i; TuiWinInfoPtr winInfo; wname = bufPtr; bufPtr = strchr (bufPtr, ' '); if (bufPtr != (char *) NULL) { *bufPtr = (char) 0; /* ** Validate the window name */ for (i = 0; i < strlen (wname); i++) wname[i] = toupper (wname[i]); winInfo = partialWinByName (wname); if (winInfo == (TuiWinInfoPtr) NULL || !winInfo->generic.isVisible) warning ("Invalid window specified. \n\ The window name specified must be valid and visible.\n"); else { /* Process the size */ while (*(++bufPtr) == ' ') ; if (*bufPtr != (char) 0) { int negate = FALSE; int fixedSize = TRUE; int inputNo;; if (*bufPtr == '+' || *bufPtr == '-') { if (*bufPtr == '-') negate = TRUE; fixedSize = FALSE; bufPtr++; } inputNo = atoi (bufPtr); if (inputNo > 0) { if (negate) inputNo *= (-1); if (fixedSize) newHeight = inputNo; else newHeight = winInfo->generic.height + inputNo; /* ** Now change the window's height, and adjust all ** other windows around it */ if (_tuiAdjustWinHeights (winInfo, newHeight) == TUI_FAILURE) warning ("Invalid window height specified.\n%s", WIN_HEIGHT_USAGE); else tui_update_gdb_sizes (); } else warning ("Invalid window height specified.\n%s", WIN_HEIGHT_USAGE); } } } else printf_filtered (WIN_HEIGHT_USAGE); if (buf != (char *) NULL) tuiFree (buf); } else printf_filtered (WIN_HEIGHT_USAGE); return; } /* _tuiSetWinHeight */ /* ** _tuiSetWinHeight_command(). ** Set the height of the specified window, with va_list. */ static void _tuiSetWinHeight_command (char *arg, int fromTTY) { /* Make sure the curses mode is enabled. */ tui_enable (); _tuiSetWinHeight (arg, fromTTY); } /* ** _tuiXDBsetWinHeight(). ** XDB Compatibility command for setting the window height. This will ** increase or decrease the command window by the specified amount. */ static void _tuiXDBsetWinHeight (char *arg, int fromTTY) { /* Make sure the curses mode is enabled. */ tui_enable (); if (arg != (char *) NULL) { int inputNo = atoi (arg); if (inputNo > 0) { /* Add 1 for the locator */ int newHeight = termHeight () - (inputNo + 1); if (!_newHeightOk (winList[CMD_WIN], newHeight) || _tuiAdjustWinHeights (winList[CMD_WIN], newHeight) == TUI_FAILURE) warning ("Invalid window height specified.\n%s", XDBWIN_HEIGHT_USAGE); } else warning ("Invalid window height specified.\n%s", XDBWIN_HEIGHT_USAGE); } else warning ("Invalid window height specified.\n%s", XDBWIN_HEIGHT_USAGE); return; } /* _tuiXDBsetWinHeight */ /* ** _tuiSetWinHeight_command(). ** Set the height of the specified window, with va_list. */ static void _tuiXDBsetWinHeight_command (char *arg, int fromTTY) { _tuiXDBsetWinHeight (arg, fromTTY); } /* ** _tuiAdjustWinHeights(). ** Function to adjust all window heights around the primary */ static TuiStatus _tuiAdjustWinHeights (TuiWinInfoPtr primaryWinInfo, int newHeight) { TuiStatus status = TUI_FAILURE; if (_newHeightOk (primaryWinInfo, newHeight)) { status = TUI_SUCCESS; if (newHeight != primaryWinInfo->generic.height) { int diff; TuiWinInfoPtr winInfo; TuiGenWinInfoPtr locator = locatorWinInfoPtr (); TuiLayoutType curLayout = currentLayout (); diff = (newHeight - primaryWinInfo->generic.height) * (-1); if (curLayout == SRC_COMMAND || curLayout == DISASSEM_COMMAND) { TuiWinInfoPtr srcWinInfo; _makeInvisibleAndSetNewHeight (primaryWinInfo, newHeight); if (primaryWinInfo->generic.type == CMD_WIN) { winInfo = (TuiWinInfoPtr) (sourceWindows ())->list[0]; srcWinInfo = winInfo; } else { winInfo = winList[CMD_WIN]; srcWinInfo = primaryWinInfo; } _makeInvisibleAndSetNewHeight (winInfo, winInfo->generic.height + diff); cmdWin->generic.origin.y = locator->origin.y + 1; _makeVisibleWithNewHeight (winInfo); _makeVisibleWithNewHeight (primaryWinInfo); if (srcWinInfo->generic.contentSize <= 0) tuiEraseSourceContent (srcWinInfo, EMPTY_SOURCE_PROMPT); } else { TuiWinInfoPtr firstWin, secondWin; if (curLayout == SRC_DISASSEM_COMMAND) { firstWin = srcWin; secondWin = disassemWin; } else { firstWin = dataWin; secondWin = (TuiWinInfoPtr) (sourceWindows ())->list[0]; } if (primaryWinInfo == cmdWin) { /* ** Split the change in height accross the 1st & 2nd windows ** adjusting them as well. */ int firstSplitDiff = diff / 2; /* subtract the locator */ int secondSplitDiff = firstSplitDiff; if (diff % 2) { if (firstWin->generic.height > secondWin->generic.height) if (diff < 0) firstSplitDiff--; else firstSplitDiff++; else { if (diff < 0) secondSplitDiff--; else secondSplitDiff++; } } /* make sure that the minimum hieghts are honored */ while ((firstWin->generic.height + firstSplitDiff) < 3) { firstSplitDiff++; secondSplitDiff--; } while ((secondWin->generic.height + secondSplitDiff) < 3) { secondSplitDiff++; firstSplitDiff--; } _makeInvisibleAndSetNewHeight ( firstWin, firstWin->generic.height + firstSplitDiff); secondWin->generic.origin.y = firstWin->generic.height - 1; _makeInvisibleAndSetNewHeight ( secondWin, secondWin->generic.height + secondSplitDiff); cmdWin->generic.origin.y = locator->origin.y + 1; _makeInvisibleAndSetNewHeight (cmdWin, newHeight); } else { if ((cmdWin->generic.height + diff) < 1) { /* ** If there is no way to increase the command window ** take real estate from the 1st or 2nd window. */ if ((cmdWin->generic.height + diff) < 1) { int i; for (i = cmdWin->generic.height + diff; (i < 1); i++) if (primaryWinInfo == firstWin) secondWin->generic.height--; else firstWin->generic.height--; } } if (primaryWinInfo == firstWin) _makeInvisibleAndSetNewHeight (firstWin, newHeight); else _makeInvisibleAndSetNewHeight ( firstWin, firstWin->generic.height); secondWin->generic.origin.y = firstWin->generic.height - 1; if (primaryWinInfo == secondWin) _makeInvisibleAndSetNewHeight (secondWin, newHeight); else _makeInvisibleAndSetNewHeight ( secondWin, secondWin->generic.height); cmdWin->generic.origin.y = locator->origin.y + 1; if ((cmdWin->generic.height + diff) < 1) _makeInvisibleAndSetNewHeight (cmdWin, 1); else _makeInvisibleAndSetNewHeight ( cmdWin, cmdWin->generic.height + diff); } _makeVisibleWithNewHeight (cmdWin); _makeVisibleWithNewHeight (secondWin); _makeVisibleWithNewHeight (firstWin); if (firstWin->generic.contentSize <= 0) tuiEraseSourceContent (firstWin, EMPTY_SOURCE_PROMPT); if (secondWin->generic.contentSize <= 0) tuiEraseSourceContent (secondWin, EMPTY_SOURCE_PROMPT); } } } return status; } /* _tuiAdjustWinHeights */ /* ** _makeInvisibleAndSetNewHeight(). ** Function make the target window (and auxillary windows associated ** with the targer) invisible, and set the new height and location. */ static void _makeInvisibleAndSetNewHeight (TuiWinInfoPtr winInfo, int height) { int i; TuiGenWinInfoPtr genWinInfo; m_beInvisible (&winInfo->generic); winInfo->generic.height = height; if (height > 1) winInfo->generic.viewportHeight = height - 1; else winInfo->generic.viewportHeight = height; if (winInfo != cmdWin) winInfo->generic.viewportHeight--; /* Now deal with the auxillary windows associated with winInfo */ switch (winInfo->generic.type) { case SRC_WIN: case DISASSEM_WIN: genWinInfo = winInfo->detail.sourceInfo.executionInfo; m_beInvisible (genWinInfo); genWinInfo->height = height; genWinInfo->origin.y = winInfo->generic.origin.y; if (height > 1) genWinInfo->viewportHeight = height - 1; else genWinInfo->viewportHeight = height; if (winInfo != cmdWin) genWinInfo->viewportHeight--; if (m_hasLocator (winInfo)) { genWinInfo = locatorWinInfoPtr (); m_beInvisible (genWinInfo); genWinInfo->origin.y = winInfo->generic.origin.y + height; } break; case DATA_WIN: /* delete all data item windows */ for (i = 0; i < winInfo->generic.contentSize; i++) { genWinInfo = (TuiGenWinInfoPtr) & ((TuiWinElementPtr) winInfo->generic.content[i])->whichElement.dataWindow; tuiDelwin (genWinInfo->handle); genWinInfo->handle = (WINDOW *) NULL; } break; default: break; } } /* ** _makeVisibleWithNewHeight(). ** Function to make the windows with new heights visible. ** This means re-creating the windows' content since the window ** had to be destroyed to be made invisible. */ static void _makeVisibleWithNewHeight (TuiWinInfoPtr winInfo) { struct symtab *s; m_beVisible (&winInfo->generic); checkAndDisplayHighlightIfNeeded (winInfo); switch (winInfo->generic.type) { case SRC_WIN: case DISASSEM_WIN: freeWinContent (winInfo->detail.sourceInfo.executionInfo); m_beVisible (winInfo->detail.sourceInfo.executionInfo); if (winInfo->generic.content != (OpaquePtr) NULL) { TuiLineOrAddress lineOrAddr; struct symtab_and_line cursal = get_current_source_symtab_and_line (); if (winInfo->generic.type == SRC_WIN) lineOrAddr.lineNo = winInfo->detail.sourceInfo.startLineOrAddr.lineNo; else lineOrAddr.addr = winInfo->detail.sourceInfo.startLineOrAddr.addr; freeWinContent (&winInfo->generic); tuiUpdateSourceWindow (winInfo, cursal.symtab, lineOrAddr, TRUE); } else if (deprecated_selected_frame != (struct frame_info *) NULL) { TuiLineOrAddress line; struct symtab_and_line cursal = get_current_source_symtab_and_line (); s = find_pc_symtab (deprecated_selected_frame->pc); if (winInfo->generic.type == SRC_WIN) line.lineNo = cursal.line; else { find_line_pc (s, cursal.line, &line.addr); } tuiUpdateSourceWindow (winInfo, s, line, TRUE); } if (m_hasLocator (winInfo)) { m_beVisible (locatorWinInfoPtr ()); tuiShowLocatorContent (); } break; case DATA_WIN: tuiDisplayAllData (); break; case CMD_WIN: winInfo->detail.commandInfo.curLine = 0; winInfo->detail.commandInfo.curch = 0; wmove (winInfo->generic.handle, winInfo->detail.commandInfo.curLine, winInfo->detail.commandInfo.curch); break; default: break; } return; } /* _makeVisibleWithNewHeight */ static int _newHeightOk (TuiWinInfoPtr primaryWinInfo, int newHeight) { int ok = (newHeight < termHeight ()); if (ok) { int diff; TuiLayoutType curLayout = currentLayout (); diff = (newHeight - primaryWinInfo->generic.height) * (-1); if (curLayout == SRC_COMMAND || curLayout == DISASSEM_COMMAND) { ok = ((primaryWinInfo->generic.type == CMD_WIN && newHeight <= (termHeight () - 4) && newHeight >= MIN_CMD_WIN_HEIGHT) || (primaryWinInfo->generic.type != CMD_WIN && newHeight <= (termHeight () - 2) && newHeight >= MIN_WIN_HEIGHT)); if (ok) { /* check the total height */ TuiWinInfoPtr winInfo; if (primaryWinInfo == cmdWin) winInfo = (TuiWinInfoPtr) (sourceWindows ())->list[0]; else winInfo = cmdWin; ok = ((newHeight + (winInfo->generic.height + diff)) <= termHeight ()); } } else { int curTotalHeight, totalHeight, minHeight = 0; TuiWinInfoPtr firstWin, secondWin; if (curLayout == SRC_DISASSEM_COMMAND) { firstWin = srcWin; secondWin = disassemWin; } else { firstWin = dataWin; secondWin = (TuiWinInfoPtr) (sourceWindows ())->list[0]; } /* ** We could simply add all the heights to obtain the same result ** but below is more explicit since we subtract 1 for the ** line that the first and second windows share, and add one ** for the locator. */ totalHeight = curTotalHeight = (firstWin->generic.height + secondWin->generic.height - 1) + cmdWin->generic.height + 1 /*locator */ ; if (primaryWinInfo == cmdWin) { /* locator included since first & second win share a line */ ok = ((firstWin->generic.height + secondWin->generic.height + diff) >= (MIN_WIN_HEIGHT * 2) && newHeight >= MIN_CMD_WIN_HEIGHT); if (ok) { totalHeight = newHeight + (firstWin->generic.height + secondWin->generic.height + diff); minHeight = MIN_CMD_WIN_HEIGHT; } } else { minHeight = MIN_WIN_HEIGHT; /* ** First see if we can increase/decrease the command ** window. And make sure that the command window is ** at least 1 line */ ok = ((cmdWin->generic.height + diff) > 0); if (!ok) { /* ** Looks like we have to increase/decrease one of ** the other windows */ if (primaryWinInfo == firstWin) ok = (secondWin->generic.height + diff) >= minHeight; else ok = (firstWin->generic.height + diff) >= minHeight; } if (ok) { if (primaryWinInfo == firstWin) totalHeight = newHeight + secondWin->generic.height + cmdWin->generic.height + diff; else totalHeight = newHeight + firstWin->generic.height + cmdWin->generic.height + diff; } } /* ** Now make sure that the proposed total height doesn't exceed ** the old total height. */ if (ok) ok = (newHeight >= minHeight && totalHeight <= curTotalHeight); } } return ok; } /* _newHeightOk */ /* ** _parseScrollingArgs(). */ static void _parseScrollingArgs (char *arg, TuiWinInfoPtr * winToScroll, int *numToScroll) { if (numToScroll) *numToScroll = 0; *winToScroll = tuiWinWithFocus (); /* ** First set up the default window to scroll, in case there is no ** window name arg */ if (arg != (char *) NULL) { char *buf, *bufPtr; /* process the number of lines to scroll */ buf = bufPtr = xstrdup (arg); if (isdigit (*bufPtr)) { char *numStr; numStr = bufPtr; bufPtr = strchr (bufPtr, ' '); if (bufPtr != (char *) NULL) { *bufPtr = (char) 0; if (numToScroll) *numToScroll = atoi (numStr); bufPtr++; } else if (numToScroll) *numToScroll = atoi (numStr); } /* process the window name if one is specified */ if (bufPtr != (char *) NULL) { char *wname; int i; if (*bufPtr == ' ') while (*(++bufPtr) == ' ') ; if (*bufPtr != (char) 0) wname = bufPtr; else wname = "?"; /* Validate the window name */ for (i = 0; i < strlen (wname); i++) wname[i] = toupper (wname[i]); *winToScroll = partialWinByName (wname); if (*winToScroll == (TuiWinInfoPtr) NULL || !(*winToScroll)->generic.isVisible) warning ("Invalid window specified. \n\ The window name specified must be valid and visible.\n"); else if (*winToScroll == cmdWin) *winToScroll = (TuiWinInfoPtr) (sourceWindows ())->list[0]; } tuiFree (buf); } return; } /* _parseScrollingArgs */