882 lines
21 KiB
C++
Raw Normal View History

wm4Nx is a port of twm, Tab Window Manager (or Tom's Window Manager) version 1.0.10 to NuttX NX windows server. No, a port is not the right word. It is a re-design of TWM from the inside out to work with the NuttX NX server. The name Twm4Nx reflects this legacy. But Twm4Nx is more a homage to TWM than a port of TWM. The original TWM was based on X11 which provides a rich set of features. TWM provided titlebars, shaped windows, several forms of icon management, user-defined macro functions, click-to-type and pointer-driven keyboard focus, graphic contexts, and user-specified key and pointer button bindings, etc. Twm4Nx, on the other hand is based on the NuttX NX server which provides comparatively minimal support. Additional drawing support comes from the NuttX NxWidgets library (which necessitated the change to C++). Twm4Nx is greatly stripped down and targeted on small embedded systems with minimal resources. For example, no assumption is made about the availability of a file system; no .twmrc file is used. Bitmaps are not used (other than for fonts). The TWM license is, I believe compatible with the BSD license used by NuttX. The origin TWM license required notice of copyrights within each file and a full copy of the original license which you can find in the COPYING file. within this directory. STATUS: This port was brutal. Much TWM logic was removed because it depending on X11 features (or just because I could not understand how to use it). The logic is partial. A lot more needs to be done to have a complete system (hence, it is marked EXPERIMENTAL). The kinds of things that need to done are: 1. Update some logic that is only fragmentary for how like resizing, and menus. 2. Integrate NxWidgets into the windows: The resize menu needs a CLabel, the menus are CListBox'es, but not completely integrated, the Icon Manager needs to be a button array. 3. Resit Icons. They are windows now, but need to be compound widgets lying on the background. 4. Widget events are only partially integrated. A lot more needs to be done. A partial change to thoe event system that hints at the redesign is in place but it is far from complete.
2019-04-25 16:54:17 -06:00
/////////////////////////////////////////////////////////////////////////////
// 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 <debug.h>
#include <nuttx/version.h>
#include "graphics/nxwidgets/cnxfont.hxx"
#include "graphics/nxwidgets/clistbox.hxx"
#include "graphics/twm4nx/ctwm4nx.hxx"
#include "graphics/twm4nx/cmenus.hxx"
#include "graphics/twm4nx/cresize.hxx"
#include "graphics/twm4nx/cfonts.hxx"
#include "graphics/twm4nx/cicon.hxx"
#include "graphics/twm4nx/ciconmgr.hxx"
#include "graphics/twm4nx/cwindow.hxx"
#include "graphics/twm4nx/cwindowfactory.hxx"
#include "graphics/twm4nx/cwindowevent.hxx"
#include "graphics/twm4nx/twm4nx_widgetevents.hxx"
#include "graphics/twm4nx/cmenus.hxx"
////////////////////////////////////////////////////////////////////////////
// Class Implementations
/////////////////////////////////////////////////////////////////////////////
using namespace Twm4Nx;
/**
* CMenus Constructor
*/
CMenus::CMenus(CTwm4Nx *twm4nx)
{
// Save the Twm4Nx session
m_twm4nx = twm4nx; // Save the Twm4Nx session
// Menus
m_popUpMenu = (FAR CMenus *)0; // No pop-up menu
m_activeItem = (FAR struct SMenuItem *)0; // No active menu item
m_nMenuItems = 0; // No menu items yet
m_menuDepth = 0; // No menus up
m_entryHeight = 0; // Menu entry height
m_menuPull = false; // No pull right entry
// Windows
m_menuWindow = (FAR NXWidgets::CNxTkWindow *)0; // The menu window
// Widgets
m_menuListBox = (FAR NXWidgets::CListBox *)0; //The menu list box
// Functions
m_funcKeyHead = (FAR struct SFuncKey *)0;
}
/**
* CMenus Destructor
*/
CMenus::~CMenus(void)
{
cleanup();
}
/**
* CMenus Initializer. Performs the parts of the CMenus construction
* that may fail.
*
* @result True is returned on success
*/
bool CMenus::initialize(FAR const char *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)
{
gerr("ERROR: Failed open message queue '%s': %d\n",
mqname, errno);
}
// Save the menu name
m_menuName = strdup(name);
if (m_menuName == (FAR char *)0)
{
return false;
}
// Create the menu window
if (!createMenuWindow())
{
gerr("ERROR: Failed to create menu window\n");
cleanup();
return false;
}
// Create the menu list box
if (!createMenuListBox())
{
gerr("ERROR: Failed to create menu list box\n");
cleanup();
return false;
}
return true;
}
/**
* Add an item to a menu
*
* \param text The text to appear in the menu
* \param action The string to possibly execute
* \param subMenu The menu if it is a pull-right entry
* \param func The numeric function
*/
// REVISIT: Only used internally. Was used in .twmrc parsing.
bool CMenus::addMenuItem(FAR const char *text,
FAR const char *action, FAR CMenus *subMenu,
int func)
{
ginfo("Adding menu text=\"%s\", action=%s, subMenu=%d, f=%d\n",
text, action, subMenu, func);
// Allocate a new menu item entry
FAR struct SMenuItem *item = new SMenuItem;
if (item == (FAR struct SMenuItem *)0)
{
gerr("ERROR: Failed to allocate menu item\n");
return false;
}
// Clone the item name so that we have control over its lifespan
item->text = std::strdup(text);
if (item->text == (FAR char *)0)
{
gerr("ERROR: strdup of item text failed\n");
std::free(item);
return false;
}
// Save information about the menu item
item->action = action;
item->flink = NULL;
item->subMenu = NULL;
item->func = func;
CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *menuFont = fonts->getMenuFont();
int width = menuFont->getStringWidth(text);
if (width <= 0)
{
width = 1;
}
struct nxgl_size_s menuSize;
m_menuWindow->getSize(&menuSize);
if (width > menuSize.w)
{
menuSize.w = width;
m_menuWindow->setSize(&menuSize);
}
if (subMenu != NULL)
{
item->subMenu = subMenu;
m_menuPull = true;
}
// Save the index to this item and increment the total number of menu
// items
item->index = m_nMenuItems++;
// Add the menu item to the tail of the item list
if (m_menuHead == NULL)
{
m_menuHead = item;
item->blink = (FAR struct SMenuItem *)0;
}
else
{
m_menuTail->flink = item;
item->blink = m_menuTail;
}
m_menuTail = item;
item->flink = (FAR struct SMenuItem *)0;
// Add the item text to the list box
m_menuListBox->addOption(item->text, item->index);
// Update the menu window size
setMenuWindowSize();
// Redraw the list box
m_menuListBox->enableDrawing();
m_menuListBox->setRaisesEvents(true);
m_menuListBox->redraw();
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_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->func;
newmsg.pos.x = eventmsg->pos.x;
newmsg.pos.y = eventmsg->pos.y;
newmsg.delta.x = 0;
newmsg.delta.y = 0;
wm4Nx is a port of twm, Tab Window Manager (or Tom's Window Manager) version 1.0.10 to NuttX NX windows server. No, a port is not the right word. It is a re-design of TWM from the inside out to work with the NuttX NX server. The name Twm4Nx reflects this legacy. But Twm4Nx is more a homage to TWM than a port of TWM. The original TWM was based on X11 which provides a rich set of features. TWM provided titlebars, shaped windows, several forms of icon management, user-defined macro functions, click-to-type and pointer-driven keyboard focus, graphic contexts, and user-specified key and pointer button bindings, etc. Twm4Nx, on the other hand is based on the NuttX NX server which provides comparatively minimal support. Additional drawing support comes from the NuttX NxWidgets library (which necessitated the change to C++). Twm4Nx is greatly stripped down and targeted on small embedded systems with minimal resources. For example, no assumption is made about the availability of a file system; no .twmrc file is used. Bitmaps are not used (other than for fonts). The TWM license is, I believe compatible with the BSD license used by NuttX. The origin TWM license required notice of copyrights within each file and a full copy of the original license which you can find in the COPYING file. within this directory. STATUS: This port was brutal. Much TWM logic was removed because it depending on X11 features (or just because I could not understand how to use it). The logic is partial. A lot more needs to be done to have a complete system (hence, it is marked EXPERIMENTAL). The kinds of things that need to done are: 1. Update some logic that is only fragmentary for how like resizing, and menus. 2. Integrate NxWidgets into the windows: The resize menu needs a CLabel, the menus are CListBox'es, but not completely integrated, the Icon Manager needs to be a button array. 3. Resit Icons. They are windows now, but need to be compound widgets lying on the background. 4. Widget events are only partially integrated. A lot more needs to be done. A partial change to thoe event system that hints at the redesign is in place but it is far from complete.
2019-04-25 16:54:17 -06:00
newmsg.context = eventmsg->context;
newmsg.obj = eventmsg->obj;
// 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 runawy stack usage.
int ret = mq_send(m_eventq, (FAR const char *)&newmsg,
sizeof(struct SEventMsg), 100);
if (ret < 0)
{
gerr("ERROR: mq_send failed: %d\n", ret);
success = false;
}
}
}
break;
case EVENT_MENU_TITLE: // Really an action not an event
case EVENT_MENU_ROOT: // Popup root menu, really an action not an event
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->getPosition(&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->setPosition(&menuPos) ||
!m_menuWindow->setSize(&menuSize))
{
return;
}
// Raise it to the top of the hiearchy
m_menuWindow->raise();
}
/**
* Create the menu window
*
* @result True is returned on success
*/
bool CMenus::createMenuWindow(void)
{
// Create the menu window
// 1. Get the server instance. m_twm4nx inherits from NXWidgets::CNXServer
// so we all ready have the server instance.
// 2. Create the style, using the selected colors (REVISIT)
// 3. Create a Widget control instance for the window using the default
// style for now. CWindowEvent derives from CWidgetControl.
FAR CWindowEvent *control = new CWindowEvent(m_twm4nx);
// 4. Create the menu window
m_menuWindow = m_twm4nx->createFramedWindow(control);
if (m_menuWindow == (FAR NXWidgets::CNxTkWindow *)0)
{
delete control;
return false;
}
// 5. Open and initialize the menu window
bool success = m_menuWindow->open();
if (!success)
{
delete m_menuWindow;
m_menuWindow = (FAR NXWidgets::CNxTkWindow *)0;
return false;
}
// 6. Set the initial window size
if (!setMenuWindowSize())
{
delete m_menuWindow;
m_menuWindow = (FAR NXWidgets::CNxTkWindow *)0;
return false;
}
// 7. Set the initial window position
struct nxgl_point_s pos =
{
.x = 0,
.y = 0
};
if (!m_menuWindow->setPosition(&pos))
{
delete m_menuWindow;
m_menuWindow = (FAR NXWidgets::CNxTkWindow *)0;
return false;
}
return true;
}
/**
* Update the menu window size
*
* @result True is returned on success
*/
bool CMenus::setMenuWindowSize(void)
{
CFonts *fonts = m_twm4nx->getFonts();
FAR NXWidgets::CNxFont *menuFont = fonts->getMenuFont();
m_entryHeight = menuFont->getHeight() + 4;
// Get the length of the longest item string in in the menu
nxgl_coord_t maxstring = 0;
for (FAR struct SMenuItem *curr = m_menuHead;
curr != NULL;
curr = curr->flink)
{
if (curr->text != (FAR char *)0)
{
nxgl_coord_t stringlen = menuFont->getStringWidth(curr->text);
if (stringlen > maxstring)
{
maxstring = stringlen;
}
}
}
// Lets first size the window accordingly
struct nxgl_size_s menuSize;
menuSize.w = maxstring + 10;
unsigned int nMenuItems = m_nMenuItems > 0 ? m_nMenuItems : 1;
menuSize.h = nMenuItems * m_entryHeight;
if (m_menuPull == true)
{
menuSize.w += 16;
}
// Clip to the size of the display
struct nxgl_size_s displaySize;
m_twm4nx->getDisplaySize(&displaySize);
struct nxgl_size_s frameSize;
menuToFrameSize(&menuSize, &frameSize);
if (frameSize.w > displaySize.w)
{
frameSize.w = displaySize.w;
}
if (frameSize.h > displaySize.h)
{
frameSize.h = displaySize.h;
}
// Set the new menu window size
frameToMenuSize(&frameSize, &menuSize);
if (!m_menuWindow->setSize(&menuSize))
{
gerr("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->setPosition(&menuPos);
}
/**
* Create the menu list box
*
* @result True is returned on success
*/
bool CMenus::createMenuListBox(void)
{
// Create the menu list box
// 1. Get the server instance. m_twm4nx inherits from NXWidgets::CNXServer
// so we all ready have the server instance.
// 2. Create the style, using the selected colors (REVISIT)
// 3. Create a Widget control instance for the window using the default
// style for now. CWindowEvent derives from CWidgetControl.
FAR CWindowEvent *control = new CWindowEvent(m_twm4nx);
// 4. Create the menu list box
struct nxgl_point_s pos;
pos.x = 0;
pos.y = 0;
struct nxgl_size_s size;
pos.x = 0;
pos.y = 0;
m_menuListBox = new NXWidgets::CListBox(control, pos.x, pos.y,
size.w, size.h);
if (m_menuListBox == (FAR NXWidgets::CListBox *)0)
{
gerr("ERROR: Failed to instantiate list box\n");
delete control;
return false;
}
// Configure the list box
m_menuListBox->disable();
m_menuListBox->disableDrawing();
m_menuListBox->disableDrawing();
// Register to get events from the mouse clicks on the image
m_menuListBox->addWidgetEventHandler(this);
return true;
}
/**
* Pop up a pull down menu.
*
* @param pos Location of upper left of menu frame
*/
bool CMenus::popUpMenu(FAR struct nxgl_point_s *pos)
{
// If there is already a popup menu, then delete it. We only permit
// one popup at this level.
if (m_popUpMenu != (FAR CMenus *)0)
{
delete m_popUpMenu;
}
// Create and initialize a new menu
m_popUpMenu = new CMenus(m_twm4nx);
if (m_popUpMenu == (FAR CMenus *)0)
{
gerr("ERROR: Failed to create popup menu.\n");
return false;
}
if (!m_popUpMenu->initialize(m_activeItem->text))
{
gerr("ERROR: Failed to intialize popup menu.\n");
delete m_popUpMenu;
m_popUpMenu = (FAR CMenus *)0;
return false;
}
m_popUpMenu->addMenuItem("TWM Windows", (FAR const char *)0,
(FAR CMenus *)0, 0);
FAR CWindowFactory *factory = m_twm4nx->getWindowFactory();
int nWindowNames;
FAR struct SWindow *swin;
for (swin = factory->windowHead(), nWindowNames = 0;
swin != NULL; swin = swin->flink)
{
nWindowNames++;
}
if (nWindowNames != 0)
{
FAR CWindow **windowNames =
(FAR CWindow **)std::malloc(sizeof(FAR CWindow *) * nWindowNames);
if (windowNames == (FAR CWindow **)0)
{
gerr("ERROR: Failed to allocat window name\n");
return false;
}
swin = factory->windowHead();
windowNames[0] = swin->cwin;
for (nWindowNames = 1;
swin != NULL;
swin = swin->flink, nWindowNames++)
{
FAR CWindow *tmpcwin1 = swin->cwin;
for (int i = 0; i < nWindowNames; i++)
{
FAR const char *windowName1 = tmpcwin1->getWindowName();
FAR const char *windowName2 = windowNames[i]->getWindowName();
if (std::strcmp(windowName1, windowName2) < 0)
{
FAR CWindow *tmpcwin2;
tmpcwin2 = tmpcwin1;
tmpcwin1 = windowNames[i];
windowNames[i] = tmpcwin2;
}
}
windowNames[nWindowNames] = tmpcwin1;
}
for (int i = 0; i < nWindowNames; i++)
{
m_popUpMenu->addMenuItem(windowNames[i]->getWindowName(),
(FAR const char *)0, (FAR CMenus *)0,
EVENT_WINDOW_POPUP);
}
std::free(windowNames);
}
if (m_nMenuItems == 0)
{
delete m_popUpMenu;
m_popUpMenu = (FAR CMenus *)0;
return false;
}
// Clip to screen
struct nxgl_size_s displaySize;
m_twm4nx->getDisplaySize(&displaySize);
struct nxgl_size_s menuSize;
m_menuWindow->getSize(&menuSize);
struct nxgl_size_s frameSize;
menuToFrameSize(&menuSize, &frameSize);
if (pos->x + frameSize.w > displaySize.w)
{
pos->x = displaySize.w - frameSize.w;
}
if (pos->x < 0)
{
pos->x = 0;
}
if (pos->y + frameSize.h > displaySize.h)
{
pos->y = displaySize.h - frameSize.h;
}
if (pos->y < 0)
{
pos->y = 0;
}
DEBUGASSERT(m_menuDepth < UINT8_MAX);
m_menuDepth++;
if (!m_popUpMenu->setMenuWindowPosition(pos))
{
delete m_popUpMenu;
m_popUpMenu = (FAR CMenus *)0;
return false;
}
m_popUpMenu->raiseMenuWindow();
m_menuWindow->synchronize();
return m_popUpMenu;
}
/**
* 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 any popup menus
if (m_popUpMenu != (FAR CMenus *)0)
{
delete m_popUpMenu;
}
// Free the menu window
if (m_menuWindow != (FAR NXWidgets::CNxTkWindow *)0)
{
delete m_menuWindow;
m_menuWindow = (FAR NXWidgets::CNxTkWindow *)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 the menu item text
if (curr->text != (FAR char *)0)
{
std::free(curr->text);
}
// Free any subMenu
if (curr->subMenu != (FAR CMenus *)0)
{
delete curr->subMenu;
}
// Free the menu item
delete curr;
}
// Free allocated memory
if (m_menuName != (FAR char *)0)
{
std::free(m_menuName);
m_menuName = (FAR char *)0;
}
}