/* AbiSource Program Utilities
 * Copyright (C) 1998 AbiSource, Inc.
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
 * 02111-1307, USA.
 */
 
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "ut_types.h"
#include "ut_stack.h"
#include "ut_string.h"
#include "ut_string_class.h"
#include "ut_debugmsg.h"
#include "xap_Types.h"
#include "ev_QNXMenu.h"
#include "xap_QNXApp.h"
#include "xap_QNXFrameImpl.h"
#include "ap_QNXFrameImpl.h"
#include "xap_Frame.h"
#include "ev_QNXKeyboard.h"
#include "ev_Menu_Layouts.h"
#include "ev_Menu_Actions.h"
#include "ev_Menu_Labels.h"
#include "ev_EditEventMapper.h"


/*****************************************************************/

/*
  Unlike the Win32 version, which uses a \t (tab) to seperate the
  feature from the mnemonic in a single label string, this
  function returns two strings, to be put into the two seperate
  labels in a Gtk menu item.

  Oh, and these are static buffers, don't call this function
  twice and expect previous return pointers to have the same
  values at their ends.
*/

static const char ** _ev_GetLabelName(XAP_QNXApp * pQNXApp,
									  XAP_Frame * pFrame,
									  const EV_Menu_Action * pAction,
									  const EV_Menu_Label * pLabel)
{
	static const char * data[2] = {NULL, NULL};

	// hit the static pointers back to null each time around
	data[0] = NULL;
	data[1] = NULL;
	
	const char * szLabelName;
	
	if (pAction->hasDynamicLabel())
		szLabelName = pAction->getDynamicLabel(pLabel);
	else
		szLabelName = pLabel->getMenuLabel();

	if (!szLabelName || !*szLabelName)
		return data;	// which will be two nulls now

	static char accelbuf[32];
	{
		// see if this has an associated keybinding
		const char * szMethodName = pAction->getMethodName();

		if (szMethodName)
		{
			const EV_EditMethodContainer * pEMC = pQNXApp->getEditMethodContainer();
			UT_ASSERT(pEMC);

			EV_EditMethod * pEM = pEMC->findEditMethodByName(szMethodName);
			UT_ASSERT(pEM);						// make sure it's bound to something

			const EV_EditEventMapper * pEEM = pQNXApp->getEditEventMapper();
			UT_ASSERT(pEEM);

			const char * string = pEEM->getShortcutFor(pEM);
			if (string && *string)
				strcpy(accelbuf, string);
			else
				// zero it out for this round
				*accelbuf = 0;
		}
	}

	// set shortcut mnemonic, if any
	if (*accelbuf)
		data[1] = accelbuf;
	
	if (!pAction->raisesDialog())
	{
		data[0] = szLabelName;
		return data;
	}

	// append "..." to menu item if it raises a dialog
	static char buf[128];
	memset(buf,0,NrElements(buf));
	strncpy(buf,szLabelName,NrElements(buf)-4);
	strcat(buf,"...");

	data[0] = buf;
	
	return data;
}

/*****************************************************************/

EV_QNXMenu::EV_QNXMenu(XAP_QNXApp * pQNXApp, XAP_Frame * pFrame,
					   const char * szMenuLayoutName,
					   const char * szMenuLabelSetName)
	: EV_Menu(pQNXApp, pQNXApp->getEditMethodContainer(), szMenuLayoutName, szMenuLabelSetName),
	  m_pQNXApp(pQNXApp),
	  m_pFrame(pFrame)
{
}

EV_QNXMenu::~EV_QNXMenu()
{
	m_vecMenuWidgets.clear();
}

XAP_Frame * EV_QNXMenu::getFrame()
{
	return m_pFrame;
}

