]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - menu/m_driver.c
ncurses 5.6 - patch 20070407
[ncurses.git] / menu / m_driver.c
index 5e86843cc262523ab9c8ff601b56d2f5dc82644a..d29c6024a7e3a0c235a2ed0973b4b5a15ab6762f 100644 (file)
@@ -1,33 +1,43 @@
-/*-----------------------------------------------------------------------------+
-|           The ncurses menu library is  Copyright (C) 1995-1997               |
-|             by Juergen Pfeifer <Juergen.Pfeifer@T-Online.de>                 |
-|                          All Rights Reserved.                                |
-|                                                                              |
-| Permission to use, copy, modify, and distribute this software and its        |
-| documentation for any purpose and without fee is hereby granted, provided    |
-| that the above copyright notice appear in all copies and that both that      |
-| copyright notice and this permission notice appear in supporting             |
-| documentation, and that the name of the above listed copyright holder(s) not |
-| be used in advertising or publicity pertaining to distribution of the        |
-| software without specific, written prior permission.                         | 
-|                                                                              |
-| THE ABOVE LISTED COPYRIGHT HOLDER(S) DISCLAIM ALL WARRANTIES WITH REGARD TO  |
-| THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-  |
-| NESS, IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR   |
-| ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RE- |
-| SULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, |
-| NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH    |
-| THE USE OR PERFORMANCE OF THIS SOFTWARE.                                     |
-+-----------------------------------------------------------------------------*/
+/****************************************************************************
+ * Copyright (c) 1998-2004,2005 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 menu_driver and menu_pattern                                      *
-* Central dispatching routine and pattern matching handling                *
+* Module m_driver                                                          *
+* Central dispatching routine                                              *
 ***************************************************************************/
 
 #include "menu.priv.h"
 
-MODULE_ID("$Id: m_driver.c,v 1.8 1997/05/01 16:47:26 juergen Exp $")
+MODULE_ID("$Id: m_driver.c,v 1.25 2005/11/26 20:46:59 tom Exp $")
 
 /* Macros */
 
@@ -41,48 +51,51 @@ MODULE_ID("$Id: m_driver.c,v 1.8 1997/05/01 16:47:26 juergen Exp $")
     (menu)->pattern[(menu)->pindex] = '\0'; }
 
 /*---------------------------------------------------------------------------
-|   Facility      :  libnmenu  
-|   Function      :  static bool Is_Sub_String( 
+|   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
-                        )
+static bool
+Is_Sub_String(
+              bool IgnoreCaseFlag,
+              const char *part,
+              const char *string
+)
 {
-  assert( part && string );
-  if ( IgnoreCaseFlag )
+  assert(part && string);
+  if (IgnoreCaseFlag)
     {
-      while(*string && *part)
+      while (*string && *part)
        {
-         if (toupper(*string++)!=toupper(*part)) break;
+         if (toupper(*string++) != toupper(*part))
+           break;
          part++;
        }
     }
   else
     {
-      while( *string && *part )
-       if (*part != *string++) break;
+      while (*string && *part)
+       if (*part != *string++)
+         break;
       part++;
     }
-  return ( (*part) ? FALSE : TRUE );
+  return ((*part) ? FALSE : TRUE);
 }
 
 /*---------------------------------------------------------------------------
-|   Facility      :  libnmenu  
-|   Function      :  static int Match_Next_Character_In_Item_Name(
+|   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
@@ -97,164 +110,95 @@ static bool Is_Sub_String(
 |                       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
 +--------------------------------------------------------------------------*/
-static int Match_Next_Character_In_Item_Name(MENU *menu, int ch, ITEM **item)
+NCURSES_EXPORT(int)
+_nc_Match_Next_Character_In_Item_Name
+(MENU * menu, int ch, ITEM ** item)
 {
   bool found = FALSE, passed = FALSE;
-  int  idx, last;
-  
-  assert( menu && item && *item);
+  int idx, last;
+
+  T((T_CALLED("_nc_Match_Next_Character(%p,%d,%p)"), menu, ch, item));
+
+  assert(menu && item && *item);
   idx = (*item)->index;
-  
-  if (ch && ch!=BS)
+
+  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) 
+         a match ! */
+      if ((menu->pindex + 1) > menu->namelen)
        RETURN(E_NO_MATCH);
