/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiSource Program Utilities * Copyright (C) 1998-2000 AbiSource, Inc. * Copyright (C) 2001 Hubert Figuiere * * 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 #include #include #include #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_CocoaMenu.h" #include "ev_CocoaMenuBar.h" #include "ev_CocoaMenuPopup.h" #include "xap_CocoaApp.h" #include "xap_CocoaFrame.h" #include "ev_CocoaKeyboard.h" #include "ev_Menu_Layouts.h" #include "ev_Menu_Actions.h" #include "ev_Menu_Labels.h" #include "ev_EditEventMapper.h" #include "ut_string_class.h" #import #import class _wd // a private little class to help { // us remember all the widgets that public: // we create... _wd(EV_CocoaMenu * pCocoaMenu, XAP_Menu_Id menuid, NSMenuItem *item = nil); ~_wd(void) {}; NSMenuItem * m_item; EV_CocoaMenu * m_pCocoaMenu; XAP_Menu_Id m_id; }; @implementation EV_CocoaMenuTarget - (id)menuSelected:(id)sender { UT_DEBUGMSG (("@EV_CocoaMenuTarget (id)menuSelected:(id)sender\n")); UT_ASSERT ([sender class] == [NSMenuItem class]); _wd *wd = (_wd *)[sender tag]; UT_ASSERT (wd); wd->m_pCocoaMenu->menuEvent(wd->m_id); } @end /*****************************************************************/ _wd::_wd(EV_CocoaMenu * pCocoaMenu, XAP_Menu_Id menuid, NSMenuItem *item) { m_pCocoaMenu = pCocoaMenu; m_id = menuid; m_item = item; } #if 0 class _wd // a private little class to help { // us remember all the widgets that public: // we create... static void s_onActivate(GtkWidget * /* widget */, gpointer callback_data) { // this is a static callback method and does not have a 'this' pointer. // map the user_data into an object and dispatch the event. _wd * wd = (_wd *) callback_data; UT_ASSERT(wd); wd->m_pCocoaMenu->menuEvent(wd->m_id); }; static void s_onMenuItemSelect(GtkWidget * widget, gpointer data) { UT_ASSERT(widget && data); _wd * wd = (_wd *) data; UT_ASSERT(wd && wd->m_pCocoaMenu); XAP_CocoaFrame * pFrame = wd->m_pCocoaMenu->getFrame(); UT_ASSERT(pFrame); EV_Menu_Label * pLabel = wd->m_pCocoaMenu->getLabelSet()->getLabel(wd->m_id); if (!pLabel) { pFrame->setStatusMessage(NULL); return; } const char * szMsg = pLabel->getMenuStatusMessage(); if (!szMsg || !*szMsg) szMsg = "TODO This menu item doesn't have a StatusMessage defined."; pFrame->setStatusMessage(szMsg); }; static void s_onMenuItemDeselect(GtkWidget * widget, gpointer data) { UT_ASSERT(widget && data); _wd * wd = (_wd *) data; UT_ASSERT(wd && wd->m_pCocoaMenu); XAP_CocoaFrame * pFrame = wd->m_pCocoaMenu->getFrame(); UT_ASSERT(pFrame); pFrame->setStatusMessage(NULL); }; static void s_onInitMenu(GtkMenuItem * menuItem, gpointer callback_data) { _wd * wd = (_wd *) callback_data; UT_ASSERT(wd); wd->m_pCocoaMenu->refreshMenu(wd->m_pCocoaMenu->getFrame()->getCurrentView()); // attach this new menu's accel group to be triggered off itself gtk_accel_group_attach(wd->m_accelGroup, GTK_OBJECT(menuItem)); gtk_accel_group_lock(wd->m_accelGroup); }; static void s_onDestroyMenu(GtkMenuItem * menuItem, gpointer callback_data) { _wd * wd = (_wd *) callback_data; UT_ASSERT(wd); // we always clear the status bar when a menu goes away, so we don't // leave a message behind XAP_CocoaFrame * pFrame = wd->m_pCocoaMenu->getFrame(); UT_ASSERT(pFrame); pFrame->setStatusMessage(NULL); // bind this menuitem to its parent menu gtk_accel_group_detach(wd->m_accelGroup, GTK_OBJECT(menuItem)); gtk_accel_group_unlock(wd->m_accelGroup); }; // GTK wants to run popup menus asynchronously, but we want synchronous, // so we need to do a gtk_main_quit() on our own to show we're done // with our modal work. static void s_onDestroyPopupMenu(GtkMenuItem * menuItem, gpointer callback_data) { // do the grunt work s_onDestroyMenu(menuItem, callback_data); gtk_main_quit(); }; GtkAccelGroup * m_accelGroup; EV_CocoaMenu * m_pCocoaMenu; XAP_Menu_Id m_id; }; #endif /*****************************************************************/ EV_CocoaMenu::EV_CocoaMenu(XAP_CocoaApp * pCocoaApp, XAP_CocoaFrame * pCocoaFrame, const char * szMenuLayoutName, const char * szMenuLabelSetName) : EV_Menu(pCocoaApp, pCocoaApp->getEditMethodContainer(), szMenuLayoutName, szMenuLabelSetName), m_pCocoaApp(pCocoaApp), m_pCocoaFrame(pCocoaFrame) { m_menuTarget = [[EV_CocoaMenuTarget alloc] init]; } EV_CocoaMenu::~EV_CocoaMenu() { UT_VECTOR_SPARSEPURGEALL(_wd *, m_vecMenuWidgets); [m_menuTarget release]; } XAP_CocoaFrame * EV_CocoaMenu::getFrame() { return m_pCocoaFrame; } bool EV_CocoaMenu::menuEvent(XAP_Menu_Id menuid) { // user selected something from the menu. // invoke the appropriate function. // return true if handled. const EV_Menu_ActionSet * pMenuActionSet = m_pCocoaApp->getMenuActionSet(); UT_ASSERT(pMenuActionSet); const EV_Menu_Action * pAction = pMenuActionSet->getAction(menuid); UT_ASSERT(pAction); const char * szMethodName = pAction->getMethodName(); if (!szMethodName) return false; const EV_EditMethodContainer * pEMC = m_pCocoaApp->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_pCocoaFrame->getCurrentView(), pEM, script_name); return true; } bool EV_CocoaMenu::synthesizeMenu(NSMenu * wMenuRoot) { UT_DEBUGMSG(("EV_CocoaMenu::synthesizeMenu\n")); // create a GTK menu from the info provided. const EV_Menu_ActionSet * pMenuActionSet = m_pCocoaApp->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. UT_uint32 tmp = 0; bool bResult; UT_Stack stack; stack.push(wMenuRoot); NSNibControlConnector * conn = [[NSNibControlConnector alloc] init]; for (UT_uint32 k = 0; (k < nrLabelItemsInLayout); k++) { EV_Menu_LayoutItem * pLayoutItem = m_pMenuLayout->getLayoutItem(k); UT_ASSERT(pLayoutItem); XAP_Menu_Id menuid = pLayoutItem->getMenuId(); // VERY BAD HACK! It will be here until I fix the const correctness of all the functions // using EV_Menu_Action const EV_Menu_Action * pAction = pMenuActionSet->getAction(menuid); UT_ASSERT(pAction); const EV_Menu_Label * pLabel = m_pMenuLabelSet->getLabel(menuid); UT_ASSERT(pLabel); // get the name for the menu item const char * szLabelName; const char * szMnemonicName; switch (pLayoutItem->getMenuLayoutFlags()) { case EV_MLF_Normal: { unsigned int modifier = 0; const char ** data = getLabelName(m_pCocoaApp, m_pCocoaFrame, pAction, pLabel); szLabelName = data[0]; szMnemonicName = data[1]; if (data[0] && *(data[0])) { NSString * shortCut = nil; if (data[1] && *(data[1])) { _getItemCmd (data[1], modifier, shortCut); } else { shortCut = [NSString string]; } char buf[1024]; // convert label into underscored version // create the item with the underscored label NSMenu * wParent; bResult = stack.viewTop((void **)&wParent); UT_ASSERT(bResult); NSMenuItem * menuItem = nil; NSString * str = nil; if (szLabelName) { _convertToMac(buf, sizeof (buf), szLabelName); str = [NSString stringWithCString:buf]; // autoreleased } else { str = [NSString string]; // autoreleased } menuItem = [wParent addItemWithTitle:str action:nil keyEquivalent:shortCut]; [conn setDestination:m_menuTarget]; [conn setSource:menuItem]; [conn setLabel:@"menuSelected:"]; [conn establishConnection]; // TODO check that this does not leak when we destroy the menu _wd * wd = new _wd (this, pLayoutItem->getMenuId(), menuItem); [menuItem setTag:(int)wd]; [shortCut release]; // item is created, add to class vector m_vecMenuWidgets.addItem(wd); } break; } case EV_MLF_BeginSubMenu: { const char ** data = getLabelName(m_pCocoaApp, m_pCocoaFrame, pAction, pLabel); szLabelName = data[0]; char buf[1024]; // convert label into underscored version // create the item with the underscored label NSMenu * wParent; bResult = stack.viewTop((void **)&wParent); UT_ASSERT(bResult); NSMenuItem * menuItem = nil; NSString * str = nil; if (szLabelName) { _convertToMac(buf, sizeof (buf), szLabelName); str = [NSString stringWithCString:buf]; // autoreleased } else { str = [NSString string]; // autoreleased } menuItem = [wParent addItemWithTitle:str action:nil keyEquivalent:@""]; // item is created, add to class vector _wd * wd = new _wd (this, pLayoutItem->getMenuId(), menuItem); [menuItem setTag:(int)wd]; m_vecMenuWidgets.addItem(wd); NSMenu * subMenu = [[NSMenu alloc] initWithTitle:str]; [menuItem setSubmenu:subMenu]; [subMenu setAutoenablesItems:NO]; stack.push((void **)subMenu); break; } case EV_MLF_EndSubMenu: { // pop and inspect NSMenu * menu; bResult = stack.pop((void **)&menu); UT_ASSERT(bResult); // item is created (albeit empty in this case), add to vector m_vecMenuWidgets.addItem(NULL); break; } case EV_MLF_Separator: { NSMenuItem * menuItem = nil; menuItem = [NSMenuItem separatorItem]; NSMenu * wParent; bResult = stack.viewTop((void **)&wParent); UT_ASSERT(bResult); [wParent addItem:menuItem]; _wd * wd = new _wd (this, pLayoutItem->getMenuId(), menuItem); [menuItem setTag:(int)wd]; // item is created, add to class vector m_vecMenuWidgets.addItem(wd); break; } case EV_MLF_BeginPopupMenu: case EV_MLF_EndPopupMenu: m_vecMenuWidgets.addItem(NULL); // reserve slot in vector so indexes will be in sync break; default: UT_ASSERT(0); break; } } [conn release]; // make sure our last item on the stack is the one we started with NSMenu * wDbg = NULL; bResult = stack.pop((void **)&wDbg); UT_ASSERT(bResult); UT_ASSERT(wDbg == wMenuRoot); return true; } bool EV_CocoaMenu::_refreshMenu(AV_View * pView, NSMenu * wMenuRoot) { // update the status of stateful items on menu bar. const EV_Menu_ActionSet * pMenuActionSet = m_pCocoaApp->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 menuid = pLayoutItem->getMenuId(); const EV_Menu_Action * pAction = pMenuActionSet->getAction(menuid); const EV_Menu_Label * pLabel = m_pMenuLabelSet->getLabel(menuid); 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 = getLabelName(m_pCocoaApp, m_pCocoaFrame, pAction, pLabel); const char * szLabelName = data[0]; // First we check to make sure the item exists. If it does not, // we create it and continue on. UT_ASSERT(UT_NOT_IMPLEMENTED); #if 0 GList * testchildren = gtk_container_children(GTK_CONTAINER(m_vecMenuWidgets.getNthItem(k))); if (!testchildren) { // This should be the only place refreshMenu touches // callback hooks, since this handles the case a widget doesn't // exist for a given layout item if (szLabelName && *szLabelName) { // find parent menu item GtkWidget * wParent; bResult = stack.viewTop((void **)&wParent); UT_ASSERT(bResult); char labelbuf[1024]; // convert label into underscored version _ev_convert(labelbuf, szLabelName); // create a label GtkLabel * label = GTK_LABEL(gtk_accel_label_new("SHOULD NOT APPEAR")); UT_ASSERT(label); // get a newly padded underscore version char * padString = _ev_skip_first_underscore_pad_rest(labelbuf); UT_ASSERT(padString); gtk_label_parse_uline(GTK_LABEL(label), padString); FREEP(padString); // create the item with the underscored label GtkWidget * w = gtk_menu_item_new(); UT_ASSERT(w); // show and add the label to our menu item gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(label)); gtk_accel_label_set_accel_widget(GTK_ACCEL_LABEL(label), w); gtk_widget_show(GTK_WIDGET(label)); gtk_widget_show(w); // set menu data to relate to class gtk_object_set_user_data(GTK_OBJECT(w),this); // create callback info data for action handling _wd * wd = new _wd(this, id); UT_ASSERT(wd); // set parent data stuff gtk_object_set_data(GTK_OBJECT(wMenuRoot), szLabelName, w); // bury in parent gtk_menu_insert(GTK_MENU(GTK_MENU_ITEM(wParent)->submenu), w, nPositionInThisMenu); // connect callbacks gtk_signal_connect(GTK_OBJECT(w), "activate", GTK_SIGNAL_FUNC(_wd::s_onActivate), wd); gtk_signal_connect(GTK_OBJECT(w), "select", GTK_SIGNAL_FUNC(_wd::s_onMenuItemSelect), wd); gtk_signal_connect(GTK_OBJECT(w), "deselect", GTK_SIGNAL_FUNC(_wd::s_onMenuItemDeselect), wd); // we do NOT add a new item, we point the existing index at our new widget // (update the pointers) void ** old = NULL; if (m_vecMenuWidgets.setNthItem(k, w, old)) { UT_DEBUGMSG(("Could not update dynamic menu widget vector item %s.\n", k)); UT_ASSERT(0); } break; } else { // do not create a widget if the label is blank, it should not appear in the // menu } } #endif // No dynamic label, check/enable if (!pAction->hasDynamicLabel()) { // if no dynamic label, all we need to do // is enable/disable and/or check/uncheck it. NSMenuItem * item = (NSMenuItem *) m_vecMenuWidgets.getNthItem(k); UT_ASSERT(item); UT_ASSERT([item isKindOfClass:[NSMenuItem class]]); // all get the gray treatment [item setState:(bCheck ? NSOnState : NSOffState)]; [item setEnabled:(bEnable ? YES : NO)]; break; } // Get the item NSMenuItem * item = (NSMenuItem *) m_vecMenuWidgets.getNthItem(k); // if item is null, there is no widget for it, so ignore its attributes for // this pass if (!item) { break; } UT_ASSERT([item isKindOfClass:[NSMenuItem class]]); // Dynamic label, check for remove bool bRemoveIt = (!szLabelName || !*szLabelName); if (bRemoveIt) { NSMenu * parentMenu = [item menu]; [parentMenu removeItem:item]; // TODO check that we don't leak the menu item. I think it is autoreleased, but I'm not sure // 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 NSMenuItem * fakeItem = [[NSMenuItem alloc] init]; UT_ASSERT(fakeItem); void ** blah = NULL; if(m_vecMenuWidgets.setNthItem(k, fakeItem, blah)) { UT_DEBUGMSG(("Could not update dynamic menu widget vector item %s.\n", k)); UT_ASSERT(0); } break; } #if 0 // Dynamic label, check for add/change // We always change the labels every time, it's actually cheaper // than doing the test for conditional changes. // TODO : check that it is cheaper in Cocoa. Obj-C method call is expensive !! -- Hub { // Get a list of children. If there are any, destroy them GList * children = gtk_container_children(GTK_CONTAINER(item)); if (children) { // Get the first item in the list GList * firstItem = g_list_first(children); UT_ASSERT(firstItem); // First item's data should be the label, since we added it first // in construction. GtkWidget * labelChild = GTK_WIDGET(firstItem->data); UT_ASSERT(labelChild); // destroy the current label gtk_container_remove(GTK_CONTAINER(item), labelChild); // unbind all accelerators gtk_widget_remove_accelerators(item, "activate_item", FALSE); //gtk_widget_destroy(labelChild); } // create a new updated label char labelbuf[1024]; // convert label into underscored version _ev_convert(labelbuf, szLabelName); // create a label GtkLabel * label = GTK_LABEL(gtk_accel_label_new("SHOULD NOT APPEAR")); UT_ASSERT(label); // get a newly padded underscore version char * padString = _ev_skip_first_underscore_pad_rest(labelbuf); UT_ASSERT(padString); guint keyCode = gtk_label_parse_uline(label, padString); FREEP(padString); // show and add the label to our menu item gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); gtk_container_add(GTK_CONTAINER(item), GTK_WIDGET(label)); gtk_accel_label_set_accel_widget(GTK_ACCEL_LABEL(label), item); gtk_widget_show(GTK_WIDGET(label)); // bind to parent item's accel group if ((keyCode != GDK_VoidSymbol))// && parent_accel_group) { gtk_widget_add_accelerator(item, "activate_item", GTK_MENU(item->parent)->accel_group, keyCode, 0, GTK_ACCEL_LOCKED); } // finally, enable/disable and/or check/uncheck it. if (GTK_IS_CHECK_MENU_ITEM(item)) GTK_CHECK_MENU_ITEM(item)->active = bCheck; gtk_widget_set_sensitive((GtkWidget *) item, bEnable); } #endif // we are done with this menu item } break; case EV_MLF_Separator: nPositionInThisMenu++; 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 NSMenu * item = (NSMenu *) m_vecMenuWidgets.getNthItem(k); UT_ASSERT(item); UT_ASSERT([item isKindOfClass:[NSMenu class]]); stack.push(item); break; } case EV_MLF_EndSubMenu: { NSMenu * item = NULL; bResult = stack.pop((void **)&item); UT_ASSERT(bResult); UT_ASSERT ([item isKindOfClass:[NSMenu class]]); break; } case EV_MLF_BeginPopupMenu: case EV_MLF_EndPopupMenu: break; default: UT_ASSERT(0); break; } } NSMenu * wDbg = NULL; bResult = stack.pop((void **)&wDbg); UT_ASSERT(bResult); UT_ASSERT(wDbg == wMenuRoot); return true; } /*! * That will add a new menu entry for the menu item at layout_pos. * * @param layout_pos UT_uint32 with the relative position of the item in the * menu. * @return true if there were no problems. False elsewere. */ bool EV_CocoaMenu::_doAddMenuItem(UT_uint32 layout_pos) { UT_DEBUGMSG(("JCA: layout_pos = [%d]\n", layout_pos)); if (layout_pos > 0) { UT_DEBUGMSG(("Trying to insert at [%d] in a vector of size [%d].\n", layout_pos, m_vecMenuWidgets.size())); UT_sint32 err = m_vecMenuWidgets.insertItemAt(NULL, layout_pos); if (err != 0) UT_DEBUGMSG(("Error [%d] inserting NULL item in a ut_vector.\n", err)); return (err == 0); } return false; } /* Strip the '&' from the label \param buf the result buffer \param bufSize the allocated size for buf \param label the label to convert */ void EV_CocoaMenu::_convertToMac (char * buf, size_t bufSize, const char * label) { UT_ASSERT(label && buf); UT_ASSERT(strlen (label) < bufSize); /* TODO: Handle charset conversion */ strcpy (buf, label); char * src, *dst; src = dst = buf; while (*src) { *dst = *src; src++; if (*dst != '&') dst++; } *dst = 0; } /*! Return the menu shortcut for the mnemonic \param mnemonic the string for the menmonic \returnvalue modifier the modifiers \returnvalue key a newly allocated NSString that contains the key equivalent. should be nil on entry. */ void EV_CocoaMenu::_getItemCmd (const char * mnemonic, unsigned int & modifiers, NSString * & key) { NSString * nsMnemonic; modifiers = 0; char * p; if (strstr (mnemonic, "Alt+")) { modifiers |= NSAlternateKeyMask; } else if (strstr (mnemonic, "Ctrl+") != NULL) { modifiers |= NSCommandKeyMask; } if ((modifiers & NSCommandKeyMask) == 0) { p = (char *)mnemonic; } else { p = strchr (mnemonic, '+'); p++; } nsMnemonic = [NSString stringWithCString:p]; // autoreleased key = [nsMnemonic lowercaseString]; } /*****************************************************************/ EV_CocoaMenuBar::EV_CocoaMenuBar(XAP_CocoaApp * pCocoaApp, XAP_CocoaFrame * pCocoaFrame, const char * szMenuLayoutName, const char * szMenuLabelSetName) : EV_CocoaMenu(pCocoaApp, pCocoaFrame, szMenuLayoutName, szMenuLabelSetName) { } EV_CocoaMenuBar::~EV_CocoaMenuBar() { } void EV_CocoaMenuBar::destroy(void) { } bool EV_CocoaMenuBar::synthesizeMenuBar(NSMenu *menu) { // Just create, don't show the menu bar yet. It is later added // to a 3D handle box and shown m_wMenuBar = menu; synthesizeMenu(m_wMenuBar); [[NSApplication sharedApplication] setMainMenu:m_wMenuBar]; return true; } bool EV_CocoaMenuBar::rebuildMenuBar() { UT_ASSERT (UT_NOT_IMPLEMENTED); return false; #if 0 GtkWidget * wVBox = m_pCocoaFrame->getVBoxWidget(); m_wHandleBox = gtk_handle_box_new(); UT_ASSERT(m_wHandleBox); // Just create, don't show the menu bar yet. It is later added // to a 3D handle box and shown m_wMenuBar = gtk_menu_bar_new(); synthesizeMenu(m_wMenuBar); // show up the properly connected menu structure gtk_widget_show(m_wMenuBar); // pack it in a handle box gtk_container_add(GTK_CONTAINER(m_wHandleBox), m_wMenuBar); gtk_widget_show(m_wHandleBox); // put it at position 1 in the vbox gtk_box_pack_start(GTK_BOX(wVBox), m_wHandleBox, FALSE, TRUE, 0); // was start gtk_box_reorder_child(GTK_BOX(wVBox), m_wHandleBox,0); return true; #endif } bool EV_CocoaMenuBar::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_CocoaMenuPopup::EV_CocoaMenuPopup(XAP_CocoaApp * pCocoaApp, XAP_CocoaFrame * pCocoaFrame, const char * szMenuLayoutName, const char * szMenuLabelSetName) : EV_CocoaMenu(pCocoaApp, pCocoaFrame, szMenuLayoutName, szMenuLabelSetName), m_wMenuPopup(nil) { } EV_CocoaMenuPopup::~EV_CocoaMenuPopup() { [m_wMenuPopup release]; } NSMenu * EV_CocoaMenuPopup::getMenuHandle() const { return m_wMenuPopup; } bool EV_CocoaMenuPopup::synthesizeMenuPopup() { m_wMenuPopup = [[NSMenu alloc] initWithTitle:@""]; [m_wMenuPopup setAutoenablesItems:NO]; synthesizeMenu(m_wMenuPopup); return true; } bool EV_CocoaMenuPopup::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; }