bool EV_QNXMenu::menuEvent(XAP_Menu_Id id)
{
	// user selected something from the menu.
	// invoke the appropriate function.
	// return true iff handled.

	const EV_Menu_ActionSet * pMenuActionSet = m_pQNXApp->getMenuActionSet();
	UT_ASSERT(pMenuActionSet);

	const EV_Menu_Action * pAction = pMenuActionSet->getAction(id);
	UT_ASSERT(pAction);

	const char * szMethodName = pAction->getMethodName();
	if (!szMethodName)
		return false;
	
	const EV_EditMethodContainer * pEMC = m_pQNXApp->getEditMethodContainer();
	UT_ASSERT(pEMC);

	EV_EditMethod * pEM = pEMC->findEditMethodByName(szMethodName);
	UT_ASSERT(pEM);						// make sure it's bound to something

	UT_String script_name(pAction->getScriptName());
	invokeMenuMethod(m_pFrame->getCurrentView(), pEM, script_name);

	return true;
}

static char _ev_convert(char * bufResult,
			const char * szString)
{
	int i;
	char *p, c;
	UT_ASSERT(szString && bufResult);

	c = 0;
	for (i=0, p = bufResult; szString[i]; i++) {
		if (szString[i] == '&' && szString[i+1] != '&') 
			c = szString[i+1];
		else
			*p++ = szString[i];
	}
	*p = '\0';
	return(c);
}

struct _cb_menu {
	EV_QNXMenu	*qnxmenu;
	PtWidget_t	*widget;
	XAP_Menu_Id id;
};

/*******************************************************************************/

