nuttx-apps/graphics/twm4nx/src/cmenus.cxx
Gregory Nutt abd7c9a165 This commit incorporates the NxTerm window hosting NSH. This is just code complete and just compiles with no errors. The NxTerm item does not appear in the Main Menu, however, selecting the menu item does not yet bring up the NxTerm window.
Squashed commit of the following:

    apps/graphics/twm4nx:  Revamp the event system to support notification of external applications when the window is being closed.

    apps/graphics/twm4nx:  A little NxTerm progress

    apps/graphics/twm4nx:  Clean up some logic associated with use of multiple Icon Managers.

    apps/graphics/twm4nx:  Add CNxterm to the build.  It is a long way from compiling.
2019-05-12 11:57:45 -06:00

943 lines
26 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// apps/graphics/twm4nx/src/cmenus.cxx
// twm menu code
//
// Copyright (C) 2019 Gregory Nutt. All rights reserved.
// Author: Gregory Nutt <gnutt@nuttx.org>
//
// Largely an original work but derives from TWM 1.0.10 in many ways:
//
// Copyright 1989,1998 The Open Group
// Copyright 1988 by Evans & Sutherland Computer Corporation,
//
// Please refer to apps/twm4nx/COPYING for detailed copyright information.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
// 3. Neither the name NuttX nor the names of its contributors may be
// used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
// OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// Included Files
/////////////////////////////////////////////////////////////////////////////
#include <nuttx/config.h>
#include <cstdio>
#include <cstring>
#include <cassert>
#include <cerrno>
#include <fcntl.h>
#include <nuttx/version.h>
#include <nuttx/nx/nxbe.h>
#include "graphics/nxwidgets/cnxstring.hxx"
#include "graphics/nxwidgets/cnxfont.hxx"
#include "graphics/nxwidgets/cbuttonarray.hxx"
#include "graphics/nxwidgets/cwidgeteventargs.hxx"
#include "graphics/twm4nx/twm4nx_config.hxx"
#include "graphics/twm4nx/ctwm4nx.hxx"
#include "graphics/twm4nx/cmenus.hxx"
#include "graphics/twm4nx/cresize.hxx"
#include "graphics/twm4nx/cfonts.hxx"
#include "graphics/twm4nx/ciconmgr.hxx"
#include "graphics/twm4nx/cwindow.hxx"
#include "graphics/twm4nx/cwindowfactory.hxx"
#include "graphics/twm4nx/cwindowevent.hxx"
#include "graphics/twm4nx/ctwm4nxevent.hxx"
#include "graphics/twm4nx/twm4nx_widgetevents.hxx"
#include "graphics/twm4nx/cmenus.hxx"
////////////////////////////////////////////////////////////////////////////
// Pre-processor Definitions
/////////////////////////////////////////////////////////////////////////////
// Window flags:
//
// WFLAGS_NO_MENU_BUTTON: No menu buttons on menus
// WFLAGS_NO_DELETE_BUTTON: Menus cannot be deleted in this manner.
// WFLAGS_NO_RESIZE_BUTTON: Menus cannot be resized
// WFLAGS_MENU: Menu windows are always created in the
// hidden and iconifed state. When the menu is
// selected, then it should be de-iconfied to
// be shown.
// WFLAGS_HIDDEN: Redundant
#define MENU_WINDOW_FLAGS (WFLAGS_NO_MENU_BUTTON | WFLAGS_NO_DELETE_BUTTON | \
WFLAGS_NO_RESIZE_BUTTON | WFLAGS_MENU | \
WFLAGS_HIDDEN)
////////////////////////////////////////////////////////////////////////////
// Class Implementations
/////////////////////////////////////////////////////////////////////////////
using namespace Twm4Nx;
/**
* CMenus Constructor
*/
CMenus::CMenus(CTwm4Nx *twm4nx)
{
// Save the Twm4Nx session
m_twm4nx = twm4nx; // Save the Twm4Nx session
m_eventq = (mqd_t)-1; // No widget message queue yet
// Menus
m_menuHead = (FAR struct SMenuItem *)0; // No menu items
m_menuTail = (FAR struct SMenuItem *)0; // No menu items
m_nMenuItems = 0; // No menu items yet
m_entryHeight = 0; // Menu entry height
// Windows
m_menuWindow = (FAR CWindow *)0; // The menu window
// Widgets
m_buttons = (FAR NXWidgets::CButtonArray *)0; // The menu button array
}
/**
* CMenus Destructor
*/
CMenus::~CMenus(void)
{
cleanup();
}
/**
* CMenus Initializer. Performs the parts of the CMenus construction
* that may fail. The menu window is created but is not initially
* visible. Use the show() method to make the menu visible.
*
* @param name The name of the menu
* @result True is returned on success
*/
bool CMenus::initialize(FAR NXWidgets::CNxString &name)
{
// Open a message queue to NX events.
FAR const char *mqname = m_twm4nx->getEventQueueName();
m_eventq = mq_open(mqname, O_WRONLY | O_NONBLOCK);
if (m_eventq == (mqd_t)-1)
{
twmerr("ERROR: Failed open message queue '%s': %d\n",
mqname, errno);
return false;
}
// Clone the menu name
m_menuName = name;
// Create the menu window
if (!createMenuWindow())
{
twmerr("ERROR: Failed to create menu window\n");
cleanup();
return false;
}
// Create the menu button array
if (!createMenuButtonArray())
{
twmerr("ERROR: Failed to create menu button array\n");
cleanup();
return false;
}
return true;
}
/**
* Add an item to a menu
*
* @param item Describes the menu item entry
* @return True if the menu item was added successfully
*/
bool CMenus::addMenuItem(FAR IApplication *item)
{
twminfo("Adding: subMenu=%p, event=%04x\n", subMenu, event);
// Allocate a new menu item entry
FAR struct SMenuItem *newitem = new SMenuItem;
if (newitem == (FAR struct SMenuItem *)0)
{
twmerr("ERROR: Failed to allocate menu item\n");
return false;
}
// Save information about the menu item
newitem->flink = NULL;
newitem->text = item->getName();
newitem->subMenu = item->getSubMenu();
newitem->start = item->getStartFunction();
newitem->handler = item->getEventHandler();
newitem->event = item->getEvent();
// Increment the total number of menu items
m_nMenuItems++;
// Add the menu item to the tail of the item list
if (m_menuHead == NULL)
{
m_menuHead = newitem;
newitem->blink = (FAR struct SMenuItem *)0;
}
else
{
m_menuTail->flink = newitem;
newitem->blink = m_menuTail;
}
m_menuTail = newitem;
newitem->flink = (FAR struct SMenuItem *)0;
// Update the menu window size
setMenuWindowSize();
m_menuWindow->synchronize();
// Get the updated window size
struct nxgl_size_s menuSize;
m_menuWindow->getWindowSize(&menuSize);
// Resize the button array
nxgl_coord_t buttonHeight = menuSize.h / m_nMenuItems;
if (!m_buttons->resizeArray(1, m_nMenuItems, menuSize.w, buttonHeight))
{
twmerr("ERROR: CButtonArray::resizeArray failed\n");
return false;
}
// We have to update all button labels after resizing
FAR struct SMenuItem *tmpitem;
int index;
for (index = 0, tmpitem = m_menuHead;
tmpitem != (FAR struct SMenuItem *)0;
index++, tmpitem = tmpitem->flink)
{
m_buttons->setText(0, index, tmpitem->text);
}
return true;
}
/**
* Handle MENU events.
*
* @param eventmsg. The received NxWidget MENU event message.
* @return True if the message was properly handled. false is
* return on any failure.
*/
bool CMenus::event(FAR struct SEventMsg *eventmsg)
{
bool success = true;
switch (eventmsg->eventID)
{
case EVENT_MENU_XYINPUT: // Poll for button array events
{
// This event message is sent from CWindowEvent whenever mouse,
// touchscreen, or keyboard entry events are received in the
// menu application window that contains the button array.
NXWidgets::CWidgetControl *control =
m_menuWindow->getWidgetControl();
// Poll for button array events.
//
// pollEvents() returns true if any interesting event in the
// button array. handleActionEvent() will be called in that
// case. false is not a failure.
(void)control->pollEvents();
}
break;
case EVENT_MENU_IDENTIFY: // Describe the window
{
identify((FAR CWindow *)eventmsg->obj);
}
break;
case EVENT_MENU_VERSION: // Show the Twm4Nx version
identify((FAR CWindow *) NULL);
break;
case EVENT_MENU_DEICONIFY: // Window icon pressed
case EVENT_MENU_ICONIFY: // Tool bar minimize button pressed
{
FAR CWindow *cwin = (FAR CWindow *)eventmsg->obj;
if (cwin->isIconified())
{
cwin->deIconify();
}
else if (eventmsg->eventID == EVENT_MENU_ICONIFY)
{
cwin->iconify();
}
}
break;
case EVENT_MENU_FUNCTION: // Perform function on unknown menu
{
FAR struct SMenuItem *item;
for (item = m_menuHead; item != NULL; item = item->flink)
{
// Send another event message to the session manager
struct SEventMsg newmsg;
newmsg.eventID = item->event;
newmsg.obj = eventmsg->obj;
newmsg.pos.x = eventmsg->pos.x;
newmsg.pos.y = eventmsg->pos.y;
newmsg.context = eventmsg->context;
newmsg.handler = (FAR void *)item->handler;
// NOTE that we cannot block because we are on the same thread
// as the message reader. If the event queue becomes full then
// we have no other option but to lose events.
//
// I suppose we could recurse and call Twm4Nx::dispatchEvent at
// the risk of runaway stack usage.
int ret = mq_send(m_eventq, (FAR const char *)&newmsg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
twmerr("ERROR: mq_send failed: %d\n", ret);
success = false;
}
}
}
break;
case EVENT_MENU_SUBMENU: // Sub-menu selected
{
// Bring up the sub-menu
FAR CMenus *cmenu = (FAR CMenus *)eventmsg->obj;
success = cmenu->show();
}
break;
default:
success = false;
break;
}
return success;
}
void CMenus::identify(FAR CWindow *cwin)
{
int n = 0;
#if CONFIG_VERSION_MAJOR != 0 || CONFIG_VERSION_MINOR != 0
std::snprintf(m_info[n], INFO_SIZE, "Twm4Nx: NuttX-" CONFIG_VERSION_STRING);
#else
std::snprintf(m_info[n], INFO_SIZE, "Twm4Nx:");
#endif
m_info[n++][0] = '\0';
if (cwin != (FAR CWindow *)0)
{
// Get the size of the window
struct nxgl_size_s windowSize;
if (!cwin->getFrameSize(&windowSize))
{
return;
}
struct nxgl_point_s windowPos;
if (!cwin->getFramePosition(&windowPos))
{
return;
}
std::snprintf(m_info[n++], INFO_SIZE, "Name = \"%s\"",
cwin->getWindowName());
m_info[n++][0] = '\0';
std::snprintf(m_info[n++], INFO_SIZE, "Geometry/root = %dx%d+%d+%d",
windowSize.w, windowSize.h, windowPos.x, windowPos.y);
}
m_info[n++][0] = '\0';
std::snprintf(m_info[n++], INFO_SIZE, "Click to dismiss....");
// Figure out the width and height of the info window
FAR CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *defaultFont = fonts->getDefaultFont();
struct nxgl_size_s menuSize;
menuSize.h = n * (defaultFont->getHeight() + 2);
menuSize.w = 1;
for (int i = 0; i < n; i++)
{
int twidth = defaultFont->getStringWidth(m_info[i]);
if (twidth > menuSize.w)
{
menuSize.w = twidth;
}
}
menuSize.w += 10; // some padding
// Make sure that the window is on the display
struct nxgl_point_s menuPos;
if (m_menuWindow->getWindowPosition(&menuPos))
{
menuPos.x -= (menuSize.w / 2);
menuPos.y -= (menuSize.h / 3);
struct nxgl_size_s displaySize;
m_twm4nx->getDisplaySize(&displaySize);
struct nxgl_size_s frameSize;
menuToFrameSize(&menuSize, &frameSize);
if (menuPos.x + frameSize.w >= displaySize.w)
{
menuPos.x = displaySize.w - frameSize.w;
}
if (menuPos.y + frameSize.h >= displaySize.h)
{
menuPos.y = displaySize.h - frameSize.h;
}
if (menuPos.x < 0)
{
menuPos.x = 0;
}
if (menuPos.y < 0)
{
menuPos.y = 0;
}
frameToMenuSize(&frameSize, &menuSize);
}
else
{
menuPos.x = 0;
menuPos.y = 0;
}
// Set the new window size and position
if (!m_menuWindow->setWindowPosition(&menuPos) ||
!m_menuWindow->setWindowSize(&menuSize))
{
return;
}
// Raise it to the top of the hiearchy
m_menuWindow->raiseWindow();
}
/**
* Convert the position of a menu window to the position of
* the containing frame.
*/
void CMenus::menuToFramePos(FAR const struct nxgl_point_s *menupos,
FAR struct nxgl_point_s *framepos)
{
nxgl_coord_t tbheight = m_menuWindow->getToolbarHeight();
framepos->x = menupos->x - CONFIG_NXTK_BORDERWIDTH;
framepos->y = menupos->y - tbheight - CONFIG_NXTK_BORDERWIDTH;
}
/**
* Convert the position of the containing frame to the position of
* the menu window.
*/
void CMenus::frameToMenuPos(FAR const struct nxgl_point_s *framepos,
FAR struct nxgl_point_s *menupos)
{
nxgl_coord_t tbheight = m_menuWindow->getToolbarHeight();
menupos->x = framepos->x + CONFIG_NXTK_BORDERWIDTH;
menupos->y = framepos->y + tbheight + CONFIG_NXTK_BORDERWIDTH;
}
/**
* Convert the size of a menu window to the size of the containing
* frame.
*/
void CMenus::menuToFrameSize(FAR const struct nxgl_size_s *menusize,
FAR struct nxgl_size_s *framesize)
{
nxgl_coord_t tbheight = m_menuWindow->getToolbarHeight();
framesize->w = menusize->w + 2 * CONFIG_NXTK_BORDERWIDTH;
framesize->h = menusize->h + tbheight + 2 * CONFIG_NXTK_BORDERWIDTH;
}
/**
* Convert the size of a containing frame to the size of the menu
* window.
*/
void CMenus::frameToMenuSize(FAR const struct nxgl_size_s *framesize,
FAR struct nxgl_size_s *menusize)
{
nxgl_coord_t tbheight = m_menuWindow->getToolbarHeight();
menusize->w = framesize->w - 2 * CONFIG_NXTK_BORDERWIDTH;
menusize->h = framesize->h - tbheight - 2 * CONFIG_NXTK_BORDERWIDTH;
}
/**
* Create the menu window. Menu windows are always created in the hidden
* state. When the menu is selected, then it should be shown.
*
* @result True is returned on success
*/
bool CMenus::createMenuWindow(void)
{
// Create the menu window
CWindowFactory *factory = m_twm4nx->getWindowFactory();
m_menuWindow =
factory->createWindow(m_menuName,
(FAR const struct NXWidgets::SRlePaletteBitmap *)0,
(FAR CIconMgr *)0, MENU_WINDOW_FLAGS);
if (m_menuWindow == (FAR CWindow *)0)
{
twmerr("ERROR: Failed to create icon manager window");
return false;
}
// Configure mouse events needed by the button array.
struct SAppEvents events;
events.eventObj = (FAR void *)this;
events.redrawEvent = EVENT_SYSTEM_NOP;
events.mouseEvent = EVENT_MENU_XYINPUT;
events.kbdEvent = EVENT_SYSTEM_NOP;
events.closeEvent = EVENT_SYSTEM_NOP;
bool success = m_menuWindow->configureEvents(events);
if (!success)
{
delete m_menuWindow;
m_menuWindow = (FAR CWindow *)0;
return false;
}
// Adjust the size of the window
struct nxgl_size_s windowSize;
getMenuWindowSize(windowSize);
if (!m_menuWindow->setWindowSize(&windowSize))
{
twmerr("ERROR: Failed to set window size\n");
delete m_menuWindow;
m_menuWindow = (FAR CWindow *)0;
return false;
}
return true;
}
/**
* Calculate the optimal menu frame size
*
* @param frameSize The location to return the calculated frame size
*/
void CMenus::getMenuFrameSize(FAR struct nxgl_size_s &frameSize)
{
CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *menuFont = fonts->getMenuFont();
m_entryHeight = menuFont->getHeight() + CONFIG_TWM4NX_MENU_VSPACING;
// Get the minimum width of the toolbar
nxgl_coord_t maxWidth = minimumToolbarWidth(m_twm4nx, m_menuName,
MENU_WINDOW_FLAGS);
// Compare that to the length of the longest item string in in the menu
for (FAR struct SMenuItem *curr = m_menuHead;
curr != NULL;
curr = curr->flink)
{
nxgl_coord_t stringlen = menuFont->getStringWidth(curr->text);
if (stringlen > maxWidth)
{
maxWidth = stringlen;
}
}
// Lets first size the window accordingly
struct nxgl_size_s menuSize;
menuSize.w = maxWidth + CONFIG_TWM4NX_MENU_HSPACING;
unsigned int nMenuItems = m_nMenuItems > 0 ? m_nMenuItems : 1;
menuSize.h = nMenuItems * m_entryHeight;
// Clip to the size of the display
struct nxgl_size_s displaySize;
m_twm4nx->getDisplaySize(&displaySize);
menuToFrameSize(&menuSize, &frameSize);
if (frameSize.w > displaySize.w)
{
frameSize.w = displaySize.w;
}
if (frameSize.h > displaySize.h)
{
frameSize.h = displaySize.h;
}
}
/**
* Calculate the optimal menu window size
*
* @param frameSize The location to return the calculated window size
*/
void CMenus::getMenuWindowSize(FAR struct nxgl_size_s &size)
{
struct nxgl_size_s frameSize;
getMenuFrameSize(frameSize);
frameToMenuSize(&frameSize, &size);
}
/**
* Update the menu window size
*
* @result True is returned on success
*/
bool CMenus::setMenuWindowSize(void)
{
// Get the optimal menu window size
struct nxgl_size_s frameSize;
getMenuFrameSize(frameSize);
if (!m_menuWindow->resizeFrame(&frameSize, (FAR const struct nxgl_point_s *)0))
{
twmerr("ERROR: Failed to set window size\n");
return false;
}
return true;
}
/**
* Set the position of the menu window. Supports positioning of a
* pop-up window.
*
* @param framePos The position of the menu window frame
* @result True is returned on success
*/
bool CMenus::setMenuWindowPosition(FAR struct nxgl_point_s *framePos)
{
struct nxgl_point_s menuPos;
frameToMenuPos(framePos, &menuPos);
return m_menuWindow->setWindowPosition(&menuPos);
}
/**
* Create the menu button array
*
* @result True is returned on success
*/
bool CMenus::createMenuButtonArray(void)
{
// Get the width of the window
struct nxgl_size_s windowSize;
if (!m_menuWindow->getWindowSize(&windowSize))
{
twmerr("ERROR: Failed to get window size\n");
return false;
}
// Create the button array
uint8_t nrows = m_nMenuItems > 0 ? m_nMenuItems : 1;
nxgl_coord_t buttonWidth = windowSize.w;
nxgl_coord_t buttonHeight = windowSize.h / nrows;
// Get the Widget control instance from the Icon Manager window. This
// will force all widget drawing to go to the Icon Manager window.
FAR NXWidgets:: CWidgetControl *control = m_menuWindow->getWidgetControl();
if (control == (FAR NXWidgets:: CWidgetControl *)0)
{
// Should not fail
return false;
}
// Now we have enough information to create the button array
// The button must be positioned at the upper left of the window
m_buttons = new NXWidgets::CButtonArray(control, 0, 0, 1, nrows,
buttonWidth, buttonHeight);
if (m_buttons == (FAR NXWidgets::CButtonArray *)0)
{
twmerr("ERROR: Failed to create the button array\n");
return false;
}
// Configure the button array widget
FAR CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *iconManagerFont = fonts->getIconManagerFont();
m_buttons->setFont(iconManagerFont);
m_buttons->setBorderless(true);
m_buttons->setRaisesEvents(true);
// Enable and draw the button array
m_buttons->enable();
m_buttons->enableDrawing();
m_buttons->redraw();
// Register to get events from the mouse clicks on the image
m_buttons->addWidgetEventHandler(this);
return true;
}
/**
* Handle a widget action event, overriding the CWidgetEventHandler
* method. This will indicate a button pre-release event.
*
* @param e The event data.
*/
void CMenus::handleActionEvent(const NXWidgets::CWidgetEventArgs &e)
{
// A button should now be clicked
int column;
int row;
if (m_buttons->isButtonClicked(column, row) && column == 0)
{
// The row number is sufficent to locate the menu entry info
// But we have to search through the menu items to find the
// at this row.
FAR struct SMenuItem *item;
int index;
for (item = m_menuHead, index = 0;
item != (FAR struct SMenuItem *)0;
item = item->flink, index++)
{
// When the index matches the row number, then we have
// the entry.
// REVISIT: Are there any race conditions we need to
// concerned with here? Such as menuitems being removed
// while the menu is up?
if (row == index)
{
// Send an event to the Twm4Nx event handler
struct SEventMsg msg;
// Precedence:
// 1. Event with recipient == EVENT_RECIPIENT_APP.
// getEventHandler() must return a non-NULL instance in this
// case.
// 2. Sub-menu
// 3. Task start-up
// 4. Event with other recipients
if ((item->event & EVENT_RECIPIENT_MASK) != EVENT_RECIPIENT_APP)
{
// If there is a subMenu, then bring the sub-menu up
// now.
if (item->subMenu != (FAR CMenus *)0)
{
msg.eventID = EVENT_MENU_SUBMENU;
msg.obj = (FAR void *)item->subMenu;
msg.handler = (FAR void *)0;
}
// If there is a start-up function, then execute the
// start-up function
else if (item->start != (TStartFunction)0)
{
msg.eventID = EVENT_MENU_SUBMENU;
msg.obj = (FAR void *)this;
msg.handler = (FAR void *)item->start;
}
// Otherwise, this is an internal message with no handler
else
{
msg.eventID = item->event;
msg.obj = (FAR void *)this;
msg.handler = (FAR void *)0;
}
}
// Otherwise, send the event specified for the menu item. The
// handler is only used if the recipient of the event is
// EVENT_RECIPIENT_APP
else
{
msg.eventID = item->event;
msg.obj = (FAR void *)this;
msg.handler = (FAR void *)item->handler;
}
// Fill in the remaining, common stuff
msg.pos.x = e.getX();
msg.pos.y = e.getY();
msg.context = EVENT_CONTEXT_MENU;
// NOTE that we cannot block because we are on the same thread
// as the message reader. If the event queue becomes full then
// we have no other option but to lose events.
//
// I suppose we could recurse and call Twm4Nx::dispatchEvent at
// the risk of runaway stack usage.
int ret = mq_send(m_eventq, (FAR const char *)&msg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
twmerr("ERROR: mq_send failed: %d\n", ret);
}
return;
}
}
twmwarn("WARNING: No matching menu at index %d\n", row);
}
}
/**
* Cleanup or initialization error or on deconstruction.
*/
void CMenus::cleanup(void)
{
// Close the NxWidget event message queue
if (m_eventq != (mqd_t)-1)
{
(void)mq_close(m_eventq);
m_eventq = (mqd_t)-1;
}
// Free the menu window
if (m_menuWindow != (FAR CWindow *)0)
{
delete m_menuWindow;
m_menuWindow = (FAR CWindow *)0;
}
// Free each menu item
FAR struct SMenuItem *curr;
FAR struct SMenuItem *next;
for (curr = m_menuHead; curr != (FAR struct SMenuItem *)0; curr = next)
{
next = curr->flink;
// Free any subMenu
if (curr->subMenu != (FAR CMenus *)0)
{
delete curr->subMenu;
}
// Free the menu item
delete curr;
}
m_menuHead = (FAR struct SMenuItem *)0;
m_menuTail = (FAR struct SMenuItem *)0;
// Free the button array
if (m_buttons != (FAR NXWidgets::CButtonArray *)0)
{
delete m_buttons;
m_buttons = (FAR NXWidgets::CButtonArray *)0;
}
}