-      
-      Add_Character_To_Pattern(menu,ch);
+
+      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;
+         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((menu->opt & O_IGNORECASE) != 0,
-                     menu->pattern,
-                     menu->items[idx]->name.str)
+
+  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));
-  
+       found = TRUE;
+      else
+       passed = TRUE;
+    }
+  while (!found && (idx != last));
+
   if (found)
     {
-      if (!((idx==(*item)->index) && passed))
+      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 );
+         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 (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      :  char *menu_pattern(const MENU *menu)
-|   
-|   Description   :  Return the value of the pattern buffer.
-|
-|   Return Values :  NULL          - if there is no pattern buffer allocated
-|                    EmptyString   - if there is a pattern buffer but no
-|                                    pattern is stored
-|                    PatternString - as expected
-+--------------------------------------------------------------------------*/
-char *menu_pattern(const MENU * menu)
-{
-  return (menu ? (menu->pattern ? menu->pattern : "") : (char *)0);
-}
-
-/*---------------------------------------------------------------------------
-|   Facility      :  libnmenu  
-|   Function      :  int set_menu_pattern(MENU *menu, const char *p)
-|   
-|   Description   :  Set the match pattern for a menu and position to the
-|                    first item that matches.
-|
-|   Return Values :  E_OK              - success
-|                    E_BAD_ARGUMENT    - invalid menu or pattern pointer
-|                    E_NOT_CONNECTED   - no items connected to menu
-|                    E_BAD_STATE       - menu in user hook routine
-|                    E_NO_MATCH        - no item matches pattern
-+--------------------------------------------------------------------------*/
-int set_menu_pattern(MENU *menu, const char *p)
-{
-  ITEM *matchitem;
-  int   matchpos;
-  
-  if (!menu || !p)     
-    RETURN(E_BAD_ARGUMENT);
-  
-  if (!(menu->items))
-    RETURN(E_NOT_CONNECTED);
-  
-  if ( menu->status & _IN_DRIVER )
-    RETURN(E_BAD_STATE);
-  
-  Reset_Pattern(menu);
-  
-  if (!(*p))
-    {
-      pos_menu_cursor(menu);
-      RETURN(E_OK);
     }
-  
-  if (menu->status & _LINK_NEEDED) 
-    _nc_Link_Items(menu);
-  
-  matchpos  = menu->toprow;
-  matchitem = menu->curitem;
-  assert(matchitem);
-  
-  while(*p)
-    {
-      if ( !isprint(*p) || 
-         (Match_Next_Character_In_Item_Name(menu,*p,&matchitem) != E_OK) )
-       {
-         Reset_Pattern(menu);
-         pos_menu_cursor(menu);
-         RETURN(E_NO_MATCH);
-       }
-      p++;
-    }                  
-  
-  /* This is reached if there was a match. So we position to the new item */
-  Adjust_Current_Item(menu,matchpos,matchitem);
-  RETURN(E_OK);
+  RETURN(E_NO_MATCH);
 }
 
 /*---------------------------------------------------------------------------
-|   Facility      :  libnmenu  
+|   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.
 |
@@ -263,7 +207,8 @@ int set_menu_pattern(MENU *menu, const char *p)
 |                    E_BAD_STATE     - menu is in user hook routine
 |                    E_NOT_POSTED    - menu is not posted
 +--------------------------------------------------------------------------*/
-int menu_driver(MENU * menu, int   c)
+NCURSES_EXPORT(int)
+menu_driver(MENU * menu, int c)
 {
 #define NAVIGATE(dir) \
   if (!item->dir)\
@@ -274,118 +219,121 @@ int menu_driver(MENU * menu, int   c)
   int result = E_OK;
   ITEM *item;
   int my_top_row, rdiff;
-  
+
+  T((T_CALLED("menu_driver(%p,%d)"), menu, c));
+
   if (!menu)
     RETURN(E_BAD_ARGUMENT);
-  
-  if ( menu->status & _IN_DRIVER )
+
+  if (menu->status & _IN_DRIVER)
     RETURN(E_BAD_STATE);
-  if ( !( menu->status & _POSTED ) )
+  if (!(menu->status & _POSTED))
     RETURN(E_NOT_POSTED);
-  
+
+  item = menu->curitem;
+
   my_top_row = menu->toprow;
-  item    = menu->curitem;
   assert(item);
-  
-  if ((c > KEY_MAX) && (c<=MAX_MENU_COMMAND))
-    {  
-      if (!((c==REQ_BACK_PATTERN)
-           || (c==REQ_NEXT_MATCH) || (c==REQ_PREV_MATCH)))
+
+  if ((c > KEY_MAX) && (c <= MAX_MENU_COMMAND))
+    {
+      if (!((c == REQ_BACK_PATTERN)
+           || (c == REQ_NEXT_MATCH) || (c == REQ_PREV_MATCH)))
        {
-         assert( menu->pattern );
+         assert(menu->pattern);
          Reset_Pattern(menu);
        }
-      
-      switch(c)
+
+      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)
+           /*=================*/
+         if (my_top_row == 0 || !(item->up))
            result = E_REQUEST_DENIED;
          else
            {
              --my_top_row;
              item = item->up;
-           }  
+           }
          break;
-         
+
        case REQ_SCR_DLINE:
-         /*=================*/  
-         my_top_row++;
-         if ((menu->rows - menu->arows)>0)
+           /*=================*/
+         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 */
-             my_top_row--;
+                request. Otherwise the epilogue of this routine adjusts the
+                top row if necessary */
              result = E_REQUEST_DENIED;
            }
          else
-           item = item->down;
+           {
+             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->rows - (menu->arows + my_top_row);
+         if (rdiff > menu->arows)
            rdiff = menu->arows;
-         if (rdiff==0)
+         if (rdiff <= 0)
            result = E_REQUEST_DENIED;
          else
            {
              my_top_row += rdiff;
-             while(rdiff-- > 0)
+             while (rdiff-- > 0 && item != (ITEM *) 0)
                item = item->down;
            }
          break;
-         
+
        case REQ_SCR_UPAGE:
-         /*=================*/  
-         rdiff = (menu->arows < my_top_row) ?
-           menu->arows : my_top_row;
-         if (rdiff==0)
+           /*=================*/
+         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--)
+             while (rdiff-- && item != (ITEM *) 0)
                item = item->up;
            }
          break;