static int s_menu_select(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
{
		struct _cb_menu *mcb = (struct _cb_menu *)data;
		UT_ASSERT(mcb && mcb->qnxmenu);

		XAP_Frame * pFrame = mcb->qnxmenu->getFrame();
		UT_ASSERT(pFrame);

		EV_Menu_Label * pLabel = mcb->qnxmenu->getLabelSet()->getLabel(mcb->id);
		if (!pLabel) {
			pFrame->setStatusMessage(NULL);
			return Pt_CONTINUE;
		}

		const char * szMsg = pLabel->getMenuStatusMessage();
		if (!szMsg || !*szMsg) {
			szMsg = "TODO This menu item doesn't have a StatusMessage defined.";
		}
	
		pFrame->setStatusMessage(szMsg);
		return Pt_CONTINUE;
}
	
static int s_menu_deselect(PtWidget_t *widget, void *data, PtCallbackInfo_t *info)
{
		EV_QNXMenu *pQNXMenu = (EV_QNXMenu *)data;

		XAP_Frame * pFrame = pQNXMenu->getFrame();
		UT_ASSERT(pFrame);

		pFrame->setStatusMessage(NULL);
		static_cast<AP_QNXFrameImpl *>(pFrame->getFrameImpl())->setDocumentFocus();

		return Pt_CONTINUE;
}


static int s_menu_activate(PtWidget_t *w, void *data, PtCallbackInfo_t *info) {
	struct _cb_menu *mcb = (struct _cb_menu *)data;

	mcb->qnxmenu->menuEvent(mcb->id);

	return Pt_CONTINUE;
}

static int s_menu_appear(PtWidget_t *w, void *data, PtCallbackInfo_t *info) {
	PtWidget_t *menu= (PtWidget_t *)data;

	if (menu) {
		PtPositionMenu(menu, (info) ? info->event : NULL);
		PtRealizeWidget(menu);
	}

	return Pt_CONTINUE;
}

static int s_menu_init(PtWidget_t *w, void *data, PtCallbackInfo_t *info) {
	EV_QNXMenu *pMenu = (EV_QNXMenu *)data;
	UT_ASSERT(pMenu);

	pMenu->refreshMenu(pMenu->getFrame()->getCurrentView());
	return Pt_CONTINUE;
}

/*******************************************************************************/

/* Not perfect since we have FXX keys and Del in this list 
   Really we should have a function to attach a hotkey/label
   to a widget given the widget.
*/
static char get_hotkey_key(const char *str) {
	//Find the next character after the =
	const char *p;
	if ((p = strchr(str, '+')) && *++p) {
		//This fixes problems like Alt-F4 for quitting ... for now
		if (*(p+1) == '\0') {
			return tolower(*p);
		}
	}	
	return '\0';
}

static int get_hotkey_code(const char *str) {
	int code = 0;
	if (strstr(str, "Ctrl")) {
		code |= Pk_KM_Ctrl; 
	}
	if (strstr(str, "Shift")) {
		code |= Pk_KM_Shift;
	}
	if (strstr(str, "Alt")) {
		code |= Pk_KM_Alt;
	}
	return code;
}



bool EV_QNXMenu::synthesizeMenu(PtWidget_t * wMenuRoot)
{
	PtArg_t args[10];

	const EV_Menu_ActionSet * pMenuActionSet = m_pQNXApp->getMenuActionSet();
	UT_ASSERT(pMenuActionSet);
	
	UT_uint32 nrLabelItemsInLayout = m_pMenuLayout->getLayoutItemCount();
	UT_ASSERT(nrLabelItemsInLayout > 0);

	// we keep a stack of the widgets so that we can properly
	// parent the menu items and deal with nested pull-rights.
	bool bResult;
	UT_Stack stack;
	stack.push(wMenuRoot);

	for (UT_uint32 k=0; (k < nrLabelItemsInLayout); k++)
	{
		EV_Menu_LayoutItem * pLayoutItem = m_pMenuLayout->getLayoutItem(k);
		UT_ASSERT(pLayoutItem);
		
		XAP_Menu_Id id = pLayoutItem->getMenuId();
		const EV_Menu_Action * pAction = pMenuActionSet->getAction(id);
		UT_ASSERT(pAction);
		const EV_Menu_Label * pLabel = m_pMenuLabelSet->getLabel(id);
		UT_ASSERT(pLabel);

		// get the name for the menu item
		const char * szLabelName;
		const char * szMnemonicName;
		
		switch (pLayoutItem->getMenuLayoutFlags())
		{
		case EV_MLF_Normal:
		{
			const char ** data = _ev_GetLabelName(m_pQNXApp, m_pFrame, pAction, pLabel);
			szLabelName = data[0];
			szMnemonicName = data[1];

			PtWidget_t * wParent, *wbutton;
			stack.viewTop((void **)&wParent);
			
			if (szLabelName && *szLabelName)
			{
				char buf[1024], accel[2];
				// convert label into underscored version
				accel[0] = _ev_convert(buf, szLabelName);
				accel[1] = '\0';

				int n = 0;
				PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, buf, 0); 
				PtSetArg(&args[n++], Pt_ARG_ACCEL_KEY, accel, 0); 
				if (szMnemonicName && *szMnemonicName) {
					PtSetArg(&args[n++], Pt_ARG_ACCEL_TEXT, szMnemonicName, 0); 
				}

				if (pAction->isCheckable() || pAction->isRadio()) {
					PtSetArg(&args[n++], Pt_ARG_FLAGS,
							Pt_MENU_BUTTON | Pt_AUTOHIGHLIGHT | Pt_SET, 
							Pt_MENU_BUTTON | Pt_AUTOHIGHLIGHT | Pt_SET);
					wbutton = PtCreateWidget(PtToggleButton, wParent, n, args);
				}
				else {
 					wbutton = PtCreateWidget(PtMenuButton, wParent, n, args); 
				}

				struct _cb_menu *mcb;
				mcb = (struct _cb_menu *)malloc(sizeof(*mcb));
				mcb->widget = wbutton;
				mcb->id = id;
				mcb->qnxmenu = this;
				PtAddCallback(wbutton, Pt_CB_ACTIVATE, s_menu_activate, mcb);
				PtAddCallback(wbutton, Pt_CB_ARM, s_menu_select, mcb);

				if (szMnemonicName && *szMnemonicName && get_hotkey_key(szMnemonicName) != '\0') {
					PtAddHotkeyHandler(PtGetParent(wMenuRoot, PtWindow),
									   get_hotkey_key(szMnemonicName), 
									   get_hotkey_code(szMnemonicName),
										0, mcb, s_menu_activate); 
				}

				// item is created, add to class vector
				m_vecMenuWidgets.addItem(wbutton);
			}
			else {
				// Add a placeholder item in the list
				m_vecMenuWidgets.addItem(NULL);
			}
			break;
		}
		case EV_MLF_BeginSubMenu:
		{
			const char ** data = _ev_GetLabelName(m_pQNXApp, m_pFrame, pAction, pLabel);
			szLabelName = data[0];

			PtWidget_t * wParent, *wbutton, *wmenu;
			stack.viewTop((void **)&wParent);

			if (szLabelName && *szLabelName)
			{
				char buf[1024], accel[2];
				// convert label into underscored version
				accel[0] =_ev_convert(buf, szLabelName);
				accel[1] = '\0';

				// create the item widget
				int n = 0;
				PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, buf, 0); 
				PtSetArg(&args[n++], Pt_ARG_ACCEL_KEY, accel, 0);
				if ((PtGetParent(wParent,PtMenuBar) == NULL) || wParent != wMenuRoot) {
					PtSetArg(&args[n++], Pt_ARG_BUTTON_TYPE, Pt_MENU_RIGHT, Pt_MENU_RIGHT);
				}
				wbutton = PtCreateWidget(PtMenuButton, wParent, n, args); 

				n = 0;
				if ((PtGetParent(wParent,PtMenuBar) == NULL) || wParent != wMenuRoot) {
					PtSetArg(&args[n], Pt_ARG_MENU_FLAGS, 
							Pt_MENU_CHILD|Pt_MENU_AUTO, 
							Pt_MENU_CHILD|Pt_MENU_AUTO); n++;
				}
				wmenu =  PtCreateWidget(PtMenu, wbutton, n, args); 
				if ((PtGetParent(wParent,PtMenuBar) && wParent == wMenuRoot)) {
					PtAddCallback(wbutton, Pt_CB_ARM, s_menu_init, this);
					PtAddCallback(wbutton, Pt_CB_ARM, s_menu_appear, wmenu);
					PtAddCallback(wmenu,Pt_CB_UNREALIZED,s_menu_deselect,this);
					PtAddHotkeyHandler(PtGetParent(wMenuRoot, PtWindow), 
										tolower(accel[0]), Pk_KM_Alt, 
										0, wmenu, s_menu_appear); 
				}

				stack.push(wmenu);
				//If you need the menu button for manipulation, you can always get the parent
				m_vecMenuWidgets.addItem(wmenu /* wbutton */);
			}
			else {
				// Add a placeholder item in the list
				m_vecMenuWidgets.addItem(NULL);
			}
			break;
		}
		case EV_MLF_EndSubMenu:
		{
			PtWidget_t * w;
			bResult = stack.pop((void **)&w);
			UT_ASSERT(bResult);
			
			if(w == NULL) {
			stack.push(wMenuRoot);
			w= wMenuRoot;
			}
			//Add the same widget that was the start of the menu
			m_vecMenuWidgets.addItem(w);
			break;
		}
		case EV_MLF_Separator:
		{	
			PtWidget_t * wParent;
			bResult = stack.viewTop((void **)&wParent);
			UT_ASSERT(bResult);

			PtWidget_t * w = PtCreateWidget(PtSeparator, wParent, 0, 0);

			m_vecMenuWidgets.addItem(w);
			break;
		}
		case EV_MLF_BeginPopupMenu:
		case EV_MLF_EndPopupMenu:
			m_vecMenuWidgets.addItem(NULL);	
			break;
			
		default:
			UT_ASSERT(0);
			break;
		}
	}

	// make sure our last item on the stack is the one we started with
	return true;
}

