Change-Id: Ie1da925aceb01c2d21b472bf171000803004578f Signed-off-by: Elyes HAOUAS <ehaouas@noos.fr> Reviewed-on: https://review.coreboot.org/25856 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Julius Werner <jwerner@chromium.org>
		
			
				
	
	
		
			557 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			557 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /****************************************************************************
 | |
|  * Copyright (c) 1998-2009,2010 Free Software Foundation, Inc.              *
 | |
|  *                                                                          *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining a  *
 | |
|  * copy of this software and associated documentation files (the            *
 | |
|  * "Software"), to deal in the Software without restriction, including      *
 | |
|  * without limitation the rights to use, copy, modify, merge, publish,      *
 | |
|  * distribute, distribute with modifications, sublicense, and/or sell       *
 | |
|  * copies of the Software, and to permit persons to whom the Software is    *
 | |
|  * furnished to do so, subject to the following conditions:                 *
 | |
|  *                                                                          *
 | |
|  * The above copyright notice and this permission notice shall be included  *
 | |
|  * in all copies or substantial portions of the Software.                   *
 | |
|  *                                                                          *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
 | |
|  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
 | |
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
 | |
|  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
 | |
|  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
 | |
|  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
 | |
|  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
 | |
|  *                                                                          *
 | |
|  * Except as contained in this notice, the name(s) of the above copyright   *
 | |
|  * holders shall not be used in advertising or otherwise to promote the     *
 | |
|  * sale, use or other dealings in this Software without prior written       *
 | |
|  * authorization.                                                           *
 | |
|  ****************************************************************************/
 | |
| 
 | |
| /****************************************************************************
 | |
|  *   Author:  Juergen Pfeifer, 1995,1997                                    *
 | |
|  ****************************************************************************/
 | |
| 
 | |
| /***************************************************************************
 | |
| * Module m_driver                                                          *
 | |
| * Central dispatching routine                                              *
 | |
| ***************************************************************************/
 | |
| 
 | |
| #include "menu.priv.h"
 | |
| 
 | |
| MODULE_ID("$Id: m_driver.c,v 1.29 2010/01/23 21:20:10 tom Exp $")
 | |
| 
 | |
| /* Macros */
 | |
| 
 | |
| /* Remove the last character from the match pattern buffer */
 | |
| #define Remove_Character_From_Pattern(menu) \
 | |
|   (menu)->pattern[--((menu)->pindex)] = '\0'
 | |
| 
 | |
| /* Add a new character to the match pattern buffer */
 | |
| #define Add_Character_To_Pattern(menu,ch) \
 | |
|   { (menu)->pattern[((menu)->pindex)++] = (ch);\
 | |
|     (menu)->pattern[(menu)->pindex] = '\0'; }
 | |
| 
 | |
| /*---------------------------------------------------------------------------
 | |
| |   Facility      :  libnmenu
 | |
| |   Function      :  static bool Is_Sub_String(
 | |
| |                           bool IgnoreCaseFlag,
 | |
| |                           const char *part,
 | |
| |                           const char *string)
 | |
| |
 | |
| |   Description   :  Checks whether or not part is a substring of string.
 | |
| |
 | |
| |   Return Values :  TRUE   - if it is a substring
 | |
| |                    FALSE  - if it is not a substring
 | |
| +--------------------------------------------------------------------------*/
 | |
| static bool
 | |
| Is_Sub_String(
 | |
| 	       bool IgnoreCaseFlag,
 | |
| 	       const char *part,
 | |
| 	       const char *string
 | |
| )
 | |