-         
+
        case REQ_FIRST_ITEM:
-         /*==================*/  
+           /*==================*/
          item = menu->items[0];
          break;
-         
+
        case REQ_LAST_ITEM:
-         /*=================*/  
-         item = menu->items[menu->nitems-1];
+           /*=================*/
+         item = menu->items[menu->nitems - 1];
          break;
 
        case REQ_NEXT_ITEM:
-         /*=================*/  
-         if ((item->index+1)>=menu->nitems)
+           /*=================*/
+         if ((item->index + 1) >= menu->nitems)
            {
              if (menu->opt & O_NONCYCLIC)
                result = E_REQUEST_DENIED;
@@ -395,22 +343,22 @@ int menu_driver(MENU * menu, int   c)
          else
            item = menu->items[item->index + 1];
          break;
-         
+
        case REQ_PREV_ITEM:
-         /*=================*/  
-         if (item->index<=0)
+           /*=================*/
+         if (item->index <= 0)
            {
              if (menu->opt & O_NONCYCLIC)
                result = E_REQUEST_DENIED;
              else
-               item = menu->items[menu->nitems-1];
+               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;
@@ -420,40 +368,40 @@ int menu_driver(MENU * menu, int   c)
              if (menu->curitem->opt & O_SELECTABLE)
                {
                  menu->curitem->value = !menu->curitem->value;
-                 Move_And_Post_Item(menu,menu->curitem);
+                 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)
+           /*====================*/
+         if (menu->pindex > 0)
            {
              assert(menu->pattern);
              Remove_Character_From_Pattern(menu);
-             pos_menu_cursor( menu );
+             pos_menu_cursor(menu);
            }
          else
            result = E_REQUEST_DENIED;
          break;
-         
+
        case REQ_NEXT_MATCH:
-         /*==================*/  
+           /*==================*/
          assert(menu->pattern);
          if (menu->pattern[0])
-           result = Match_Next_Character_In_Item_Name(menu,0,&item);
+           result = _nc_Match_Next_Character_In_Item_Name(menu, 0, &item);
          else
            {
-             if ((item->index+1)<menu->nitems)
-               item=menu->items[item->index+1];
+             if ((item->index + 1) < menu->nitems)
+               item = menu->items[item->index + 1];
              else
                {
                  if (menu->opt & O_NONCYCLIC)
@@ -462,50 +410,145 @@ int menu_driver(MENU * menu, int   c)
                    item = menu->items[0];
                }
            }
-         break;        
-         
+         break;
+
        case REQ_PREV_MATCH:
-         /*==================*/  
+           /*==================*/
          assert(menu->pattern);
          if (menu->pattern[0])
-           result = Match_Next_Character_In_Item_Name(menu,BS,&item);
+           result = _nc_Match_Next_Character_In_Item_Name(menu, BS, &item);
          else
            {
              if (item->index)
-               item = menu->items[item->index-1];
+               item = menu->items[item->index - 1];
              else
                {
                  if (menu->opt & O_NONCYCLIC)
                    result = E_REQUEST_DENIED;
                  else
-                   item = menu->items[menu->nitems-1];
+                   item = menu->items[menu->nitems - 1];
                }
            }
          break;
-         
+
        default:
-         /*======*/  
+           /*======*/
          result = E_UNKNOWN_COMMAND;
          break;
        }
     }
   else
     {                          /* not a command */
-      if ( !(c & ~((int)MAX_REGULAR_CHARACTER)) && isprint(c) )
-       result = Match_Next_Character_In_Item_Name( menu, c, &item );
+      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;
     }
-  
-  /* 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 );
-  
+
+  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);
 }