static void set_menu_enabled(PtWidget_t *w, int enabled, int checked) {
	int flags;

/* Photon funniness ... why can't ghosting work? */
	flags =  (enabled == true) ? Pt_SELECTABLE : (Pt_BLOCKED | Pt_GHOST)  ;
	flags |= (checked == true) ? Pt_SET : Pt_FALSE;
	PtSetResource(w, Pt_ARG_FLAGS, flags, Pt_BLOCKED | Pt_GHOST | Pt_SET | Pt_SELECTABLE);
}

//TODO: This code gets called way too often, or maybe we need to be able
//      to whip through all of the non-relevant widgets more quickly.  In
//      any case it is on the TODO list.
bool EV_QNXMenu::_refreshMenu(AV_View * pView, void * wMenuRoot)
{
	PtWidget_t *item, *wParent, *wPrev;

	// update the status of stateful items on menu bar.
	const EV_Menu_ActionSet * pMenuActionSet = m_pQNXApp->getMenuActionSet();
	UT_ASSERT(pMenuActionSet);
	UT_uint32 nrLabelItemsInLayout = m_pMenuLayout->getLayoutItemCount();

	// we keep a stack of the widgets so that we can properly
	// parent the menu items and deal with nested pull-rights.
	bool bResult;
	UT_Stack stack;
	stack.push(wMenuRoot);

	// -1 will catch the case where we're inserting and haven't actually
	// entered into a real menu (only at a top level menu)
	
	int nPositionInThisMenu = -1;

	for (UT_uint32 k=0; (k < nrLabelItemsInLayout); k++)
	{
		EV_Menu_LayoutItem * pLayoutItem = m_pMenuLayout->getLayoutItem(k);
		XAP_Menu_Id id = pLayoutItem->getMenuId();
		const EV_Menu_Action * pAction = pMenuActionSet->getAction(id);
		const EV_Menu_Label * pLabel = m_pMenuLabelSet->getLabel(id);

		switch (pLayoutItem->getMenuLayoutFlags())
		{
		case EV_MLF_Normal:
			{
				// Keep track of where we are in this menu; we get cut down
				// to zero on the creation of each new submenu.
				nPositionInThisMenu++;
			
				// see if we need to enable/disable and/or check/uncheck it.
				
				bool bEnable = true;
				bool bCheck = false;
				
				if (pAction->hasGetStateFunction())
				{
					EV_Menu_ItemState mis = pAction->getMenuItemState(pView);
					if (mis & EV_MIS_Gray)
						bEnable = false;
					if (mis & EV_MIS_Toggled)
						bCheck = true;
				}

				// must have an entry for each and every layout item in the vector
				UT_ASSERT((k < m_vecMenuWidgets.getItemCount() - 1));

				// Get the dynamic label
				const char ** data = _ev_GetLabelName(m_pQNXApp, m_pFrame, pAction, pLabel);
				const char * szLabelName = data[0];
				
				// Get the item we are pointing at
				item = (PtWidget_t *) m_vecMenuWidgets.getNthItem(k);
				stack.viewTop((void **)&wParent);

				// No dynamic label then just check/enable the item
				if (!pAction->hasDynamicLabel())
				{
					// If there is no item, then skip this placeholder entry		
					if (!item) {
						UT_ASSERT(0);
						break;
					}
					wPrev = item;
					set_menu_enabled(item, bEnable, bCheck);
				}

				// Dynamic label string --> NULL string means remove entry
				else if (!szLabelName || !*szLabelName)
				{
					if (item) {
						PtDestroyWidget(item);
					}

					// we must also mark this item in the vector as "removed",
					// which means setting [k] equal to a fake item as done
					// on creation of dynamic items.
					// give it a fake, with no label, to make sure it passes the
					// test that an empty (to be replaced) item in the vector should
					// have no children

					if(m_vecMenuWidgets.setNthItem(k, NULL /* New */, NULL /* Old */))
					{
						UT_DEBUGMSG(("Could not update dynamic menu widget vector item %s.", k));
						UT_ASSERT(0);
					}
					break;
				}

				// Dynamic label string --> Change label and set mode
				else {
					// create a new updated label
					char labelbuf[1024], accel[2];

					// convert label into underscored version
					accel[0] = _ev_convert(labelbuf, szLabelName);
					accel[1] = '\0';


					if (!item) {
						int n;
						PtArg_t args[10];
						
						n = 0;
						PtSetArg(&args[n++], Pt_ARG_TEXT_STRING, labelbuf, 0); 
						PtSetArg(&args[n++], Pt_ARG_ACCEL_KEY, accel, 0); 

						if (pAction->isCheckable()) {
							PtSetArg(&args[n++], Pt_ARG_FLAGS,
								Pt_MENU_BUTTON | Pt_AUTOHIGHLIGHT | Pt_SET, 
								Pt_MENU_BUTTON | Pt_AUTOHIGHLIGHT | Pt_SET);
							item = PtCreateWidget(PtToggleButton, wParent, n, args);
						} else {
							item = PtCreateWidget(PtMenuButton, wParent, n, args); 
						}
						if(wPrev) {
							PtWidgetInsert(item, wPrev, 0);
						}
						PtRealizeWidget(item);

						struct _cb_menu *mcb;
						mcb = (struct _cb_menu *)malloc(sizeof(*mcb));
						mcb->widget = item;
						mcb->id = id;
						mcb->qnxmenu = this;
						PtAddCallback(item, Pt_CB_ACTIVATE, s_menu_activate, mcb);
						PtAddCallback(item, Pt_CB_ARM, s_menu_select, mcb);

						//Now that we have an item, add it to the vector
						m_vecMenuWidgets.setNthItem(k, item, NULL);

						break;
					}

					PtSetResource(item, Pt_ARG_TEXT_STRING, labelbuf, 0);
					PtSetResource(item, Pt_ARG_ACCEL_KEY, accel, 0); 
					set_menu_enabled(item, bEnable, bCheck);
					wPrev = item;
				}
			}
			break;

		case EV_MLF_Separator:
			nPositionInThisMenu++;
			wPrev = (PtWidget_t *) m_vecMenuWidgets.getNthItem(k);
			break;

		case EV_MLF_BeginSubMenu:
		{
			nPositionInThisMenu = -1;

			// we need to nest sub menus to have some sort of context so
			// we can parent menu items
			item = (PtWidget_t *) m_vecMenuWidgets.getNthItem(k);
			wPrev = NULL;
			UT_ASSERT(item);
			stack.push(item);
			break;
		}
		case EV_MLF_EndSubMenu:
		{
			item = NULL;
			bResult = stack.pop((void **)&item);
			UT_ASSERT(bResult);
			break;
		}

		case EV_MLF_BeginPopupMenu:
		case EV_MLF_EndPopupMenu:
			break;
			
		default:
			UT_ASSERT(0);
			break;
		}	
	}

	PtWidget_t * wDbg = NULL;
	bResult = stack.pop((void **)&wDbg);
	UT_ASSERT(bResult);
	UT_ASSERT(wDbg == wMenuRoot);

	return true;
}