| {
 | |
|   assert(part && string);
 | |
|   if (IgnoreCaseFlag)
 | |
|     {
 | |
|       while (*string && *part)
 | |
| 	{
 | |
| 	  if (toupper(UChar(*string++)) != toupper(UChar(*part)))
 | |
| 	    break;
 | |
| 	  part++;
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       while (*string && *part)
 | |
| 	if (*part != *string++)
 | |
| 	  break;
 | |
|       part++;
 | |
|     }
 | |
|   return ((*part) ? FALSE : TRUE);
 | |
| }
 | |
| 
 | |
| /*---------------------------------------------------------------------------
 | |
| |   Facility      :  libnmenu
 | |
| |   Function      :  int _nc_Match_Next_Character_In_Item_Name(
 | |
| |                           MENU *menu,
 | |
| |                           int  ch,
 | |
| |                           ITEM **item)
 | |
| |
 | |
| |   Description   :  This internal routine is called for a menu positioned
 | |
| |                    at an item with three different classes of characters:
 | |
| |                       - a printable character; the character is added to
 | |
| |                         the current pattern and the next item matching
 | |
| |                         this pattern is searched.
 | |
| |                       - NUL; the pattern stays as it is and the next item
 | |
| |                         matching the pattern is searched
 | |
| |                       - BS; the pattern stays as it is and the previous
 | |
| |                         item matching the pattern is searched
 | |
| |
 | |
| |                       The item parameter contains on call a pointer to
 | |
| |                       the item where the search starts. On return - if
 | |
| |                       a match was found - it contains a pointer to the
 | |
| |                       matching item.
 | |
| |
 | |
| |   Return Values :  E_OK        - an item matching the pattern was found
 | |
| |                    E_NO_MATCH  - nothing found
 | |
| +--------------------------------------------------------------------------*/
 | |
| NCURSES_EXPORT(int)
 | |
| _nc_Match_Next_Character_In_Item_Name
 | |
| (MENU * menu, int ch, ITEM ** item)
 | |
| {
 | |
|   bool found = FALSE, passed = FALSE;
 | |
|   int idx, last;
 | |
| 
 | |
|   T((T_CALLED("_nc_Match_Next_Character(%p,%d,%p)"),
 | |
|      (void *)menu, ch, (void *)item));
 | |
| 
 | |
|   assert(menu && item && *item);
 | |
|   idx = (*item)->index;
 | |
| 
 | |
|   if (ch && ch != BS)
 | |
|     {
 | |
|       /* if we become to long, we need no further checking : there can't be
 | |
|          a match ! */
 | |
|       if ((menu->pindex + 1) > menu->namelen)
 | |
| 	RETURN(E_NO_MATCH);
 | |
| 
 | |
|       Add_Character_To_Pattern(menu, ch);
 | |
|       /* we artificially position one item back, because in the do...while
 | |
|          loop we start with the next item. This means, that with a new
 | |
|          pattern search we always start the scan with the actual item. If
 | |
|          we do a NEXT_PATTERN oder PREV_PATTERN search, we start with the
 | |
|          one after or before the actual item. */
 | |
|       if (--idx < 0)
 | |
| 	idx = menu->nitems - 1;
 | |
|     }
 | |
| 
 | |
|   last = idx;			/* this closes the cycle */
 | |
| 
 | |
|   do
 | |
|     {
 | |
|       if (ch == BS)
 | |
| 	{			/* we have to go backward */
 | |
| 	  if (--idx < 0)
 | |
| 	    idx = menu->nitems - 1;
 | |
| 	}
 | |
|       else
 | |
| 	{			/* otherwise we always go forward */
 | |
| 	  if (++idx >= menu->nitems)
 | |
| 	    idx = 0;
 | |
| 	}
 | |
|       if (Is_Sub_String((bool)((menu->opt & O_IGNORECASE) != 0),
 | |
| 			menu->pattern,
 | |
| 			menu->items[idx]->name.str)
 | |
| 	)
 | |
| 	found = TRUE;
 | |
|       else
 | |
| 	passed = TRUE;
 | |
|     }
 | |
|   while (!found && (idx != last));
 | |
| 
 | |
|   if (found)
 | |
|     {
 | |
|       if (!((idx == (*item)->index) && passed))
 | |
| 	{
 | |
| 	  *item = menu->items[idx];
 | |
| 	  RETURN(E_OK);
 | |
| 	}
 | |
|       /* This point is reached, if we fully cycled through the item list
 | |
|          and the only match we found is the starting item. With a NEXT_PATTERN
 | |
|          or PREV_PATTERN scan this means, that there was no additional match.
 | |
|          If we searched with an expanded new pattern, we should never reach
 | |
|          this point, because if the expanded pattern matches also the actual
 | |
|          item we will find it in the first attempt (passed == FALSE) and we
 | |
|          will never cycle through the whole item array.
 | |
|        */
 | |
|       assert(ch == 0 || ch == BS);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       if (ch && ch != BS && menu->pindex > 0)
 | |
| 	{
 | |
| 	  /* if we had no match with a new pattern, we have to restore it */
 | |
| 	  Remove_Character_From_Pattern(menu);
 | |
| 	}
 | |
|     }
 | |
|   RETURN(E_NO_MATCH);
 | |
| }
 | |
| 
 | |
| /*---------------------------------------------------------------------------
 | |
| |   Facility      :  libnmenu
 | |
| |   Function      :  int menu_driver(MENU* menu, int c)
 | |
| |
 | |
| |   Description   :  Central dispatcher for the menu. Translates the logical
 | |
| |                    request 'c' into a menu action.
 | |
| |
 | |
| |   Return Values :  E_OK            - success
 | |
| |                    E_BAD_ARGUMENT  - invalid menu pointer
 | |
| |                    E_BAD_STATE     - menu is in user hook routine
 | |
| |                    E_NOT_POSTED    - menu is not posted
 | |
| +--------------------------------------------------------------------------*/
 | |
| NCURSES_EXPORT(int)
 | |
| menu_driver(MENU * menu, int c)
 | |
| {
 | |
| #define NAVIGATE(dir) \
 | |
|   if (!item->dir)\
 | |
|      result = E_REQUEST_DENIED;\
 | |
|   else\
 | |
|      item = item->dir
 | |
| 
 | |
|   int result = E_OK;
 | |
|   ITEM *item;
 | |
|   int my_top_row, rdiff;
 | |
| 
 | |
|   T((T_CALLED("menu_driver(%p,%d)"), (void *)menu, c));
 | |
| 
 | |
|   if (!menu)
 | |
|     RETURN(E_BAD_ARGUMENT);
 | |
| 
 | |
|   if (menu->status & _IN_DRIVER)
 | |
|     RETURN(E_BAD_STATE);
 | |
|   if (!(menu->status & _POSTED))
 | |
|     RETURN(E_NOT_POSTED);
 | |
| 
 | |
|   item = menu->curitem;
 | |
| 
 | |
|   my_top_row = menu->toprow;
 | |
|   assert(item);
 | |
| 
 | |
|   if ((c > KEY_MAX) && (c <= MAX_MENU_COMMAND))
 | |
|     {
 | |
|       if (!((c == REQ_BACK_PATTERN)
 | |
| 	    || (c == REQ_NEXT_MATCH) || (c == REQ_PREV_MATCH)))
 | |
| 	{
 | |
| 	  assert(menu->pattern);
 | |
| 	  Reset_Pattern(menu);
 | |
| 	}
 | |
| 
 | |
|       switch (c)
 | |
| 	{
 | |
| 	case REQ_LEFT_ITEM:
 | |
| 	    /*=================*/
 | |
| 	  NAVIGATE(left);
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_RIGHT_ITEM:
 | |
| 	    /*==================*/
 | |
| 	  NAVIGATE(right);
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_UP_ITEM:
 | |
| 	    /*===============*/
 | |
| 	  NAVIGATE(up);
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_DOWN_ITEM:
 | |
| 	    /*=================*/
 | |
| 	  NAVIGATE(down);
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_SCR_ULINE:
 | |
| 	    /*=================*/
 | |
| 	  if (my_top_row == 0 || !(item->up))
 | |
| 	    result = E_REQUEST_DENIED;
 | |
| 	  else
 | |
| 	    {
 | |
| 	      --my_top_row;
 | |
| 	      item = item->up;
 | |
| 	    }
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_SCR_DLINE:
 | |
| 	    /*=================*/
 | |
| 	  if ((my_top_row + menu->arows >= menu->rows) || !(item->down))
 | |
| 	    {
 | |
| 	      /* only if the menu has less items than rows, we can deny the
 | |
| 	         request. Otherwise the epilogue of this routine adjusts the
 | |
| 	         top row if necessary */
 | |
| 	      result = E_REQUEST_DENIED;
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      my_top_row++;
 | |
| 	      item = item->down;
 | |
| 	    }
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_SCR_DPAGE:
 | |
| 	    /*=================*/
 | |
| 	  rdiff = menu->rows - (menu->arows + my_top_row);
 | |
| 	  if (rdiff > menu->arows)
 | |
| 	    rdiff = menu->arows;
 | |
| 	  if (rdiff <= 0)
 | |
| 	    result = E_REQUEST_DENIED;
 | |
| 	  else
 | |
| 	    {
 | |
| 	      my_top_row += rdiff;
 | |
| 	      while (rdiff-- > 0 && item != 0 && item->down != 0)
 | |
| 		item = item->down;
 | |
| 	    }
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_SCR_UPAGE:
 | |
| 	    /*=================*/
 | |
| 	  rdiff = (menu->arows < my_top_row) ? menu->arows : my_top_row;
 | |
| 	  if (rdiff <= 0)
 | |
| 	    result = E_REQUEST_DENIED;
 | |
| 	  else
 | |
| 	    {
 | |
| 	      my_top_row -= rdiff;
 | |
| 	      while (rdiff-- > 0 && item != 0 && item->up != 0)
 | |
| 		item = item->up;
 | |
| 	    }
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_FIRST_ITEM:
 | |
| 	    /*==================*/
 | |
| 	  item = menu->items[0];
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_LAST_ITEM:
 | |
| 	    /*=================*/
 | |
| 	  item = menu->items[menu->nitems - 1];
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_NEXT_ITEM:
 | |
| 	    /*=================*/
 | |
| 	  if ((item->index + 1) >= menu->nitems)
 | |
| 	    {
 | |
| 	      if (menu->opt & O_NONCYCLIC)
 | |
| 		result = E_REQUEST_DENIED;
 | |
| 	      else
 | |
| 		item = menu->items[0];
 | |
| 	    }
 | |
| 	  else
 | |
| 	    item = menu->items[item->index + 1];
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_PREV_ITEM:
 | |
| 	    /*=================*/
 | |
| 	  if (item->index <= 0)
 | |
| 	    {
 | |
| 	      if (menu->opt & O_NONCYCLIC)
 | |
| 		result = E_REQUEST_DENIED;
 | |
| 	      else
 | |
| 		item = menu->items[menu->nitems - 1];
 | |
| 	    }
 | |
| 	  else
 | |
| 	    item = menu->items[item->index - 1];
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_TOGGLE_ITEM:
 | |
| 	    /*===================*/
 | |
| 	  if (menu->opt & O_ONEVALUE)
 | |
| 	    {
 | |
| 	      result = E_REQUEST_DENIED;
 | |
| 	    }
 | |
| 	  else
 | |
| 	    {
 | |
| 	      if (menu->curitem->opt & O_SELECTABLE)
 | |
| 		{
 | |
| 		  menu->curitem->value = !menu->curitem->value;
 | |
| 		  Move_And_Post_Item(menu, menu->curitem);
 | |
| 		  _nc_Show_Menu(menu);
 | |
| 		}
 | |
| 	      else
 | |
| 		result = E_NOT_SELECTABLE;
 | |
| 	    }
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_CLEAR_PATTERN:
 | |
| 	    /*=====================*/
 | |
| 	  /* already cleared in prologue */
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_BACK_PATTERN:
 | |
| 	    /*====================*/
 | |
| 	  if (menu->pindex > 0)
 | |
| 	    {
 | |
| 	      assert(menu->pattern);
 | |
| 	      Remove_Character_From_Pattern(menu);
 | |
| 	      pos_menu_cursor(menu);
 | |
| 	    }
 | |
| 	  else
 | |
| 	    result = E_REQUEST_DENIED;
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_NEXT_MATCH:
 | |
| 	    /*==================*/
 | |
| 	  assert(menu->pattern);
 | |
| 	  if (menu->pattern[0])
 | |
| 	    result = _nc_Match_Next_Character_In_Item_Name(menu, 0, &item);
 | |
| 	  else
 | |
| 	    {
 | |
| 	      if ((item->index + 1) < menu->nitems)
 | |
| 		item = menu->items[item->index + 1];
 | |
| 	      else
 | |
| 		{
 | |
| 		  if (menu->opt & O_NONCYCLIC)
 | |
| 		    result = E_REQUEST_DENIED;
 | |
| 		  else
 | |
| 		    item = menu->items[0];
 | |
| 		}
 | |
| 	    }
 | |
| 	  break;
 | |
| 
 | |
| 	case REQ_PREV_MATCH:
 | |
| 	    /*==================*/
 | |
| 	  assert(menu->pattern);
 | |
| 	  if (menu->pattern[0])
 | |
| 	    result = _nc_Match_Next_Character_In_Item_Name(menu, BS, &item);
 | |
| 	  else
 | |
| 	    {
 | |
| 	      if (item->index)
 | |
| 		item = menu->items[item->index - 1];
 | |
| 	      else
 | |
| 		{
 | |
| 		  if (menu->opt & O_NONCYCLIC)
 | |
| 		    result = E_REQUEST_DENIED;
 | |
| 		  else
 | |
| 		    item = menu->items[menu->nitems - 1];
 | |
| 		}
 | |
| 	    }
 | |
| 	  break;
 | |
| 
 | |
| 	default:
 | |
| 	    /*======*/
 | |
| 	  result = E_UNKNOWN_COMMAND;
 | |
| 	  break;
 | |
| 	}
 | |
|     }
 | |
|   else
 | |
|     {				/* not a command */
 | |
|       if (!(c & ~((int)MAX_REGULAR_CHARACTER)) && isprint(UChar(c)))
 | |
| 	result = _nc_Match_Next_Character_In_Item_Name(menu, c, &item);
 | |
| #ifdef NCURSES_MOUSE_VERSION
 | |
|       else if (KEY_MOUSE == c)
 | |
| 	{
 | |
| 	  MEVENT event;
 | |
| 	  WINDOW *uwin = Get_Menu_UserWin(menu);
 | |
| 
 | |
| 	  getmouse(&event);
 | |
| 	  if ((event.bstate & (BUTTON1_CLICKED |
 | |
| 			       BUTTON1_DOUBLE_CLICKED |
 | |
| 			       BUTTON1_TRIPLE_CLICKED))
 | |
| 	      && wenclose(uwin, event.y, event.x))
 | |
| 	    {			/* we react only if the click was in the userwin, that means
 | |
| 				 * inside the menu display area or at the decoration window.
 | |
| 				 */
 | |
| 	      WINDOW *sub = Get_Menu_Window(menu);
 | |
| 	      int ry = event.y, rx = event.x;	/* screen coordinates */
 | |
| 
 | |
| 	      result = E_REQUEST_DENIED;
 | |
| 	      if (mouse_trafo(&ry, &rx, FALSE))
 | |
| 		{		/* rx, ry are now "curses" coordinates */
 | |
| 		  if (ry < sub->_begy)
 | |
| 		    {		/* we clicked above the display region; this is
 | |
| 				 * interpreted as "scroll up" request
 | |
| 				 */
 | |
| 		      if (event.bstate & BUTTON1_CLICKED)
 | |
| 			result = menu_driver(menu, REQ_SCR_ULINE);
 | |
| 		      else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
 | |
| 			result = menu_driver(menu, REQ_SCR_UPAGE);
 | |
| 		      else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
 | |
| 			result = menu_driver(menu, REQ_FIRST_ITEM);
 | |
| 		      RETURN(result);
 | |
| 		    }
 | |
| 		  else if (ry > sub->_begy + sub->_maxy)
 | |
| 		    {		/* we clicked below the display region; this is
 | |
| 				 * interpreted as "scroll down" request
 | |
| 				 */
 | |
| 		      if (event.bstate & BUTTON1_CLICKED)
 | |
| 			result = menu_driver(menu, REQ_SCR_DLINE);
 | |
| 		      else if (event.bstate & BUTTON1_DOUBLE_CLICKED)
 | |
| 			result = menu_driver(menu, REQ_SCR_DPAGE);
 | |
| 		      else if (event.bstate & BUTTON1_TRIPLE_CLICKED)
 | |
| 			result = menu_driver(menu, REQ_LAST_ITEM);
 | |
| 		      RETURN(result);
 | |
| 		    }
 | |
| 		  else if (wenclose(sub, event.y, event.x))
 | |
| 		    {		/* Inside the area we try to find the hit item */
 | |
| 		      int i, x, y, err;
 | |
| 
 | |
| 		      ry = event.y;
 | |
| 		      rx = event.x;
 | |
| 		      if (wmouse_trafo(sub, &ry, &rx, FALSE))
 | |
| 			{
 | |
| 			  for (i = 0; i < menu->nitems; i++)
 | |
| 			    {
 | |
| 			      err = _nc_menu_cursor_pos(menu, menu->items[i],
 | |
| 							&y, &x);
 | |
| 			      if (E_OK == err)
 | |
| 				{
 | |
| 				  if ((ry == y) &&
 | |
| 				      (rx >= x) &&
 | |
| 				      (rx < x + menu->itemlen))
 | |
| 				    {
 | |
| 				      item = menu->items[i];
 | |
| 				      result = E_OK;
 | |
| 				      break;
 | |
| 				    }
 | |
| 				}
 | |
| 			    }
 | |
| 			  if (E_OK == result)
 | |
| 			    {	/* We found an item, now we can handle the click.
 | |
| 				 * A single click just positions the menu cursor
 | |
| 				 * to the clicked item. A double click toggles
 | |
| 				 * the item.
 | |
| 				 */
 | |
| 			      if (event.bstate & BUTTON1_DOUBLE_CLICKED)
 | |
| 				{
 | |
| 				  _nc_New_TopRow_and_CurrentItem(menu,
 | |
| 								 my_top_row,
 | |
| 								 item);
 | |
| 				  menu_driver(menu, REQ_TOGGLE_ITEM);
 | |
| 				  result = E_UNKNOWN_COMMAND;
 | |
| 				}
 | |
| 			    }
 | |
| 			}
 | |
| 		    }
 | |
| 		}
 | |
| 	    }
 | |
| 	  else
 | |
| 	    result = E_REQUEST_DENIED;
 | |
| 	}
 | |
| #endif /* NCURSES_MOUSE_VERSION */
 | |
|       else
 | |
| 	result = E_UNKNOWN_COMMAND;
 | |
|     }
 | |
| 
 | |
|   if (E_OK == result)
 | |
|     {
 | |
|       /* Adjust the top row if it turns out that the current item unfortunately
 | |
|          doesn't appear in the menu window */
 | |
|       if (item->y < my_top_row)
 | |
| 	my_top_row = item->y;
 | |
|       else if (item->y >= (my_top_row + menu->arows))
 | |
| 	my_top_row = item->y - menu->arows + 1;
 | |
| 
 | |
|       _nc_New_TopRow_and_CurrentItem(menu, my_top_row, item);
 | |
| 
 | |
|     }
 | |
| 
 | |
|   RETURN(result);
 | |
| }
 | |
| 
 | |
| /* m_driver.c ends here */
 |