/*!
 * See unix menu code for comment
 */
bool EV_QNXMenu::_doAddMenuItem(UT_uint32 layout_pos)
{
	if (layout_pos > 0)
	{
		UT_sint32 err = m_vecMenuWidgets.insertItemAt(NULL, layout_pos);
		return !err;
	}

	return false;
}



/*****************************************************************/

EV_QNXMenuBar::EV_QNXMenuBar(XAP_QNXApp * pQNXApp,
							   XAP_Frame * pFrame,
							   const char * szMenuLayoutName,
							   const char * szMenuLabelSetName)
	: EV_QNXMenu(pQNXApp,pFrame,szMenuLayoutName,szMenuLabelSetName)
{
	m_wMenuBar = NULL;
}

EV_QNXMenuBar::~EV_QNXMenuBar(void)
{
	if (m_wMenuBar) {
		PtDestroyWidget(m_wMenuBar);
	}
	m_wMenuBar = NULL;
	//TODO: Keep track of our alloced strucutres and free them too
}

bool EV_QNXMenuBar::synthesizeMenuBar(void)
{
	 PtArg_t args[2];
	 int		 n=0;
	 XAP_QNXFrameImpl *pQNXFrameImpl = static_cast<XAP_QNXFrameImpl *>(m_pFrame->getFrameImpl()); 

	PtSetArg(&args[n++],Pt_ARG_FLAGS,Pt_FALSE,Pt_GETS_FOCUS);
	m_wMenuBar = PtCreateWidget(PtMenuBar, pQNXFrameImpl->getTBGroupWidget(), n, args);
	synthesizeMenu(m_wMenuBar);
	return true;
}

bool EV_QNXMenuBar::refreshMenu(AV_View * pView)
{
	// this makes an exception for initialization where a view
	// might not exist... silly to refresh the menu then; it will
	// happen in due course to its first display
	if (pView)
		return _refreshMenu(pView,m_wMenuBar);

	return true;
}

/*****************************************************************/

EV_QNXMenuPopup::EV_QNXMenuPopup(XAP_QNXApp * pQNXApp,
								   XAP_Frame * pFrame,
								   const char * szMenuLayoutName,
								   const char * szMenuLabelSetName)
	: EV_QNXMenu(pQNXApp,pFrame,szMenuLayoutName,szMenuLabelSetName)
{
	m_wMenuPopup = NULL;
}

EV_QNXMenuPopup::~EV_QNXMenuPopup(void)
{
	if (m_wMenuPopup) {
		PtDestroyWidget(m_wMenuPopup);
	}
	m_wMenuPopup = NULL;
	//TODO: Keep track of our alloced strucutres and free them too
}

PtWidget_t * EV_QNXMenuPopup::getMenuHandle(void) const
{
	return m_wMenuPopup;
}

static int popup_realized(PtWidget_t *w, void *data, PtCallbackInfo_t *info) {
	XAP_Frame *pFrame = (XAP_Frame *)data; 
	 PtWidget_t *top =(static_cast<XAP_QNXFrameImpl *>(pFrame->getFrameImpl())->getTopLevelWindow()); 
	PtArg_t arg;
	PtSetArg(&arg, Pt_ARG_FLAGS, Pt_BLOCKED, Pt_BLOCKED);
	PtSetResources(top, 1, &arg);

	return Pt_CONTINUE;
}

static int popup_unrealized(PtWidget_t *w, void *data, PtCallbackInfo_t *info) {
	XAP_Frame *pFrame = (XAP_Frame *)data; 
	 PtWidget_t *top =(static_cast<XAP_QNXFrameImpl *>(pFrame->getFrameImpl())->getTopLevelWindow()); 
	PtArg_t arg;
	PtSetArg(&arg, Pt_ARG_FLAGS,Pt_FALSE, Pt_BLOCKED);
	PtSetResources(top, 1, &arg);

	pFrame->setStatusMessage(NULL);
	static_cast<AP_QNXFrameImpl *>(pFrame->getFrameImpl())->setDocumentFocus();
	static_cast<XAP_QNXFrameImpl *>(pFrame->getFrameImpl())->setPopupDone(1);

	return Pt_CONTINUE;
}


bool EV_QNXMenuPopup::synthesizeMenuPopup()
{
    PtArg_t args[10];
	int 	n = 0;
	 PtWidget_t *top =(static_cast<XAP_QNXFrameImpl *>(m_pFrame->getFrameImpl())->getTopLevelWindow()); 
	m_wMenuPopup = PtCreateWidget(PtMenu, 
								  top,
								  n, args);
	PtAddCallback(m_wMenuPopup, Pt_CB_REALIZED, popup_realized, m_pFrame);
	PtAddCallback(m_wMenuPopup, Pt_CB_UNREALIZED, popup_unrealized, m_pFrame);

	synthesizeMenu(m_wMenuPopup);

	return true;
}

bool EV_QNXMenuPopup::refreshMenu(AV_View * pView)
{
	// this makes an exception for initialization where a view
	// might not exist... silly to refresh the menu then; it will
	// happen in due course to its first display
	if (pView)
		return _refreshMenu(pView,m_wMenuPopup);

	return true;
}
