diff --git a/widget/src/mac/nsDynamicMDEF.cpp b/widget/src/mac/nsDynamicMDEF.cpp index 451bde4c068c..9d39e1fc2ce8 100644 --- a/widget/src/mac/nsDynamicMDEF.cpp +++ b/widget/src/mac/nsDynamicMDEF.cpp @@ -32,18 +32,17 @@ #include #include -extern nsIMenuBar * gMacMenubar; -extern Handle gSystemMDEFHandle; +extern nsWeakPtr gMacMenubar; +extern Handle gSystemMDEFHandle; #pragma options align=mac68k RoutineDescriptorPtr gOriginaldesc; RoutineDescriptorPtr gmdefUPP; // Caching the Mac menu -nsVoidArray gPreviousMenuHandleStack; -nsVoidArray gPreviousMenuStack; // Strong references kept! - -nsCOMPtr gPreviousMenuBar; +nsVoidArray gPreviousMenuHandleStack; // hold MenuHandles +nsMenuStack gPreviousMenuStack; // weak refs +nsWeakPtr gPreviousMenuBar; // weak ref MenuHandle gSizedMenu = nsnull; @@ -68,6 +67,58 @@ nsIMenu * gPreviousTopLevelMenu = nsnull; nsIMenu * gPreviousMenu = nsnull; MenuHandle gPreviousMenuHandle = nsnull; + +//------------------------------------------------------------------------------ + + +nsMenuStack::nsMenuStack() +{ +} + +nsMenuStack::~nsMenuStack() +{ +} + +nsresult +nsMenuStack::GetMenuAt(PRInt32 aIndex, nsIMenu **outMenu) +{ + nsCOMPtr elementPtr = getter_AddRefs(mMenuArray.ElementAt(aIndex)); + if (!elementPtr) + return NS_ERROR_NULL_POINTER; + + nsCOMPtr weakRef = do_QueryInterface(elementPtr); + return weakRef->QueryReferent(NS_GET_IID(nsIMenu), NS_REINTERPRET_CAST(void**, outMenu)); +} + +PRBool +nsMenuStack::HaveMenuAt(PRInt32 aIndex) +{ + nsCOMPtr elementPtr = getter_AddRefs(mMenuArray.ElementAt(aIndex)); + if (!elementPtr) + return NS_ERROR_NULL_POINTER; + + nsCOMPtr weakRef = do_QueryInterface(elementPtr); + nsCOMPtr theMenu = do_QueryReferent(weakRef); + return (theMenu.get() != nsnull); +} + +PRBool nsMenuStack::RemoveMenuAt(PRInt32 aIndex) +{ + return mMenuArray.RemoveElementAt(aIndex); +} + +PRBool nsMenuStack::InsertMenuAt(nsIMenu* inMenuItem, PRInt32 aIndex) +{ + nsCOMPtr weakRefFactory = do_QueryInterface(inMenuItem); + if (!weakRefFactory) return NS_ERROR_NULL_POINTER; + nsCOMPtr observerRef = getter_AddRefs(NS_STATIC_CAST(nsISupports*, NS_GetWeakReference(weakRefFactory))); + if (!observerRef) return NS_ERROR_NULL_POINTER; + return mMenuArray.InsertElementAt(observerRef, aIndex); +} + +#pragma mark - + + //------------------------------------------------------------------------------ // Internal functions @@ -129,7 +180,7 @@ pascal void nsDynamicMDEFMain( Rect * menuRect, Point hitPt, short * whichItem) -{ +{ switch (message) { case kMenuDrawMsg: //printf(" Draw passed in menu is = %d \n", *theMenu); @@ -157,44 +208,48 @@ pascal void nsDynamicMDEFMain( nsCheckDestroy(theMenu, whichItem); // Need to make sure that we rebuild the menu every time... -if (gPreviousMenuHandleStack.Count()) { - nsIMenu * menu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1]; - MenuHandle menuHandle = (MenuHandle) gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1]; - - //printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count()); - //printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count()); + if (gPreviousMenuHandleStack.Count()) + { + nsCOMPtr menu; + gPreviousMenuStack.GetMenuAt(gPreviousMenuStack.Count() - 1, getter_AddRefs(menu)); + // nsIMenu * menu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1]; + MenuHandle menuHandle = (MenuHandle) gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1]; + + //printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count()); + //printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count()); + + if( menu && menuHandle ) { + + if( menuHandle == theMenu ) { + + nsCOMPtr listener(do_QueryInterface(menu)); + if(listener) { + //printf("MenuPop \n"); + + nsMenuEvent mevent; + mevent.message = NS_MENU_SELECTED; + mevent.eventStructType = NS_MENU_EVENT; + mevent.point.x = 0; + mevent.point.y = 0; + mevent.widget = nsnull; + mevent.time = PR_IntervalNow(); + mevent.mCommand = (PRUint32) nsnull; + + // UNDO + listener->MenuDeselected(mevent); + + //gPreviousMenuStack.RemoveElementAt(gPreviousMenuStack.Count() - 1); + gPreviousMenuStack.RemoveMenuAt(gPreviousMenuStack.Count() - 1); + //NS_IF_RELEASE(menu); + + //printf("%d items now on gPreviousMenuStack \n", gPreviousMenuStack.Count()); + gPreviousMenuHandleStack.RemoveElementAt(gPreviousMenuHandleStack.Count() - 1); + + } + } + } + } - if( menu && menuHandle ) { - - if( menuHandle == theMenu ) { - - nsCOMPtr listener(do_QueryInterface(menu)); - if(listener) { - //printf("MenuPop \n"); - - nsMenuEvent mevent; - mevent.message = NS_MENU_SELECTED; - mevent.eventStructType = NS_MENU_EVENT; - mevent.point.x = 0; - mevent.point.y = 0; - mevent.widget = nsnull; - mevent.time = PR_IntervalNow(); - mevent.mCommand = (PRUint32) nsnull; - - // UNDO - listener->MenuDeselected(mevent); - - gPreviousMenuStack.RemoveElementAt(gPreviousMenuStack.Count() - 1); - NS_IF_RELEASE(menu); - - //printf("%d items now on gPreviousMenuStack \n", gPreviousMenuStack.Count()); - gPreviousMenuHandleStack.RemoveElementAt(gPreviousMenuHandleStack.Count() - 1); - - } - } - } - } - nsDynamicSizeTheMenu(theMenu); break; } @@ -205,7 +260,7 @@ if (gPreviousMenuHandleStack.Count()) { SInt8 state = ::HGetState((Handle)theMenu); HLock((Handle)theMenu); (**theMenu).menuWidth = -1; - (**theMenu).menuHeight = -1; + (**theMenu).menuHeight = -1; HSetState((Handle)theMenu, state); } } @@ -285,8 +340,9 @@ void nsDoMagic(MenuHandle theMenu) // ask if this is a child of the previous menu PRBool isChild = PR_FALSE; - if(gPreviousMenuStack.Count() > 0) { - if(gPreviousMenuStack[gPreviousMenuStack.Count() - 1]) { + if (gPreviousMenuStack.Count() > 0) + { + if (gPreviousMenuStack.HaveMenuAt(gPreviousMenuStack.Count() - 1)) { if(nsIsHierChild(theMenu)) { isChild = PR_TRUE; } @@ -304,7 +360,7 @@ void nsDoMagic(MenuHandle theMenu) } else { gCurrentMenuDepth = 1; } - + nsBuildMenu(theMenu, isChild); } @@ -312,9 +368,8 @@ void nsDoMagic(MenuHandle theMenu) void nsBuildMenu(MenuHandle theMenu, PRBool isChild) { // printf("enter BuildMenu \n"); - nsIMenuBar * menubar = gMacMenubar; // Global for current menubar - - if(!menubar || !theMenu) { + nsCOMPtr menubar = do_QueryReferent(gMacMenubar); + if (!menubar || !theMenu) { return; } @@ -329,25 +384,25 @@ void nsBuildMenu(MenuHandle theMenu, PRBool isChild) // If toplevel if( gCurrentMenuDepth < 2 ) { - PRUint32 numMenus = 0; - menubar->GetMenuCount(numMenus); - numMenus--; - for(PRInt32 i = numMenus; i >= 0; i--) { - nsCOMPtr menu; - menubar->GetMenuAt(i, *getter_AddRefs(menu)); - if(menu) { - nsCOMPtr listener(do_QueryInterface(menu)); - if(listener) { - // Reset menu depth count - gMenuDepth = 0; - nsEventStatus status = listener->MenuSelected(mevent); - if(status != nsEventStatus_eIgnore) { - + PRUint32 numMenus = 0; + menubar->GetMenuCount(numMenus); + numMenus--; + for(PRInt32 i = numMenus; i >= 0; i--) { + nsCOMPtr menu; + menubar->GetMenuAt(i, *getter_AddRefs(menu)); + if(menu) { + nsCOMPtr listener(do_QueryInterface(menu)); + if(listener) { + // Reset menu depth count + gMenuDepth = 0; + nsEventStatus status = listener->MenuSelected(mevent); + if(status != nsEventStatus_eIgnore) + { nsPostBuild(menu, theMenu, isChild); - gPreviousTopLevelMenuHandle = theMenu; - gPreviousTopLevelMenu = menu; - gPreviousMenuBar = menubar; - + gPreviousTopLevelMenuHandle = theMenu; + gPreviousTopLevelMenu = menu; + + gPreviousMenuBar = getter_AddRefs(NS_GetWeakReference(menubar)); //printf("exit BuildMenu \n"); return; } @@ -358,24 +413,30 @@ void nsBuildMenu(MenuHandle theMenu, PRBool isChild) // Not top level, so we can't use recursive MenuSelect // We must use the previously chosen menu item in combination // with the current menu to determine what menu needs to be constructed - nsISupports * supports = nsnull; - //printf("gCurrentMenuItem = %d \n", gCurrentMenuItem); - if(gCurrentMenuItem) { - if(gPreviousMenuStack.Count() > 0) { - nsIMenu * prevMenu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1]; + //printf("gCurrentMenuItem = %d \n", gCurrentMenuItem); + if (gCurrentMenuItem){ + if (gPreviousMenuStack.Count() > 0) + { + nsCOMPtr prevMenu; + gPreviousMenuStack.GetMenuAt(gPreviousMenuStack.Count() - 1, getter_AddRefs(prevMenu)); + + //nsIMenu * prevMenu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1]; //printf("gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count() ); - if(prevMenu) { - prevMenu->GetItemAt(gCurrentMenuItem - 1, supports); - nsCOMPtr menu(do_QueryInterface(supports)); - if(menu) { - nsCOMPtr menulistener(do_QueryInterface(supports)); - menulistener->MenuSelected(mevent); - nsPostBuild(menu, theMenu, isChild); - } - } - } - } + if(prevMenu) + { + nsCOMPtr supports; + prevMenu->GetItemAt(gCurrentMenuItem - 1, *getter_AddRefs(supports)); + nsCOMPtr menu = do_QueryInterface(supports); + if (menu) + { + nsCOMPtr menulistener = do_QueryInterface(menu); + menulistener->MenuSelected(mevent); + nsPostBuild(menu, theMenu, isChild); + } + } + } + } } //printf("exit BuildMenu \n"); } @@ -383,15 +444,13 @@ void nsBuildMenu(MenuHandle theMenu, PRBool isChild) //------------------------------------------------------------------------------ void nsPostBuild(nsIMenu * menu, MenuHandle theMenu, PRBool isChild) { - // it is built now - if(isChild || (gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1] != theMenu)) { - nsPushMenu(menu); - NS_IF_ADDREF(menu); - - nsPushMenuHandle(theMenu); - - //printf("Push: %d items in gMenuHandleStack \n", gMenuHandleStack.Count()); - } + // it is built now + if(isChild || (gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1] != theMenu)) + { + nsPushMenu(menu); + nsPushMenuHandle(theMenu); + //printf("Push: %d items in gMenuHandleStack \n", gMenuHandleStack.Count()); + } } //------------------------------------------------------------------------------ @@ -402,92 +461,112 @@ void nsCallSystemMDEF( Point hitPt, short * whichItem) { - SInt8 state = ::HGetState(gSystemMDEFHandle); - ::HLock(gSystemMDEFHandle); + SInt8 state = ::HGetState(gSystemMDEFHandle); + ::HLock(gSystemMDEFHandle); - gmdefUPP = ::NewRoutineDescriptor( (ProcPtr)*gSystemMDEFHandle, uppMenuDefProcInfo, kM68kISA); + gmdefUPP = ::NewRoutineDescriptor( (ProcPtr)*gSystemMDEFHandle, uppMenuDefProcInfo, kM68kISA); - CallMenuDefProc( - gmdefUPP, - message, - theMenu, - menuRect, - hitPt, - whichItem); + CallMenuDefProc( + gmdefUPP, + message, + theMenu, + menuRect, + hitPt, + whichItem); - ::DisposeRoutineDescriptor(gmdefUPP); - ::HSetState(gSystemMDEFHandle, state); + ::DisposeRoutineDescriptor(gmdefUPP); + ::HSetState(gSystemMDEFHandle, state); - return; + return; } //------------------------------------------------------------------------------ -void nsPushMenu(nsIMenu * aMenu) +void nsPushMenu(nsIMenu *aMenu) { - gPreviousMenuStack.InsertElementAt(aMenu, gPreviousMenuStack.Count()); + gPreviousMenuStack.InsertMenuAt(aMenu, gPreviousMenuStack.Count()); } //------------------------------------------------------------------------------ void nsPopMenu(nsIMenu ** aMenu) { - if(gPreviousMenuStack.Count() > 0) { - *aMenu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1]; - gPreviousMenuStack.RemoveElementAt(gPreviousMenuStack.Count() - 1); + if(gPreviousMenuStack.Count() > 0) + { + // *aMenu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1]; + gPreviousMenuStack.GetMenuAt(gPreviousMenuStack.Count() - 1, aMenu); + gPreviousMenuStack.RemoveMenuAt(gPreviousMenuStack.Count() - 1); } else *aMenu = nsnull; -} + } //------------------------------------------------------------------------------ void nsPreviousMenuStackUnwind(nsIMenu * aMenuJustBuilt, MenuHandle aMenuHandleJustBuilt) { - PRBool shouldReleaseMenubar = PR_FALSE; + //PRBool shouldReleaseMenubar = PR_FALSE; //printf("PreviousMenuStackUnwind called \n"); //printf("%d items on gPreviousMenuStack \n", gPreviousMenuStack.Count()); - while (gPreviousMenuHandleStack.Count()) { - nsIMenu * menu = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1]; + while (gPreviousMenuHandleStack.Count()) + { + nsCOMPtr menu; // = (nsIMenu *) gPreviousMenuStack[gPreviousMenuStack.Count() - 1]; + gPreviousMenuStack.GetMenuAt(gPreviousMenuStack.Count() - 1, getter_AddRefs(menu)); + MenuHandle menuHandle = (MenuHandle) gPreviousMenuHandleStack[gPreviousMenuHandleStack.Count() - 1]; - //printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count()); - //printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count()); - - if( menu && menuHandle ) { + if (menu) + { - if( menuHandle != aMenuHandleJustBuilt ) { - nsCOMPtr listener(do_QueryInterface(menu)); - if(listener) { - nsMenuEvent mevent; - mevent.message = NS_MENU_SELECTED; - mevent.eventStructType = NS_MENU_EVENT; - mevent.point.x = 0; - mevent.point.y = 0; - mevent.widget = nsnull; - mevent.time = PR_IntervalNow(); - mevent.mCommand = (PRUint32) nsnull; - - // UNDO - listener->MenuDeselected(mevent); - - gPreviousMenuStack.RemoveElementAt(gPreviousMenuStack.Count() - 1); - NS_IF_RELEASE(menu); - shouldReleaseMenubar = PR_TRUE; - - //printf("%d items now on gPreviousMenuStack \n", gPreviousMenuStack.Count()); - gPreviousMenuHandleStack.RemoveElementAt(gPreviousMenuHandleStack.Count() - 1); + //printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count()); + //printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count()); + + if( menuHandle ) { + + if( menuHandle != aMenuHandleJustBuilt ) { + nsCOMPtr listener(do_QueryInterface(menu)); + if(listener) { + nsMenuEvent mevent; + mevent.message = NS_MENU_SELECTED; + mevent.eventStructType = NS_MENU_EVENT; + mevent.point.x = 0; + mevent.point.y = 0; + mevent.widget = nsnull; + mevent.time = PR_IntervalNow(); + mevent.mCommand = (PRUint32) nsnull; + + // UNDO + listener->MenuDeselected(mevent); + + //gPreviousMenuStack.RemoveElementAt(gPreviousMenuStack.Count() - 1); + gPreviousMenuStack.RemoveMenuAt(gPreviousMenuStack.Count() - 1); + // NS_IF_RELEASE(menu); + //shouldReleaseMenubar = PR_TRUE; + + //printf("%d items now on gPreviousMenuStack \n", gPreviousMenuStack.Count()); + gPreviousMenuHandleStack.RemoveElementAt(gPreviousMenuHandleStack.Count() - 1); + } + } + else { + //printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count()); + //printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count()); + + // we are the aMenuHandleJustBuilt + return; } - } - else { - //printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count()); - //printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count()); - return; - } - } + } + } + else + { + // remove the weak ref + gPreviousMenuStack.RemoveMenuAt(gPreviousMenuStack.Count() - 1); + NS_ASSERTION(menuHandle != aMenuHandleJustBuilt, "Got the menu handle just built"); + if( menuHandle ) + gPreviousMenuHandleStack.RemoveElementAt(gPreviousMenuHandleStack.Count() - 1); + } } // relinquish hold of the menubar _after_ releasing the menu so it can finish // unregistering itself. - if ( shouldReleaseMenubar ) - gPreviousMenuBar = nsnull; + //if ( shouldReleaseMenubar ) + // gPreviousMenuBar = nsnull; //printf(" gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count()); //printf(" gPreviousMenuHandleStack.Count() = %d \n", gPreviousMenuHandleStack.Count()); diff --git a/widget/src/mac/nsDynamicMDEF.h b/widget/src/mac/nsDynamicMDEF.h index 7a29b0713871..16e7f59dedb8 100644 --- a/widget/src/mac/nsDynamicMDEF.h +++ b/widget/src/mac/nsDynamicMDEF.h @@ -25,7 +25,9 @@ #ifndef nsDynamicMDEF_h__ #define nsDynamicMDEF_h__ +#include "nsSupportsArray.h" #include "nsIMenu.h" + #include pascal void nsDynamicMDEFMain( @@ -40,4 +42,69 @@ void nsPreviousMenuStackUnwind( MenuHandle aMenuHandleJustBuilt); +// helper class useful for counting instances +class nsInstanceCounter +{ +public: + nsInstanceCounter(const char* inDesc) + : mInstanceCount(0) + , mDescription(inDesc) + { + } + + ~nsInstanceCounter() + { + printf("%s %ld\n", mDescription, mInstanceCount); + } + + nsInstanceCounter& operator ++() // prefix + { + ++ mInstanceCount; + return *this; + } + + nsInstanceCounter& operator -- () // prefix + { + -- mInstanceCount; + return *this; + } + +protected: + + PRInt32 mInstanceCount; + const char* mDescription; + +}; + + +//------------------------------------------------------------------------------ + +class nsMenuStack +{ +public: + nsMenuStack(); + ~nsMenuStack(); + + + PRInt32 Count() + { + PRUint32 num; + mMenuArray.Count(&num); + return (PRInt32)num; + } + + // returns addreffed nsIMenu + nsresult GetMenuAt(PRInt32 aIndex, nsIMenu **outMenu); + PRBool HaveMenuAt(PRInt32 aIndex); + PRBool RemoveMenuAt(PRInt32 aIndex); // no release + PRBool InsertMenuAt(nsIMenu* aElement, PRInt32 aIndex); // no addrefs; weak ref. + +protected: + + nsSupportsArray mMenuArray; // array of weak refs to nsIMenus + +}; + + + #endif nsDynamicMDEF_h__ \ No newline at end of file diff --git a/widget/src/mac/nsMenu.cpp b/widget/src/mac/nsMenu.cpp index bc2885dfd2ef..1647814dea69 100644 --- a/widget/src/mac/nsMenu.cpp +++ b/widget/src/mac/nsMenu.cpp @@ -30,6 +30,7 @@ #include "nsIDocShell.h" #include "nsMenu.h" +#include "nsMenubar.h" #include "nsIMenu.h" #include "nsIMenuBar.h" #include "nsIMenuItem.h" @@ -61,22 +62,40 @@ const PRInt16 kAppleMenuID = 1; PRInt16 gMenuDepth = 0; PRInt16 gCurrentMenuDepth = 1; -extern nsIMenuBar * gMacMenubar; extern Handle gMDEF; // Our stub MDEF extern Handle gSystemMDEFHandle; PRInt16 mMacMenuIDCount = kMacMenuID; static PRBool gConstructingMenu = PR_FALSE; +#if DEBUG +nsInstanceCounter gMenuCounter("nsMenu"); +#endif + // CIDs #include "nsWidgetsCID.h" static NS_DEFINE_CID(kMenuBarCID, NS_MENUBAR_CID); static NS_DEFINE_CID(kMenuCID, NS_MENU_CID); static NS_DEFINE_CID(kMenuItemCID, NS_MENUITEM_CID); -//------------------------------------------------------------------------- -NS_IMPL_ISUPPORTS3(nsMenu, nsIMenu, nsIMenuListener, nsIChangeObserver) +// Refcounted class for dummy menu items, like separators and help menu items. +class nsDummyMenuItem : public nsISupports +{ +public: + + NS_DECL_ISUPPORTS + + nsDummyMenuItem() + { + NS_INIT_REFCNT(); + } +}; + +NS_IMPL_ISUPPORTS0(nsDummyMenuItem); + +//------------------------------------------------------------------------- +NS_IMPL_ISUPPORTS4(nsMenu, nsIMenu, nsIMenuListener, nsIChangeObserver, nsISupportsWeakReference) // // nsMenu constructor @@ -94,14 +113,9 @@ nsMenu::nsMenu() mIsHelpMenu = PR_FALSE; mHelpMenuOSItemsCount = 0; mIsEnabled = PR_TRUE; - mListener = nsnull; mConstructed = nsnull; mDestroyHandlerCalled = PR_FALSE; - - mDOMNode = nsnull; - mDOMElement = nsnull; - mWebShell = nsnull; - + // // create a multi-destination Unicode converter which can handle all of the installed // script systems @@ -128,6 +142,9 @@ nsMenu::nsMenu() OSErr err = ::CreateUnicodeToTextRunInfoByScriptCode(0x80000000,ps,&mUnicodeTextRunConverter); NS_ASSERTION(err==noErr,"nsMenu::nsMenu: CreateUnicodeToTextRunInfoByScriptCode failed."); +#if DEBUG + ++gMenuCounter; +#endif } @@ -136,14 +153,9 @@ nsMenu::nsMenu() // nsMenu::~nsMenu() { - //printf("nsMenu::~nsMenu() called \n"); - - OSErr err; - NS_IF_RELEASE(mListener); - RemoveAll(); - err = ::DisposeUnicodeToTextRunInfo(&mUnicodeTextRunConverter); + OSErr err = ::DisposeUnicodeToTextRunInfo(&mUnicodeTextRunConverter); NS_ASSERTION(err==noErr,"nsMenu::~nsMenu: DisposeUnicodeToTextRunInfo failed."); // Don't destroy the 4 Golden Hierarchical Menu @@ -153,10 +165,12 @@ nsMenu::~nsMenu() } // alert the change notifier we don't care no more - nsCOMPtr content ( do_QueryInterface(mDOMNode) ); - mManager->Unregister ( content ); - - mDOMNode = nsnull; + nsCOMPtr content = do_QueryInterface(mDOMNode); + mManager->Unregister(content); + +#if DEBUG + --gMenuCounter; +#endif } @@ -164,39 +178,37 @@ nsMenu::~nsMenu() // Create // NS_METHOD -nsMenu :: Create ( nsISupports * aParent, const nsString &aLabel, const nsString &aAccessKey, +nsMenu::Create( nsISupports * aParent, const nsString &aLabel, const nsString &aAccessKey, nsIChangeManager* aManager, nsIWebShell* aShell, nsIDOMNode* aNode ) { - mWebShell = aShell; - mDOMNode = aNode; - mDOMElement = do_QueryInterface ( aNode ); + mWebShellWeakRef = getter_AddRefs(NS_GetWeakReference(aShell)); + mDOMNode = aNode; // strong ref // register this menu to be notified when changes are made to our content object - mManager = aManager; - nsCOMPtr content ( do_QueryInterface(aNode) ); - nsCOMPtr changeObs ( do_QueryInterface(NS_STATIC_CAST(nsIChangeObserver*,this)) ); - mManager->Register ( content, changeObs ); + mManager = aManager; // weak ref + nsCOMPtr content (do_QueryInterface(aNode)); + nsCOMPtr changeObs ( do_QueryInterface(NS_STATIC_CAST(nsIChangeObserver*, this)) ); + mManager->Register(content, changeObs); NS_ASSERTION ( mDOMNode, "Menu not given a dom node at creation time" ); - NS_ASSERTION ( mDOMElement, "Unable to convert from DOMNode to DOMElement" ); NS_ASSERTION ( mManager, "No change manager given, can't tell content model updates" ); // our parent could be either a menu bar (if we're toplevel) or a menu (if we're a submenu) - if ( aParent ) { - nsCOMPtr menubar ( do_QueryInterface(aParent) ); - if ( menubar ) - mMenuBarParent = menubar; + if (aParent) { + nsCOMPtr menubar = do_QueryInterface(aParent); + if (menubar) + mMenuBarParent = menubar; // weak ref else { - nsCOMPtr menu ( do_QueryInterface(aParent) ); - if ( menu ) - mMenuParent = menu; + nsCOMPtr menu = do_QueryInterface(aParent); + if (menu) + mMenuParent = menu; // weak ref } } - NS_ASSERTION ( mMenuParent || mMenuBarParent, "Menu parent not a menu bar or menu!" ); + NS_ASSERTION( mMenuParent || mMenuBarParent, "Menu parent not a menu bar or menu!" ); - SetLabel ( aLabel ); - SetAccessKey ( aAccessKey ); + SetLabel(aLabel); + SetAccessKey(aAccessKey); return NS_OK; } @@ -205,9 +217,9 @@ nsMenu :: Create ( nsISupports * aParent, const nsString &aLabel, const nsString NS_METHOD nsMenu::GetParent(nsISupports*& aParent) { aParent = nsnull; - if ( mMenuParent ) + if (mMenuParent) return mMenuParent->QueryInterface(NS_GET_IID(nsISupports),(void**)&aParent); - else if ( mMenuBarParent ) + else if (mMenuBarParent) return mMenuBarParent->QueryInterface(NS_GET_IID(nsISupports),(void**)&aParent); return NS_ERROR_FAILURE; @@ -239,23 +251,26 @@ NS_METHOD nsMenu::SetLabel(const nsString &aText) } else { #if !TARGET_CARBON // Look at the label and figure out if it is the "Help" menu - - if(mDOMElement) { - nsString menuIDstring; - mDOMElement->GetAttribute(NS_ConvertASCIItoUCS2("id"), menuIDstring); - if(menuIDstring.EqualsWithConversion("menu_Help")) { - mIsHelpMenu = PR_TRUE; - ::HMGetHelpMenuHandle(&mMacMenuHandle); - mMacMenuID = kHMHelpMenuID; + nsCOMPtr domElement = do_QueryInterface(mDOMNode); + if(domElement) { + nsAutoString menuIDstring; + domElement->GetAttribute(NS_ConvertASCIItoUCS2("id"), menuIDstring); + if(menuIDstring.EqualsWithConversion("menu_Help")) + { + mIsHelpMenu = PR_TRUE; + ::HMGetHelpMenuHandle(&mMacMenuHandle); + mMacMenuID = kHMHelpMenuID; - int numHelpItems = ::CountMenuItems(mMacMenuHandle); - if ( mHelpMenuOSItemsCount == 0) + int numHelpItems = ::CountMenuItems(mMacMenuHandle); + if (mHelpMenuOSItemsCount == 0) mHelpMenuOSItemsCount = numHelpItems; - for(int i=0; i menuitem ( do_QueryInterface(aItem) ); - if ( menuitem ) + nsCOMPtr menuitem(do_QueryInterface(aItem)); + if (menuitem) { AddMenuItem(menuitem); - else { - nsCOMPtr menu ( do_QueryInterface(aItem) ); - if ( menu ) + } else { + nsCOMPtr menu(do_QueryInterface(aItem)); + if (menu) AddMenu(menu); } } @@ -316,71 +331,67 @@ NS_METHOD nsMenu::AddItem(nsISupports* aItem) //------------------------------------------------------------------------- NS_METHOD nsMenu::AddMenuItem(nsIMenuItem * aMenuItem) { - if(aMenuItem) { - nsISupports * supports = nsnull; - aMenuItem->QueryInterface(NS_GET_IID(nsISupports), (void**)&supports); - if(supports) { - mMenuItemVoidArray.AppendElement(supports); - PRInt32 currItemIndex = mMenuItemVoidArray.Count(); - - nsString label; - aMenuItem->GetLabel(label); - //printf("%s \n", label.ToNewCString()); - //printf("%d = mMacMenuID\n", mMacMenuID); - mNumMenuItems++; - - if(mIsHelpMenu) { - ::InsertMenuItem(mMacMenuHandle, "\pa", mMenuItemVoidArray.Count()); - NSStringSetMenuItemText(mMacMenuHandle, mMenuItemVoidArray.Count(), label); - } else { - ::InsertMenuItem(mMacMenuHandle, "\pa", currItemIndex); - NSStringSetMenuItemText(mMacMenuHandle, currItemIndex, label); - } + if(!aMenuItem) return NS_ERROR_NULL_POINTER; + + nsCOMPtr supports = do_QueryInterface(aMenuItem); + if (!supports) return NS_ERROR_NO_INTERFACE; + + mMenuItemsArray.AppendElement(supports); // owning ref + PRUint32 currItemIndex; + mMenuItemsArray.Count(&currItemIndex); + + mNumMenuItems++; + + nsAutoString label; + aMenuItem->GetLabel(label); + //printf("%s \n", label.ToNewCString()); + //printf("%d = mMacMenuID\n", mMacMenuID); + ::InsertMenuItem(mMacMenuHandle, "\p(Blank menu item", currItemIndex); + NSStringSetMenuItemText(mMacMenuHandle, currItemIndex, label); // I want to be internationalized too! - nsString keyEquivalent; keyEquivalent.AssignWithConversion(" "); - aMenuItem->GetShortcutChar(keyEquivalent); - if(!keyEquivalent.EqualsWithConversion(" ")) { - keyEquivalent.ToUpperCase(); - char keyStr[2]; - keyEquivalent.ToCString(keyStr, sizeof(keyStr)); - short inKey = keyStr[0]; - ::SetItemCmd(mMacMenuHandle, currItemIndex, inKey); - //::SetMenuItemKeyGlyph(mMacMenuHandle, mNumMenuItems, 0x61); - } - - PRUint8 modifiers; - aMenuItem->GetModifiers(&modifiers); - PRUint8 macModifiers = kMenuNoModifiers; - if(knsMenuItemShiftModifier & modifiers) - macModifiers |= kMenuShiftModifier; - - if(knsMenuItemAltModifier & modifiers) - macModifiers |= kMenuOptionModifier; - - if(knsMenuItemControlModifier & modifiers) - macModifiers |= kMenuControlModifier; - - if(!(knsMenuItemCommandModifier & modifiers)) - macModifiers |= kMenuNoCommandModifier; - - ::SetMenuItemModifiers(mMacMenuHandle, currItemIndex, macModifiers); - - PRBool isEnabled; - aMenuItem->GetEnabled(&isEnabled); - if(isEnabled) - ::EnableMenuItem(mMacMenuHandle, currItemIndex); - else - ::DisableMenuItem(mMacMenuHandle, currItemIndex); - - PRBool isChecked; - aMenuItem->GetChecked(&isChecked); - if(isChecked) - ::CheckMenuItem(mMacMenuHandle, currItemIndex, true); - else - ::CheckMenuItem(mMacMenuHandle, currItemIndex, false); - } + nsAutoString keyEquivalent; keyEquivalent.AssignWithConversion(" "); + aMenuItem->GetShortcutChar(keyEquivalent); + if(!keyEquivalent.EqualsWithConversion(" ")) { + keyEquivalent.ToUpperCase(); + char keyStr[2]; + keyEquivalent.ToCString(keyStr, sizeof(keyStr)); + short inKey = keyStr[0]; + ::SetItemCmd(mMacMenuHandle, currItemIndex, inKey); + //::SetMenuItemKeyGlyph(mMacMenuHandle, mNumMenuItems, 0x61); } + + PRUint8 modifiers; + aMenuItem->GetModifiers(&modifiers); + PRUint8 macModifiers = kMenuNoModifiers; + if(knsMenuItemShiftModifier & modifiers) + macModifiers |= kMenuShiftModifier; + + if(knsMenuItemAltModifier & modifiers) + macModifiers |= kMenuOptionModifier; + + if(knsMenuItemControlModifier & modifiers) + macModifiers |= kMenuControlModifier; + + if(!(knsMenuItemCommandModifier & modifiers)) + macModifiers |= kMenuNoCommandModifier; + + ::SetMenuItemModifiers(mMacMenuHandle, currItemIndex, macModifiers); + + PRBool isEnabled; + aMenuItem->GetEnabled(&isEnabled); + if(isEnabled) + ::EnableMenuItem(mMacMenuHandle, currItemIndex); + else + ::DisableMenuItem(mMacMenuHandle, currItemIndex); + + PRBool isChecked; + aMenuItem->GetChecked(&isChecked); + if(isChecked) + ::CheckMenuItem(mMacMenuHandle, currItemIndex, true); + else + ::CheckMenuItem(mMacMenuHandle, currItemIndex, false); + return NS_OK; } @@ -388,33 +399,35 @@ NS_METHOD nsMenu::AddMenuItem(nsIMenuItem * aMenuItem) NS_METHOD nsMenu::AddMenu(nsIMenu * aMenu) { // Add a submenu - if(aMenu) { - nsISupports * supports = nsnull; - aMenu->QueryInterface(NS_GET_IID(nsISupports), (void**)&supports); - if(supports) { - mMenuItemVoidArray.AppendElement(supports); - PRInt32 currItemIndex = mMenuItemVoidArray.Count(); + if (!aMenu) return NS_ERROR_NULL_POINTER; - // We have to add it as a menu item and then associate it with the item - nsString label; - aMenu->GetLabel(label); - //printf("AddMenu %s \n", label.ToNewCString()); - mNumMenuItems++; + nsCOMPtr supports = do_QueryInterface(aMenu); + if (!supports) return NS_ERROR_NO_INTERFACE; - ::InsertMenuItem(mMacMenuHandle, "\pb", currItemIndex); - NSStringSetMenuItemText(mMacMenuHandle, currItemIndex, label); + mMenuItemsArray.AppendElement(supports); // owning ref + PRUint32 currItemIndex; + mMenuItemsArray.Count(&currItemIndex); + + mNumMenuItems++; + + // We have to add it as a menu item and then associate it with the item + nsAutoString label; + aMenu->GetLabel(label); + //printf("AddMenu %s \n", label.ToNewCString()); + + ::InsertMenuItem(mMacMenuHandle, "\pb", currItemIndex); + NSStringSetMenuItemText(mMacMenuHandle, currItemIndex, label); + + PRBool isEnabled; + aMenu->GetEnabled(&isEnabled); + if(isEnabled) + ::EnableMenuItem(mMacMenuHandle, currItemIndex); + else + ::DisableMenuItem(mMacMenuHandle, currItemIndex); + + PRInt16 temp = gCurrentMenuDepth; + ::SetMenuItemHierarchicalID((MenuHandle) mMacMenuHandle, currItemIndex, temp); - PRBool isEnabled; - aMenu->GetEnabled(&isEnabled); - if(isEnabled) - ::EnableMenuItem(mMacMenuHandle, currItemIndex); - else - ::DisableMenuItem(mMacMenuHandle, currItemIndex); - - PRInt16 temp = gCurrentMenuDepth; - ::SetMenuItemHierarchicalID((MenuHandle) mMacMenuHandle, currItemIndex, temp); - } - } return NS_OK; } @@ -423,8 +436,11 @@ NS_METHOD nsMenu::AddSeparator() { // HACK - We're not really appending an nsMenuItem but it // needs to be here to make sure that event dispatching isn't off by one. - mMenuItemVoidArray.AppendElement(nsnull); - ::InsertMenuItem(mMacMenuHandle, "\p(-", mMenuItemVoidArray.Count() ); + nsDummyMenuItem* dummyItem = new nsDummyMenuItem; + mMenuItemsArray.AppendElement(dummyItem); // owning ref + PRUint32 numItems; + mMenuItemsArray.Count(&numItems); + ::InsertMenuItem(mMacMenuHandle, "\p(-", numItems); mNumMenuItems++; return NS_OK; } @@ -432,25 +448,27 @@ NS_METHOD nsMenu::AddSeparator() //------------------------------------------------------------------------- NS_METHOD nsMenu::GetItemCount(PRUint32 &aCount) { - return NS_OK; + return mMenuItemsArray.Count(&aCount); } //------------------------------------------------------------------------- NS_METHOD nsMenu::GetItemAt(const PRUint32 aPos, nsISupports *& aMenuItem) { - aMenuItem = (nsISupports*) mMenuItemVoidArray[aPos]; + mMenuItemsArray.GetElementAt(aPos, &aMenuItem); return NS_OK; } //------------------------------------------------------------------------- NS_METHOD nsMenu::InsertItemAt(const PRUint32 aPos, nsISupports * aMenuItem) { + NS_ASSERTION(0, "Not implemented"); return NS_OK; } //------------------------------------------------------------------------- NS_METHOD nsMenu::RemoveItem(const PRUint32 aPos) { + NS_ASSERTION(0, "Not implemented"); return NS_OK; } @@ -466,39 +484,18 @@ NS_METHOD nsMenu::RemoveAll() #endif #endif - while(mMenuItemVoidArray.Count()) + PRUint32 curItem; + mMenuItemsArray.Count(&curItem); + while (curItem > 0) { - --mNumMenuItems; - - if(mMenuItemVoidArray[mMenuItemVoidArray.Count() - 1]) { - // Figure out what we're releasing - nsIMenuItem * menuitem = nsnull; - ((nsISupports*)mMenuItemVoidArray[mMenuItemVoidArray.Count() - 1])->QueryInterface(NS_GET_IID(nsIMenuItem), (void**) &menuitem); - if(menuitem) - { - // case menuitem - menuitem->Release(); // Release our hold - NS_IF_RELEASE(menuitem); // Balance QI - } - else - { - nsIMenu * menu = nsnull; - ((nsISupports*)mMenuItemVoidArray[mMenuItemVoidArray.Count() - 1])->QueryInterface(NS_GET_IID(nsIMenu), (void**) &menu); - if(menu) - { - // case menu - menu->Release(); // Release our hold - NS_IF_RELEASE(menu); // Balance QI - } - } - } /* don't delete the actual Mac menu item if it's a MacOS item */ - if ( (mMenuItemVoidArray.Count() - mHelpMenuOSItemsCount) > 0) - { - ::DeleteMenuItem(mMacMenuHandle, mMenuItemVoidArray.Count()); - } - mMenuItemVoidArray.RemoveElementAt(mMenuItemVoidArray.Count() - 1); + if (curItem > mHelpMenuOSItemsCount) + ::DeleteMenuItem(mMacMenuHandle, curItem); + + curItem --; } + + mMenuItemsArray.Clear(); // remove all items return NS_OK; } @@ -519,8 +516,7 @@ NS_METHOD nsMenu::SetNativeData(void * aData) //------------------------------------------------------------------------- NS_METHOD nsMenu::AddMenuListener(nsIMenuListener * aMenuListener) { - mListener = aMenuListener; - //NS_ADDREF(mListener); + mListener = aMenuListener; // strong ref return NS_OK; } @@ -528,7 +524,7 @@ NS_METHOD nsMenu::AddMenuListener(nsIMenuListener * aMenuListener) NS_METHOD nsMenu::RemoveMenuListener(nsIMenuListener * aMenuListener) { if (aMenuListener == mListener) { - //NS_IF_RELEASE(mListener); + mListener = nsnull; } return NS_OK; } @@ -566,58 +562,54 @@ nsEventStatus nsMenu::MenuItemSelected(const nsMenuEvent & aMenuEvent) /* handle about app here */ nsresult rv = NS_ERROR_FAILURE; - // Go find the about menu item - nsCOMPtr domDoc; - if (!mDOMNode) { - NS_ERROR("nsMenu mDOMNode is null."); - return nsEventStatus_eConsumeNoDefault; - } - mDOMNode->GetOwnerDocument(getter_AddRefs(domDoc)); - - if (!domDoc) { - NS_ERROR("No owner document for nsMenu DOM node."); - return nsEventStatus_eConsumeNoDefault; - } - nsCOMPtr xulDoc = do_QueryInterface(domDoc); - if (!xulDoc) { - NS_ERROR("nsIDOMDocument to nsIDOMXULDocument QI failed."); - return nsEventStatus_eConsumeNoDefault; - } - - // "releaseName" is the current node id for the About Mozilla/Netscape - // menu node. - nsCOMPtr domElement; - xulDoc->GetElementById(NS_ConvertASCIItoUCS2("releaseName"), getter_AddRefs(domElement)); - if (!domElement) { - NS_ERROR("GetElementById failed."); - return nsEventStatus_eConsumeNoDefault; - } - - // Now get the pres context so we can execute the command - nsCOMPtr presContext; - MenuHelpers::WebShellToPresContext ( mWebShell, getter_AddRefs(presContext) ); + // Go find the about menu item + if (!mDOMNode) { + NS_ERROR("nsMenu mDOMNode is null."); + return nsEventStatus_eConsumeNoDefault; + } + nsCOMPtr domDoc; + mDOMNode->GetOwnerDocument(getter_AddRefs(domDoc)); + if (!domDoc) { + NS_ERROR("No owner document for nsMenu DOM node."); + return nsEventStatus_eConsumeNoDefault; + } + nsCOMPtr xulDoc = do_QueryInterface(domDoc); + if (!xulDoc) { + NS_ERROR("nsIDOMDocument to nsIDOMXULDocument QI failed."); + return nsEventStatus_eConsumeNoDefault; + } + + // "releaseName" is the current node id for the About Mozilla/Netscape + // menu node. + nsCOMPtr domElement; + xulDoc->GetElementById(NS_ConvertASCIItoUCS2("releaseName"), getter_AddRefs(domElement)); + if (!domElement) { + NS_ERROR("GetElementById failed."); + return nsEventStatus_eConsumeNoDefault; + } + + // Now get the pres context so we can execute the command + nsCOMPtr presContext; + nsCOMPtr webShell = do_QueryReferent(mWebShellWeakRef); + if (!webShell) { + NS_ERROR("Webshell has gone away"); + return nsEventStatus_eConsumeNoDefault; + } + MenuHelpers::WebShellToPresContext(webShell, getter_AddRefs(presContext)); - nsEventStatus status = nsEventStatus_eIgnore; - nsMouseEvent event; - event.eventStructType = NS_MOUSE_EVENT; - event.message = NS_MENU_ACTION; + nsEventStatus status = nsEventStatus_eIgnore; + nsMouseEvent event; + event.eventStructType = NS_MOUSE_EVENT; + event.message = NS_MENU_ACTION; - nsCOMPtr element(do_QueryInterface(mDOMNode)); - if(!element) { - NS_ERROR("Unable to QI dom element."); - return nsEventStatus_eConsumeNoDefault; - } - - nsCOMPtr contentNode; - contentNode = do_QueryInterface(domElement); - if (!contentNode) { - NS_ERROR("DOM Node doesn't support the nsIContent interface required to handle DOM events."); - return nsEventStatus_eConsumeNoDefault; - } + nsCOMPtr contentNode = do_QueryInterface(mDOMNode); + if (!contentNode) { + NS_ERROR("DOM Node doesn't support the nsIContent interface required to handle DOM events."); + return nsEventStatus_eConsumeNoDefault; + } - rv = contentNode->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); - - return nsEventStatus_eConsumeNoDefault; + rv = contentNode->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); + return nsEventStatus_eConsumeNoDefault; } } else @@ -628,11 +620,11 @@ nsEventStatus nsMenu::MenuItemSelected(const nsMenuEvent & aMenuEvent) nsIMenuBar *mb = mMenuBarParent; if ( mb == nsnull ) { - mb = gMacMenubar; - if ( mb == nsnull ) - { + nsCOMPtr menuBar = do_QueryReferent(gMacMenubar); + if (!menuBar) return nsEventStatus_eIgnore; - } + + mb = menuBar; } /* set up a default event to query with */ @@ -652,72 +644,66 @@ nsEventStatus nsMenu::MenuItemSelected(const nsMenuEvent & aMenuEvent) { nsCOMPtr menu; mb->GetMenuAt(i, *getter_AddRefs(menu)); - if (menu) - { - nsCOMPtr listener(do_QueryInterface(menu)); - if (listener) + nsCOMPtr listener(do_QueryInterface(menu)); + if (listener) + { + nsAutoString label; + menu->GetLabel(label); + /* ask if this is the right menu */ + eventStatus = listener->MenuSelected(event); + if(eventStatus != nsEventStatus_eIgnore) { - nsString label; - menu->GetLabel(label); - /* ask if this is the right menu */ - eventStatus = listener->MenuSelected(event); - if(eventStatus != nsEventStatus_eIgnore) - { - // call our ondestroy handler now because the menu is going away. - // do it now before sending the event into the dom in case our window - // goes away. - OnDestroy(); - - /* call back into this method with the proper "this" */ - eventStatus = listener->MenuItemSelected(aMenuEvent); - return eventStatus; - } - } - } - } - } - else - - if(mMacMenuID == menuID) - { - // Call MenuItemSelected on the correct nsMenuItem - PRInt16 menuItemID = LoWord(((nsMenuEvent)aMenuEvent).mCommand); - if(mMenuItemVoidArray[menuItemID-1]) { - nsCOMPtr menuListener ( do_QueryInterface((nsIMenuItem*)mMenuItemVoidArray[menuItemID-1]) ); - if(menuListener) { - // call our ondestroy handler now because the menu is going away. - // do it now before sending the event into the dom in case our window - // goes away. - OnDestroy(); - - eventStatus = menuListener->MenuItemSelected(aMenuEvent); - if(nsEventStatus_eIgnore != eventStatus) - return eventStatus; - } - } - } - - // Make sure none of our submenus are the ones that should be handling this - for (int i = mMenuItemVoidArray.Count(); i > 0; i--) - { - if(nsnull != mMenuItemVoidArray[i-1]) - { - nsCOMPtr submenu ( do_QueryInterface((nsISupports*)mMenuItemVoidArray[i-1]) ); - if(submenu) - { - nsCOMPtr menuListener ( do_QueryInterface((nsISupports*)mMenuItemVoidArray[i-1]) ); - if(menuListener){ // call our ondestroy handler now because the menu is going away. // do it now before sending the event into the dom in case our window // goes away. OnDestroy(); - eventStatus = menuListener->MenuItemSelected(aMenuEvent); - if(nsEventStatus_eIgnore != eventStatus) - return eventStatus; - } - } - } + /* call back into this method with the proper "this" */ + eventStatus = listener->MenuItemSelected(aMenuEvent); + return eventStatus; + } + } + } + } + else if (mMacMenuID == menuID) + { + // Call MenuItemSelected on the correct nsMenuItem + PRInt16 menuItemID = LoWord(((nsMenuEvent)aMenuEvent).mCommand); + + nsCOMPtr menuSupports = getter_AddRefs(mMenuItemsArray.ElementAt(menuItemID - 1)); + nsCOMPtr menuListener = do_QueryInterface(menuSupports); + if (menuListener) + { + // call our ondestroy handler now because the menu is going away. + // do it now before sending the event into the dom in case our window + // goes away. + OnDestroy(); + + eventStatus = menuListener->MenuItemSelected(aMenuEvent); + if(nsEventStatus_eIgnore != eventStatus) + return eventStatus; + } + } + + // Make sure none of our submenus are the ones that should be handling this + PRUint32 numItems; + mMenuItemsArray.Count(&numItems); + for (PRUint32 i = numItems; i > 0; i--) + { + nsCOMPtr menuSupports = getter_AddRefs(mMenuItemsArray.ElementAt(i - 1)); + nsCOMPtr submenu = do_QueryInterface(menuSupports); + nsCOMPtr menuListener = do_QueryInterface(submenu); + if (menuListener) + { + // call our ondestroy handler now because the menu is going away. + // do it now before sending the event into the dom in case our window + // goes away. + OnDestroy(); + + eventStatus = menuListener->MenuItemSelected(aMenuEvent); + if(nsEventStatus_eIgnore != eventStatus) + return eventStatus; + } } return eventStatus; @@ -739,48 +725,46 @@ nsEventStatus nsMenu::MenuSelected(const nsMenuEvent & aMenuEvent) mConstructed = false; } - if(!mConstructed) { + if(!mConstructed) + { + nsCOMPtr webShell = do_QueryReferent(mWebShellWeakRef); + if (!webShell) { + NS_ERROR("No web shell"); + return nsEventStatus_eConsumeNoDefault; + } if(mIsHelpMenu) { - HelpMenuConstruct( - aMenuEvent, - nsnull, //mParentWindow - mDOMNode, - mWebShell); + HelpMenuConstruct(aMenuEvent, nsnull /* mParentWindow */, mDOMNode, webShell); mConstructed = true; } else { - MenuConstruct( - aMenuEvent, - nsnull, //mParentWindow - mDOMNode, - mWebShell); - mConstructed = true; - } + MenuConstruct(aMenuEvent, nsnull /* mParentWindow */, mDOMNode, webShell); + mConstructed = true; + } } else { //printf("Menu already constructed \n"); } eventStatus = nsEventStatus_eConsumeNoDefault; - } else { - // Make sure none of our submenus are the ones that should be handling this - for (int i = mMenuItemVoidArray.Count(); i > 0; i--) - { - if(nsnull != mMenuItemVoidArray[i-1]) - { - nsCOMPtr submenu ( do_QueryInterface((nsISupports*)mMenuItemVoidArray[i-1]) ); - if(submenu) - { - nsCOMPtr menuListener ( do_QueryInterface((nsISupports*)mMenuItemVoidArray[i-1]) ); - if(menuListener){ - eventStatus = menuListener->MenuSelected(aMenuEvent); - if(nsEventStatus_eIgnore != eventStatus) - return eventStatus; - } - } - } - } - } + else + { + // Make sure none of our submenus are the ones that should be handling this + PRUint32 numItems; + mMenuItemsArray.Count(&numItems); + for (PRUint32 i = numItems; i > 0; i--) + { + nsCOMPtr menuSupports = getter_AddRefs(mMenuItemsArray.ElementAt(i - 1)); + nsCOMPtr submenu = do_QueryInterface(menuSupports); + nsCOMPtr menuListener = do_QueryInterface(submenu); + if(menuListener) { + eventStatus = menuListener->MenuSelected(aMenuEvent); + if(nsEventStatus_eIgnore != eventStatus) + return eventStatus; + } + } + + } + return eventStatus; } @@ -821,7 +805,7 @@ nsEventStatus nsMenu::MenuConstruct( // Now get the kids. Retrieve our menupopup child. nsCOMPtr menuPopupNode; - GetMenuPopupElement ( getter_AddRefs(menuPopupNode) ); + GetMenuPopupElement(getter_AddRefs(menuPopupNode)); if (!menuPopupNode) return nsEventStatus_eIgnore; @@ -833,19 +817,20 @@ nsEventStatus nsMenu::MenuConstruct( // Fire our oncreate handler. If we're told to stop, don't build the menu at all PRBool keepProcessing = OnCreate(); - if ( keepProcessing ) { - while (menuitemNode) { - + if ( keepProcessing ) + { + while (menuitemNode) + { nsCOMPtr menuitemElement(do_QueryInterface(menuitemNode)); - if (menuitemElement) { - nsString menuitemNodeType; - nsString menuitemName; - - nsString label; + if (menuitemElement) + { + nsAutoString label; menuitemElement->GetAttribute(NS_ConvertASCIItoUCS2("value"), label); //printf("label = %s \n", label.ToNewCString()); // depending on the type, create a menu item, separator, or submenu + nsAutoString menuitemNodeType; + nsAutoString menuitemName; menuitemElement->GetNodeName(menuitemNodeType); if (menuitemNodeType.EqualsWithConversion("menuitem")) LoadMenuItem(this, menuitemElement, menuitemNode, menuIndex, (nsIWebShell*)aWebShell); @@ -873,19 +858,22 @@ nsEventStatus nsMenu::HelpMenuConstruct( const nsMenuEvent & aMenuEvent, nsIWidget * aParentWindow, void * menuNode, - void * aWebShell) + void * aWebShell) { //printf("nsMenu::MenuConstruct called for %s = %d \n", mLabel.ToNewCString(), mMacMenuHandle); // Begin menuitem inner loop int numHelpItems = ::CountMenuItems(mMacMenuHandle); - for(int i=0; i domElement = do_QueryInterface(mDOMNode); if (domElement) - domElement->SetAttribute(NS_ConvertASCIItoUCS2("open"), NS_ConvertASCIItoUCS2("true")); + domElement->SetAttribute(NS_ConvertASCIItoUCS2("open"), NS_ConvertASCIItoUCS2("true")); gCurrentMenuDepth++; @@ -904,14 +892,14 @@ nsEventStatus nsMenu::HelpMenuConstruct( // Fire our oncreate handler. If we're told to stop, don't build the menu at all PRBool keepProcessing = OnCreate(); if ( keepProcessing ) { - while (menuitemNode) { - + while (menuitemNode) + { nsCOMPtr menuitemElement(do_QueryInterface(menuitemNode)); if (menuitemElement) { - nsString menuitemNodeType; - nsString menuitemName; + nsAutoString menuitemNodeType; + nsAutoString menuitemName; - nsString label; + nsAutoString label; menuitemElement->GetAttribute(NS_ConvertASCIItoUCS2("value"), label); //printf("label = %s \n", label.ToNewCString()); @@ -926,7 +914,8 @@ nsEventStatus nsMenu::HelpMenuConstruct( LoadSubMenu(this, menuitemElement, menuitemNode); } } - ++menuIndex; + + ++menuIndex; nsCOMPtr oldmenuitemNode(menuitemNode); oldmenuitemNode->GetNextSibling(getter_AddRefs(menuitemNode)); } // end menu item innner loop @@ -949,7 +938,8 @@ nsEventStatus nsMenu::MenuDestruct(const nsMenuEvent & aMenuEvent) // Fire our ondestroy handler. If we're told to stop, don't destroy the menu PRBool keepProcessing = OnDestroy(); - if ( keepProcessing ) { + if ( keepProcessing ) + { RemoveAll(); //printf(" mMenuItemVoidArray.Count() = %d \n", mMenuItemVoidArray.Count()); // Close the node. @@ -1018,7 +1008,6 @@ NS_METHOD nsMenu::GetEnabled(PRBool* aIsEnabled) NS_METHOD nsMenu::IsHelpMenu(PRBool* aIsHelpMenu) { *aIsHelpMenu = mIsHelpMenu; - return NS_OK; } @@ -1030,10 +1019,8 @@ NS_METHOD nsMenu::IsHelpMenu(PRBool* aIsHelpMenu) */ NS_METHOD nsMenu::GetDOMNode(nsIDOMNode ** aMenuNode) { - if(aMenuNode) { - *aMenuNode = mDOMNode; - NS_IF_ADDREF(mDOMNode); - } + NS_ENSURE_ARG_POINTER(aMenuNode); + NS_IF_ADDREF(*aMenuNode = mDOMNode); return NS_OK; } @@ -1044,13 +1031,13 @@ void nsMenu::NSStringSetMenuItemText(MenuHandle macMenuHandle, short menuItem, n OSErr err; const PRUnichar* unicodeText; char* scriptRunText; - size_t unicodeTextLengthInBytes, unicdeTextReadInBytes, - scriptRunTextSizeInBytes, scriptRunTextLengthInBytes, - scriptCodeRunListLength; - ScriptCodeRun convertedTextScript; + size_t unicodeTextLengthInBytes, unicdeTextReadInBytes, + scriptRunTextSizeInBytes, scriptRunTextLengthInBytes, + scriptCodeRunListLength; + ScriptCodeRun convertedTextScript; short themeFontID; - Str255 themeFontName; - SInt16 themeFontSize; + Str255 themeFontName; + SInt16 themeFontSize; Style themeFontStyle; // @@ -1208,18 +1195,18 @@ MenuHandle nsMenu::NSStringNewChildMenu(short menuID, nsString& menuTitle) //---------------------------------------- void nsMenu::LoadMenuItem( - nsIMenu * pParentMenu, + nsIMenu * pParentMenu, nsIDOMElement * menuitemElement, nsIDOMNode * menuitemNode, unsigned short menuitemIndex, nsIWebShell * aWebShell) { static const char* NS_STRING_TRUE = "true"; - nsString disabled; - nsString checked; - nsString type; - nsString menuitemName; - nsString menuitemCmd; + nsAutoString disabled; + nsAutoString checked; + nsAutoString type; + nsAutoString menuitemName; + nsAutoString menuitemCmd; menuitemElement->GetAttribute(NS_ConvertASCIItoUCS2("disabled"), disabled); menuitemElement->GetAttribute(NS_ConvertASCIItoUCS2("checked"), checked); @@ -1251,17 +1238,23 @@ void nsMenu::LoadMenuItem( else if ( type.EqualsWithConversion("radio") ) itemType = nsIMenuItem::eRadio; + nsCOMPtr webShell = do_QueryReferent(mWebShellWeakRef); + if (!webShell) { + NS_ERROR("No webshell"); + return; + } + // Create the item. DO NOT use passed in webshell because of messed up windows dynamic loading // code. pnsMenuItem->Create(pParentMenu, menuitemName, PR_FALSE, itemType, - enabled, mManager, mWebShell, menuitemNode); + enabled, mManager, webShell, menuitemNode); // // Set key shortcut and modifiers // nsAutoString keyAtom; keyAtom.AssignWithConversion("key"); - nsString keyValue; + nsAutoString keyValue; domElement->GetAttribute(keyAtom, keyValue); // Try to find the key node. @@ -1270,7 +1263,7 @@ void nsMenu::LoadMenuItem( content->GetDocument(*getter_AddRefs(document)); if ( !document ) { NS_ERROR("Unable to retrieve the document."); - return;; + return; } // Turn the document into a XUL document so we can use getElementById @@ -1280,19 +1273,19 @@ void nsMenu::LoadMenuItem( return; } - nsIDOMElement * keyElement = nsnull; - xulDocument->GetElementById(keyValue, &keyElement); + nsCOMPtr keyElement; + xulDocument->GetElementById(keyValue, getter_AddRefs(keyElement)); if ( keyElement ) { PRUint8 modifiers = knsMenuItemNoModifier; nsAutoString shiftAtom; shiftAtom.AssignWithConversion("shift"); nsAutoString altAtom; altAtom.AssignWithConversion("alt"); nsAutoString commandAtom; commandAtom.AssignWithConversion("command"); - nsString shiftValue; - nsString altValue; - nsString commandValue; - nsString controlValue; - nsString keyChar; keyChar.AssignWithConversion(" "); + nsAutoString shiftValue; + nsAutoString altValue; + nsAutoString commandValue; + nsAutoString controlValue; + nsAutoString keyChar; keyChar.AssignWithConversion(" "); keyElement->GetAttribute(keyAtom, keyChar); keyElement->GetAttribute(shiftAtom, shiftValue); @@ -1337,16 +1330,22 @@ void nsMenu::LoadMenuItem( void nsMenu::LoadSubMenu( nsIMenu * pParentMenu, nsIDOMElement * menuElement, nsIDOMNode * menuNode ) { - nsString menuName; + nsAutoString menuName; menuElement->GetAttribute(NS_ConvertASCIItoUCS2("value"), menuName); //printf("Creating Menu [%s] \n", menuName.ToNewCString()); // this leaks // Create nsMenu nsCOMPtr pnsMenu ( do_CreateInstance(kMenuCID) ); - if ( pnsMenu ) { + if (pnsMenu) + { // Call Create - nsCOMPtr supports ( do_QueryInterface(pParentMenu) ); - pnsMenu->Create(supports, menuName, NS_ConvertASCIItoUCS2(""), mManager, mWebShell, menuNode); + nsCOMPtr webShell = do_QueryReferent(mWebShellWeakRef); + if (!webShell) { + NS_ERROR("No web shell"); + return; + } + nsCOMPtr supports(do_QueryInterface(pParentMenu)); + pnsMenu->Create(supports, menuName, NS_ConvertASCIItoUCS2(""), mManager, webShell, menuNode); // set if it's enabled or disabled nsAutoString disabled; @@ -1384,17 +1383,23 @@ nsMenu::OnCreate() event.clickCount = 0; event.widget = nsnull; + nsCOMPtr webShell = do_QueryReferent(mWebShellWeakRef); + if (!webShell) { + NS_ERROR("No web shell"); + return PR_FALSE; + } nsCOMPtr presContext; - MenuHelpers::WebShellToPresContext ( mWebShell, getter_AddRefs(presContext) ); - if ( presContext ) { - nsresult rv; + MenuHelpers::WebShellToPresContext(webShell, getter_AddRefs(presContext) ); + if ( presContext ) + { + nsresult rv = NS_OK; nsCOMPtr menuPopup; GetMenuPopupElement(getter_AddRefs(menuPopup)); nsCOMPtr popupContent ( do_QueryInterface(menuPopup) ); if ( popupContent ) rv = popupContent->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); else { - nsCOMPtr me ( do_QueryInterface(mDOMNode) ); + nsCOMPtr me (do_QueryInterface(mDOMNode)); if ( me ) rv = me->HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); } @@ -1429,9 +1434,16 @@ nsMenu::OnDestroy() event.clickCount = 0; event.widget = nsnull; + nsCOMPtr webShell = do_QueryReferent(mWebShellWeakRef); + if (!webShell) { + NS_WARNING("No web shell so can't run the OnDestroy"); + return PR_FALSE; + } + nsCOMPtr presContext; - MenuHelpers::WebShellToPresContext ( mWebShell, getter_AddRefs(presContext) ); - if ( presContext ) { + MenuHelpers::WebShellToPresContext (webShell, getter_AddRefs(presContext) ); + if (presContext ) + { nsresult rv; nsCOMPtr menuPopup; GetMenuPopupElement(getter_AddRefs(menuPopup)); @@ -1463,15 +1475,16 @@ nsMenu::OnDestroy() void nsMenu::GetMenuPopupElement(nsIDOMNode** aResult) { - if ( !aResult ) + if (!aResult ) return; - + *aResult = nsnull; nsCOMPtr menuPopupNode; mDOMNode->GetFirstChild(getter_AddRefs(menuPopupNode)); - while (menuPopupNode) { + while (menuPopupNode) + { nsCOMPtr menuPopupElement(do_QueryInterface(menuPopupNode)); if (menuPopupElement) { - nsString menuPopupNodeType; + nsAutoString menuPopupNodeType; menuPopupElement->GetNodeName(menuPopupNodeType); if (menuPopupNodeType.EqualsWithConversion("menupopup")) { *aResult = menuPopupNode.get(); @@ -1515,9 +1528,10 @@ nsMenu :: AttributeChanged ( nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIAt nsCOMPtr valueAtom = NS_NewAtom("value"); nsCOMPtr hiddenAtom = NS_NewAtom("hidden"); + nsCOMPtr domElement = do_QueryInterface(mDOMNode); if(aAttribute == disabledAtom.get()) { - nsString valueString; - mDOMElement->GetAttribute(NS_ConvertASCIItoUCS2("disabled"), valueString); + nsAutoString valueString; + domElement->GetAttribute(NS_ConvertASCIItoUCS2("disabled"), valueString); if(valueString.EqualsWithConversion("true")) SetEnabled(PR_FALSE); else @@ -1526,7 +1540,7 @@ nsMenu :: AttributeChanged ( nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIAt ::DrawMenuBar(); } else if(aAttribute == valueAtom.get()) { - mDOMElement->GetAttribute(NS_ConvertASCIItoUCS2("value"), mLabel); + domElement->GetAttribute(NS_ConvertASCIItoUCS2("value"), mLabel); ::DeleteMenu(mMacMenuID); mMacMenuHandle = NSStringNewMenu(mMacMenuID, mLabel); @@ -1548,8 +1562,8 @@ nsMenu :: AttributeChanged ( nsIDocument *aDocument, PRInt32 aNameSpaceID, nsIAt #endif } else if(aAttribute == hiddenAtom.get()) { - nsString valueString; - mDOMElement->GetAttribute(NS_ConvertASCIItoUCS2("hidden"), valueString); + nsAutoString valueString; + domElement->GetAttribute(NS_ConvertASCIItoUCS2("hidden"), valueString); if(valueString.EqualsWithConversion("true")) { // hide this menu ::DeleteMenu(mMacMenuID); @@ -1592,10 +1606,12 @@ nsMenu :: ContentRemoved(nsIDocument *aDocument, nsIContent *aChild, PRInt32 aIn // sending an event into the dom. // nsresult -MenuHelpers :: WebShellToPresContext ( nsIWebShell* inWebShell, nsIPresContext** outContext ) +MenuHelpers :: WebShellToPresContext (nsIWebShell* inWebShell, nsIPresContext** outContext ) { - if ( !inWebShell || !outContext ) - return NS_ERROR_INVALID_ARG ; + NS_ENSURE_ARG_POINTER(outContext); + *outContext = nsnull; + if (!inWebShell) + return NS_ERROR_INVALID_ARG; nsresult retval = NS_OK; diff --git a/widget/src/mac/nsMenu.h b/widget/src/mac/nsMenu.h index 56ce9674555d..fad6cf1398b1 100644 --- a/widget/src/mac/nsMenu.h +++ b/widget/src/mac/nsMenu.h @@ -25,9 +25,10 @@ #include "nsCOMPtr.h" #include "nsIMenu.h" -#include "nsVoidArray.h" +#include "nsSupportsArray.h" #include "nsIMenuListener.h" #include "nsIChangeManager.h" +#include "nsWeakReference.h" #include #include @@ -38,14 +39,14 @@ class nsIDOMElement; // temporary hack to get apple menu -- sfraser, approved saari -#define APPLE_MENU_HACK 1 +#define APPLE_MENU_HACK 1 #ifdef APPLE_MENU_HACK extern const PRInt16 kMacMenuID; extern const PRInt16 kAppleMenuID; #endif /* APPLE_MENU_HACK */ -//static PRInt16 mMacMenuIDCount; // use GetUniqueMenuID() +//static PRInt16 mMacMenuIDCount; // use GetUniqueMenuID() extern PRInt16 mMacMenuIDCount;// = kMacMenuID; @@ -56,7 +57,10 @@ namespace MenuHelpers } -class nsMenu : public nsIMenu, public nsIMenuListener, public nsIChangeObserver +class nsMenu : public nsIMenu, + public nsIMenuListener, + public nsIChangeObserver, + public nsSupportsWeakReference { public: @@ -103,35 +107,34 @@ public: NS_IMETHOD AddMenu(nsIMenu * aMenu); // MacSpecific - static PRInt16 GetUniqueMenuID() { - if (mMacMenuIDCount == 32767) - mMacMenuIDCount = 256; - return mMacMenuIDCount++; - } + static PRInt16 GetUniqueMenuID() + { + if (mMacMenuIDCount == 32767) + mMacMenuIDCount = 256; + return mMacMenuIDCount++; + } protected: - nsString mLabel; - PRUint32 mNumMenuItems; - nsVoidArray mMenuItemVoidArray; + nsString mLabel; + PRUint32 mNumMenuItems; + nsSupportsArray mMenuItemsArray; // array holds refs - nsIMenu * mMenuParent; // weak, my parent owns me - nsIMenuBar * mMenuBarParent; - - nsIDOMNode* mDOMNode; // weak ref, content model outlives us - nsCOMPtr mDOMElement; // for convenience; strong ref to manage the QI - nsIWebShell* mWebShell; - nsIChangeManager* mManager; // weak ref, it will outlive us - bool mConstructed; + nsIMenu* mMenuParent; // weak, my parent owns me + nsIMenuBar* mMenuBarParent; + nsIChangeManager* mManager; // weak ref, it will outlive us + nsWeakPtr mWebShellWeakRef; // weak ref to webshell + nsCOMPtr mDOMNode; //strong ref + nsCOMPtr mListener; + bool mConstructed; // MacSpecific - PRInt16 mMacMenuID; - MenuHandle mMacMenuHandle; - nsIMenuListener * mListener; - UnicodeToTextRunInfo mUnicodeTextRunConverter; - PRInt16 mHelpMenuOSItemsCount; - PRBool mIsHelpMenu; - PRBool mIsEnabled; - PRBool mDestroyHandlerCalled; + PRInt16 mMacMenuID; + MenuHandle mMacMenuHandle; + UnicodeToTextRunInfo mUnicodeTextRunConverter; + PRInt16 mHelpMenuOSItemsCount; + PRPackedBool mIsHelpMenu; + PRPackedBool mIsEnabled; + PRPackedBool mDestroyHandlerCalled; // fetch the content node associated with the menupopup item void GetMenuPopupElement ( nsIDOMNode** aResult ) ; @@ -146,7 +149,7 @@ protected: void LoadSubMenu( nsIMenu * pParentMenu, nsIDOMElement * menuElement, nsIDOMNode * menuNode); nsEventStatus HelpMenuConstruct( const nsMenuEvent & aMenuEvent, nsIWidget* aParentWindow, void* menuNode, void* aWebShell); - + void NSStringSetMenuItemText(MenuHandle macMenuHandle, short menuItem, nsString& nsString); MenuHandle NSStringNewMenu(short menuID, nsString& menuTitle); MenuHandle NSStringNewChildMenu(short menuID, nsString& menuTitle); diff --git a/widget/src/mac/nsMenuBar.cpp b/widget/src/mac/nsMenuBar.cpp index 357d3d255250..227af80bbad0 100644 --- a/widget/src/mac/nsMenuBar.cpp +++ b/widget/src/mac/nsMenuBar.cpp @@ -64,7 +64,7 @@ typedef struct { Handle gMDEF = nsnull; Handle gSystemMDEFHandle = nsnull; -nsIMenuBar * gMacMenubar = nsnull; +nsWeakPtr gMacMenubar; bool gFirstMenuBar = true; // The four Golden Hierarchical Child Menus @@ -74,7 +74,7 @@ MenuHandle gLevel4HierMenu = nsnull; MenuHandle gLevel5HierMenu = nsnull; #if !TARGET_CARBON -extern nsVoidArray gPreviousMenuStack; +extern nsMenuStack gPreviousMenuStack; #endif extern PRInt16 gCurrentMenuDepth; @@ -90,7 +90,77 @@ static NS_DEFINE_CID(kMenuItemCID, NS_MENUITEM_CID); void InstallDefProc( short dpPath, ResType dpType, short dpID, Ptr dpAddr); -NS_IMPL_ISUPPORTS4(nsMenuBar, nsIMenuBar, nsIMenuListener, nsIDocumentObserver, nsIChangeManager) + +#if DEBUG +nsInstanceCounter gMenuBarCounter("nsMenuBar"); +#endif + + +NS_IMPL_ISUPPORTS5(nsMenuBar, nsIMenuBar, nsIMenuListener, nsIDocumentObserver, nsIChangeManager, nsISupportsWeakReference) + +// +// nsMenuBar constructor +// +nsMenuBar::nsMenuBar() +{ + gCurrentMenuDepth = 1; + +#if !TARGET_CARBON + nsPreviousMenuStackUnwind(nsnull, nsnull); +#endif + NS_INIT_REFCNT(); + mNumMenus = 0; + mParent = nsnull; + mIsMenuBarAdded = PR_FALSE; + mUnicodeTextRunConverter = nsnull; + +#if !TARGET_CARBON + MenuDefUPP mdef = NewMenuDefProc( nsDynamicMDEFMain ); + InstallDefProc((short)nsMacResources::GetLocalResourceFile(), (ResType)'MDEF', (short)128, (Ptr) mdef ); +#endif + + mOriginalMacMBarHandle = nsnull; + mMacMBarHandle = nsnull; + + mOriginalMacMBarHandle = ::GetMenuBar(); + Handle tmp = ::GetMenuBar(); + ::SetMenuBar(tmp); + this->SetNativeData((void*)tmp); + + ::ClearMenuBar(); + mRefCnt = 1; // NS_GetWeakReference does an addref then a release, so this +1 is needed + gMacMenubar = getter_AddRefs(NS_GetWeakReference((nsIMenuBar *)this)); + mRefCnt = 0; + // copy from nsMenu.cpp + ScriptCode ps[1]; + ps[0] = ::GetScriptManagerVariable(smSysScript); + + OSErr err = ::CreateUnicodeToTextRunInfoByScriptCode(0x80000000, ps, &mUnicodeTextRunConverter); + NS_ASSERTION(err==noErr,"nsMenu::nsMenu: CreateUnicodeToTextRunInfoByScriptCode failed."); + +#if DEBUG + ++gMenuBarCounter; +#endif +} + + +// +// nsMenuBar destructor +// +nsMenuBar::~nsMenuBar() +{ + mMenusArray.Clear(); // release all menus + + OSErr err = ::DisposeUnicodeToTextRunInfo(&mUnicodeTextRunConverter); + NS_ASSERTION(err==noErr,"nsMenu::~nsMenu: DisposeUnicodeToTextRunInfo failed."); + + ::DisposeHandle(mMacMBarHandle); + ::DisposeHandle(mOriginalMacMBarHandle); + +#if DEBUG + --gMenuBarCounter; +#endif +} nsEventStatus @@ -99,13 +169,16 @@ nsMenuBar::MenuItemSelected(const nsMenuEvent & aMenuEvent) // Dispatch menu event nsEventStatus eventStatus = nsEventStatus_eIgnore; - for (int i = mMenuVoidArray.Count(); i > 0; --i) + PRUint32 numItems; + mMenusArray.Count(&numItems); + + for (PRUint32 i = numItems; i > 0; --i) { - nsIMenuListener * menuListener = nsnull; - ((nsISupports*)mMenuVoidArray[i-1])->QueryInterface(NS_GET_IID(nsIMenuListener), (void**)&menuListener); - if(menuListener){ + nsCOMPtr menuSupports = getter_AddRefs(mMenusArray.ElementAt(i - 1)); + nsCOMPtr menuListener = do_QueryInterface(menuSupports); + if(menuListener) + { eventStatus = menuListener->MenuItemSelected(aMenuEvent); - NS_RELEASE(menuListener); if(nsEventStatus_eIgnore != eventStatus) return eventStatus; } @@ -120,32 +193,36 @@ nsMenuBar::MenuSelected(const nsMenuEvent & aMenuEvent) // Dispatch event nsEventStatus eventStatus = nsEventStatus_eIgnore; - nsIMenuListener * menuListener = nsnull; + nsCOMPtr menuListener; //((nsISupports*)mMenuVoidArray[i-1])->QueryInterface(NS_GET_IID(nsIMenuListener), (void**)&menuListener); //printf("gPreviousMenuStack.Count() = %d \n", gPreviousMenuStack.Count()); #if !TARGET_CARBON - if (gPreviousMenuStack[gPreviousMenuStack.Count() - 1]) - ((nsIMenu*)gPreviousMenuStack[gPreviousMenuStack.Count() - 1])->QueryInterface(NS_GET_IID(nsIMenuListener), (void**)&menuListener); + nsCOMPtr theMenu; + gPreviousMenuStack.GetMenuAt(gPreviousMenuStack.Count() - 1, getter_AddRefs(theMenu)); + menuListener = do_QueryInterface(theMenu); #endif if (menuListener) { //TODO: MenuSelected is the right thing to call... //eventStatus = menuListener->MenuSelected(aMenuEvent); eventStatus = menuListener->MenuItemSelected(aMenuEvent); - NS_RELEASE(menuListener); if (nsEventStatus_eIgnore != eventStatus) return eventStatus; } else { // If it's the help menu, gPreviousMenuStack won't be accurate so we need to get the listener a different way // We'll do it the old fashioned way of looping through and finding it - for (int i = mMenuVoidArray.Count(); i > 0; --i) { - ((nsISupports*)mMenuVoidArray[i-1])->QueryInterface(NS_GET_IID(nsIMenuListener), (void**)&menuListener); - if (menuListener) { + PRUint32 numItems; + mMenusArray.Count(&numItems); + for (PRUint32 i = numItems; i > 0; --i) + { + nsCOMPtr menuSupports = getter_AddRefs(mMenusArray.ElementAt(i - 1)); + nsCOMPtr thisListener = do_QueryInterface(menuSupports); + if (thisListener) + { //TODO: MenuSelected is the right thing to call... - //eventStatus = menuListener->MenuSelected(aMenuEvent); - eventStatus = menuListener->MenuItemSelected(aMenuEvent); - NS_RELEASE(menuListener); - if(nsEventStatus_eIgnore != eventStatus) - return eventStatus; + //eventStatus = menuListener->MenuSelected(aMenuEvent); + eventStatus = thisListener->MenuItemSelected(aMenuEvent); + if(nsEventStatus_eIgnore != eventStatus) + return eventStatus; } } } @@ -194,13 +271,9 @@ nsEventStatus nsMenuBar::MenuConstruct( const nsMenuEvent & aMenuEvent, nsIWidget* aParentWindow, void * menubarNode, void * aWebShell ) { - mWebShell = (nsIWebShell*) aWebShell; - NS_ADDREF(mWebShell); - mDOMNode = (nsIDOMNode*)menubarNode; - NS_ADDREF(mDOMNode); - - nsIMenuBar * pnsMenuBar = this; - + mWebShellWeakRef = getter_AddRefs(NS_GetWeakReference(NS_STATIC_CAST(nsIWebShell*, aWebShell))); + mDOMNode = NS_STATIC_CAST(nsIDOMNode*, menubarNode); // strong ref + if(gFirstMenuBar) { gFirstMenuBar = false; // Add the 4 Golden Hierarchical Menus to the MenuList @@ -271,24 +344,25 @@ nsMenuBar::MenuConstruct( const nsMenuEvent & aMenuEvent, nsIWidget* aParentWind ::InsertMenu(gLevel5HierMenu, hierMenu); } - pnsMenuBar->Create(aParentWindow); - RegisterAsDocumentObserver ( mWebShell ); + Create(aParentWindow); + + nsCOMPtr webShell = do_QueryReferent(mWebShellWeakRef); + if (webShell) + RegisterAsDocumentObserver(webShell); - // set pnsMenuBar as a nsMenuListener on aParentWindow - nsCOMPtr menuListener; - pnsMenuBar->QueryInterface(NS_GET_IID(nsIMenuListener), getter_AddRefs(menuListener)); - aParentWindow->AddMenuListener(menuListener); + // set this as a nsMenuListener on aParentWindow + aParentWindow->AddMenuListener((nsIMenuListener *)this); - nsIDOMNode * menuNode = nsnull; - ((nsIDOMNode*)menubarNode)->GetFirstChild(&menuNode); - while (menuNode) { - NS_ADDREF(menuNode); - + nsCOMPtr menuNode; + mDOMNode->GetFirstChild(getter_AddRefs(menuNode)); + while (menuNode) + { nsCOMPtr menuElement(do_QueryInterface(menuNode)); - if (menuElement) { - nsString menuNodeType; - nsString menuName; - nsString menuAccessKey; menuAccessKey.AssignWithConversion(" "); + if (menuElement) + { + nsAutoString menuNodeType; + nsAutoString menuName; + nsAutoString menuAccessKey; menuAccessKey.AssignWithConversion(" "); menuElement->GetNodeName(menuNodeType); if (menuNodeType.EqualsWithConversion("menu")) { @@ -299,16 +373,16 @@ nsMenuBar::MenuConstruct( const nsMenuEvent & aMenuEvent, nsIWidget* aParentWind // Create nsMenu, the menubar will own it nsCOMPtr pnsMenu ( do_CreateInstance(kMenuCID) ); - if ( pnsMenu ) { - nsCOMPtr supports ( do_QueryInterface(pnsMenuBar) ); - nsCOMPtr manager ( do_QueryInterface(NS_STATIC_CAST(nsIMenuBar*,this)) ); - pnsMenu->Create(supports, menuName, menuAccessKey, manager, - NS_REINTERPRET_CAST(nsIWebShell*, aWebShell), menuNode); + if ( pnsMenu ) + { + pnsMenu->Create(NS_STATIC_CAST(nsIMenuBar*, this), menuName, menuAccessKey, + NS_STATIC_CAST(nsIChangeManager *, this), + NS_REINTERPRET_CAST(nsIWebShell*, aWebShell), menuNode); // Make nsMenu a child of nsMenuBar. nsMenuBar takes ownership - pnsMenuBar->AddMenu(pnsMenu); + AddMenu(pnsMenu); - nsString menuIDstring; + nsAutoString menuIDstring; menuElement->GetAttribute(NS_ConvertASCIItoUCS2("id"), menuIDstring); if(menuIDstring.EqualsWithConversion("menu_Help")) { nsMenuEvent event; @@ -323,17 +397,17 @@ nsMenuBar::MenuConstruct( const nsMenuEvent & aMenuEvent, nsIWidget* aParentWind } } } - nsCOMPtr oldmenuNode(do_QueryInterface(menuNode)); - oldmenuNode->GetNextSibling(&menuNode); + nsCOMPtr tempNode = menuNode; + tempNode->GetNextSibling(getter_AddRefs(menuNode)); } // end while (nsnull != menuNode) // Give the aParentWindow this nsMenuBar to hold onto. // The parent takes ownership - aParentWindow->SetMenuBar(pnsMenuBar); + aParentWindow->SetMenuBar(this); #ifdef XP_MAC Handle tempMenuBar = ::GetMenuBar(); // Get a copy of the menu list - pnsMenuBar->SetNativeData((void*)tempMenuBar); + SetNativeData((void*)tempMenuBar); #endif return nsEventStatus_eIgnore; @@ -347,67 +421,6 @@ nsMenuBar::MenuDestruct(const nsMenuEvent & aMenuEvent) } -// -// nsMenuBar constructor -// -nsMenuBar :: nsMenuBar() -{ - gCurrentMenuDepth = 1; -#if !TARGET_CARBON - nsPreviousMenuStackUnwind(nsnull, nsnull); -#endif - NS_INIT_REFCNT(); - mNumMenus = 0; - mParent = nsnull; - mIsMenuBarAdded = PR_FALSE; - mWebShell = nsnull; - mDOMNode = nsnull; - -#if !TARGET_CARBON - MenuDefUPP mdef = NewMenuDefProc( nsDynamicMDEFMain ); - InstallDefProc((short)nsMacResources::GetLocalResourceFile(), (ResType)'MDEF', (short)128, (Ptr) mdef ); -#endif - - mOriginalMacMBarHandle = nsnull; - mMacMBarHandle = nsnull; - - mOriginalMacMBarHandle = ::GetMenuBar(); - Handle tmp = ::GetMenuBar(); - ::SetMenuBar(tmp); - this->SetNativeData((void*)tmp); - - ::ClearMenuBar(); - gMacMenubar = this; - // copy from nsMenu.cpp - ScriptCode ps[1]; - ps[0] = ::GetScriptManagerVariable(smSysScript); - - OSErr err = ::CreateUnicodeToTextRunInfoByScriptCode(0x80000000,ps,&mUnicodeTextRunConverter); - NS_ASSERTION(err==noErr,"nsMenu::nsMenu: CreateUnicodeToTextRunInfoByScriptCode failed."); -} - - -// -// nsMenuBar destructor -// -nsMenuBar :: ~nsMenuBar() -{ - //NS_IF_RELEASE(mParent); - - while(mNumMenus) - { - --mNumMenus; - nsISupports* menu = (nsISupports*)mMenuVoidArray[mNumMenus]; - NS_IF_RELEASE( menu ); - } - OSErr err = ::DisposeUnicodeToTextRunInfo(&mUnicodeTextRunConverter); - NS_ASSERTION(err==noErr,"nsMenu::~nsMenu: DisposeUnicodeToTextRunInfo failed."); - - ::DisposeHandle(mMacMBarHandle); - ::DisposeHandle(mOriginalMacMBarHandle); -} - - //------------------------------------------------------------------------- // // Create the proper widget @@ -416,15 +429,13 @@ nsMenuBar :: ~nsMenuBar() NS_METHOD nsMenuBar::Create(nsIWidget *aParent) { SetParent(aParent); - return NS_OK; } //------------------------------------------------------------------------- NS_METHOD nsMenuBar::GetParent(nsIWidget *&aParent) { - aParent = mParent; - + NS_IF_ADDREF(aParent = mParent); return NS_OK; } @@ -432,8 +443,7 @@ NS_METHOD nsMenuBar::GetParent(nsIWidget *&aParent) //------------------------------------------------------------------------- NS_METHOD nsMenuBar::SetParent(nsIWidget *aParent) { - mParent = aParent; - + mParent = aParent; // weak ref return NS_OK; } @@ -441,11 +451,9 @@ NS_METHOD nsMenuBar::SetParent(nsIWidget *aParent) NS_METHOD nsMenuBar::AddMenu(nsIMenu * aMenu) { // XXX add to internal data structure - nsISupports * supports = nsnull; - aMenu->QueryInterface(NS_GET_IID(nsISupports), (void**)&supports); - if(supports){ - mMenuVoidArray.AppendElement( supports ); - } + nsCOMPtr supports = do_QueryInterface(aMenu); + if(supports) + mMenusArray.AppendElement(supports); // owner #ifdef APPLE_MENU_HACK if (mNumMenus == 0) @@ -456,35 +464,25 @@ NS_METHOD nsMenuBar::AddMenu(nsIMenu * aMenu) if (appleMenu) { nsresult ret; - nsIStringBundleService *pStringService = nsnull; - ret = nsServiceManager::GetService(kStringBundleServiceCID, - kIStringBundleServiceIID, (nsISupports**) &pStringService); + nsCOMPtr pStringService = do_GetService(kStringBundleServiceCID, &ret); if (NS_FAILED(ret)) { NS_WARNING("cannot get string service\n"); return ret; } //XXX "chrome://global/locale/brand.properties" should be less hardcoded - nsILocale *locale = nsnull; - nsIStringBundle *bundle = nsnull; - ret = pStringService->CreateBundle("chrome://global/locale/brand.properties", - locale, &bundle); - - nsServiceManager::ReleaseService(kStringBundleServiceCID, pStringService); - + nsCOMPtr bundle; + ret = pStringService->CreateBundle("chrome://global/locale/brand.properties", nsnull, getter_AddRefs(bundle)); if (NS_FAILED(ret)) { NS_WARNING("cannot create instance\n"); return ret; } //XXX "aboutStrName" should be less hardcoded - nsAutoString temp; temp.AssignWithConversion("aboutStrName"); - const PRUnichar *ptrtmp = temp.GetUnicode(); PRUnichar *ptrv = nsnull; - bundle->GetStringFromName(ptrtmp, &ptrv); - + bundle->GetStringFromName(NS_ConvertASCIItoUCS2("aboutStrName").GetUnicode(), &ptrv); nsAutoString label = ptrv; - + nsCRT::free(ptrv); ::AppendMenu(appleMenu, "\pa"); NSStringSetMenuItemText(appleMenu, 1, label); @@ -502,10 +500,10 @@ NS_METHOD nsMenuBar::AddMenu(nsIMenu * aMenu) PRBool helpMenu; aMenu->IsHelpMenu(&helpMenu); if(!helpMenu) { - nsString menuHidden; menuHidden.AssignWithConversion(" "); nsCOMPtr domNode; aMenu->GetDOMNode(getter_AddRefs(domNode)); nsCOMPtr domElement = do_QueryInterface(domNode); + nsAutoString menuHidden; domElement->GetAttribute(NS_ConvertASCIItoUCS2("hidden"), menuHidden); if(! menuHidden.EqualsWithConversion("true")) ::InsertMenu(menuHandle, 0); @@ -578,17 +576,11 @@ NS_METHOD nsMenuBar::GetMenuCount(PRUint32 &aCount) //------------------------------------------------------------------------- NS_METHOD nsMenuBar::GetMenuAt(const PRUint32 aCount, nsIMenu *& aMenu) { - nsISupports * supports = nsnull; - supports = (nsISupports*) mMenuVoidArray.ElementAt(aCount); - if(!supports) { - return NS_OK; - } + aMenu = NULL; + nsCOMPtr supports = getter_AddRefs(mMenusArray.ElementAt(aCount)); + if (!supports) return NS_OK; - nsIMenu * menu = nsnull; - supports->QueryInterface(NS_GET_IID(nsISupports), (void**)&menu); - aMenu = menu; - - return NS_OK; + return CallQueryInterface(supports, &aMenu); // addref } //------------------------------------------------------------------------- @@ -600,11 +592,7 @@ NS_METHOD nsMenuBar::InsertMenuAt(const PRUint32 aCount, nsIMenu *& aMenu) //------------------------------------------------------------------------- NS_METHOD nsMenuBar::RemoveMenu(const PRUint32 aCount) { - nsISupports* menu = (nsISupports*)mMenuVoidArray[aCount]; - NS_IF_RELEASE( menu ); - - mMenuVoidArray.RemoveElementAt(aCount); - + mMenusArray.RemoveElementAt(aCount); ::DrawMenuBar(); return NS_OK; } @@ -612,6 +600,8 @@ NS_METHOD nsMenuBar::RemoveMenu(const PRUint32 aCount) //------------------------------------------------------------------------- NS_METHOD nsMenuBar::RemoveAll() { + NS_ASSERTION(0, "Not implemented!"); + // mMenusArray.Clear(); // maybe? return NS_OK; } @@ -633,22 +623,30 @@ NS_METHOD nsMenuBar::SetNativeData(void* aData) //------------------------------------------------------------------------- NS_METHOD nsMenuBar::Paint() { - gMacMenubar = this; - PRBool isHelpMenu; + gMacMenubar = getter_AddRefs(NS_GetWeakReference((nsIMenuBar *)this)); ::SetMenuBar(mMacMBarHandle); // Now we have blown away the merged Help menu, so we have to rebuild it - for(int i = mMenuVoidArray.Count()-1; i>=0; --i) { - ((nsIMenu*)mMenuVoidArray[i])->IsHelpMenu(&isHelpMenu); - if(isHelpMenu){ + PRUint32 numItems; + mMenusArray.Count(&numItems); + + for (PRInt32 i = numItems - 1; i >= 0; --i) + { + nsCOMPtr thisItem = getter_AddRefs(mMenusArray.ElementAt(i)); + nsCOMPtr menu = do_QueryInterface(thisItem); + PRBool isHelpMenu = PR_FALSE; + if (menu) + menu->IsHelpMenu(&isHelpMenu); + if (isHelpMenu) + { MenuHandle helpMenuHandle; #if !TARGET_CARBON ::HMGetHelpMenuHandle(&helpMenuHandle); - ((nsIMenu*)mMenuVoidArray[i])->SetNativeData((void*)helpMenuHandle); + menu->SetNativeData((void*)helpMenuHandle); #endif nsMenuEvent event; event.mCommand = (unsigned int) helpMenuHandle; - nsCOMPtr listener(do_QueryInterface((nsIMenu*)mMenuVoidArray[i])); + nsCOMPtr listener = do_QueryInterface(menu); listener->MenuSelected(event); } } @@ -673,9 +671,14 @@ void InstallDefProc( gMDEF = (Handle) jH; UseResFile(savePath); - if (!jH) /* is there no defproc resource? */ + if (!jH) /* is there no defproc resource? */\ + { +#if DEBUG DebugStr("\pStub Defproc Not Found!"); - +#endif + ExitToShell(); // bail + } + HNoPurge((Handle)jH); /* make this resource nonpurgeable */ (**jH).jmpAddr = dpAddr; (**jH).jmpInstr = 0x4EF9; diff --git a/widget/src/mac/nsMenuBar.h b/widget/src/mac/nsMenuBar.h index e56fb4e35740..726a39c91a59 100644 --- a/widget/src/mac/nsMenuBar.h +++ b/widget/src/mac/nsMenuBar.h @@ -27,13 +27,15 @@ #include "nsIMenuListener.h" #include "nsIDocumentObserver.h" #include "nsIChangeManager.h" +#include "nsSupportsArray.h" #include "nsVoidArray.h" #include "nsHashtable.h" +#include "nsWeakReference.h" -#include "Types.h" +#include #include -extern nsIMenuBar * gMacMenubar; +extern nsWeakPtr gMacMenubar; class nsIWidget; @@ -41,8 +43,11 @@ class nsIWidget; * Native Mac MenuBar wrapper */ -class nsMenuBar : public nsIMenuBar, public nsIMenuListener, public nsIDocumentObserver, - public nsIChangeManager +class nsMenuBar : public nsIMenuBar, + public nsIMenuListener, + public nsIDocumentObserver, + public nsIChangeManager, + public nsSupportsWeakReference { public: @@ -130,16 +135,17 @@ public: protected: - nsHashtable mObserverTable; // stores observers for content change notification + nsHashtable mObserverTable; // stores observers for content change notification - PRUint32 mNumMenus; - nsVoidArray mMenuVoidArray; - nsIWidget * mParent; + PRUint32 mNumMenus; + nsSupportsArray mMenusArray; // holds refs + nsCOMPtr mDOMNode; + nsIWidget * mParent; // weak ref - PRBool mIsMenuBarAdded; + PRBool mIsMenuBarAdded; - nsIWebShell * mWebShell; - nsIDOMNode * mDOMNode; + nsWeakPtr mWebShellWeakRef; // weak ref to webshell + void RegisterAsDocumentObserver ( nsIWebShell* inWebShell ) ; @@ -148,7 +154,7 @@ protected: Handle mOriginalMacMBarHandle; UnicodeToTextRunInfo mUnicodeTextRunConverter; void NSStringSetMenuItemText(MenuHandle macMenuHandle, short menuItem, nsString& nsString); - + }; #endif // nsMenuBar_h__ diff --git a/widget/src/mac/nsMenuItem.cpp b/widget/src/mac/nsMenuItem.cpp index a0376ac80430..d1ea6c523ec0 100644 --- a/widget/src/mac/nsMenuItem.cpp +++ b/widget/src/mac/nsMenuItem.cpp @@ -31,11 +31,17 @@ #include "nsIMenuBar.h" #include "nsIWidget.h" #include "nsIMenuListener.h" +#include "nsDynamicMDEF.h" #include "nsStringUtil.h" -NS_IMPL_ISUPPORTS3(nsMenuItem, nsIMenuItem, nsIMenuListener, nsIChangeObserver) +#if DEBUG +nsInstanceCounter gMenuItemCounter("nsMenuItem"); +#endif + + +NS_IMPL_ISUPPORTS4(nsMenuItem, nsIMenuItem, nsIMenuListener, nsIChangeObserver, nsISupportsWeakReference) // // nsMenuItem constructor @@ -44,14 +50,15 @@ nsMenuItem::nsMenuItem() { NS_INIT_REFCNT(); mMenuParent = nsnull; - mTarget = nsnull; mIsSeparator = PR_FALSE; - mWebShell = nsnull; - mDOMNode = nsnull; mKeyEquivalent.AssignWithConversion(" "); mEnabled = PR_TRUE; mIsChecked = PR_FALSE; mMenuType = eRegular; + +#if DEBUG + ++gMenuItemCounter; +#endif } // @@ -60,14 +67,16 @@ nsMenuItem::nsMenuItem() nsMenuItem::~nsMenuItem() { //printf("nsMenuItem::~nsMenuItem() called \n"); - NS_IF_RELEASE(mTarget); - // if we're a radio menu, we've been registered to get AttributeChanged, so // make sure we unregister when we go away. - if ( mMenuType == eRadio ) { - nsCOMPtr content ( do_QueryInterface(mDOMNode) ); - mManager->Unregister ( content ); + if (mMenuType == eRadio) { + nsCOMPtr content = do_QueryInterface(mDOMNode); + mManager->Unregister(content); } + +#if DEBUG + --gMenuItemCounter; +#endif } @@ -75,10 +84,9 @@ NS_METHOD nsMenuItem::Create ( nsIMenu* aParent, const nsString & aLabel, PRBool EMenuItemType aItemType, PRBool aEnabled, nsIChangeManager* aManager, nsIWebShell* aShell, nsIDOMNode* aNode ) { - mDOMNode = aNode; - mDOMElement = do_QueryInterface ( aNode ); - mMenuParent = aParent; - mWebShell = aShell; + mDOMNode = aNode; // addref + mMenuParent = aParent; // weak + mWebShellWeakRef = getter_AddRefs(NS_GetWeakReference(aShell)); mEnabled = aEnabled; mMenuType = aItemType; @@ -86,9 +94,9 @@ NS_METHOD nsMenuItem::Create ( nsIMenu* aParent, const nsString & aLabel, PRBool // if we're a radio menu, register for AttributeChanged messages mManager = aManager; if ( aItemType == eRadio ) { - nsCOMPtr content ( do_QueryInterface(mDOMNode) ); - nsCOMPtr obs ( do_QueryInterface(NS_STATIC_CAST(nsIChangeObserver*,this)) ); - mManager->Register ( content, obs ); + nsCOMPtr content = do_QueryInterface(mDOMNode); + nsCOMPtr obs = do_QueryInterface(NS_STATIC_CAST(nsIChangeObserver*,this)); + mManager->Register(content, obs); // does not addref this } mIsSeparator = aIsSeparator; @@ -117,14 +125,12 @@ NS_METHOD nsMenuItem::SetChecked(PRBool aIsEnabled) mIsChecked = aIsEnabled; // update the content model - if ( mIsChecked ) - mDOMElement->SetAttribute(NS_ConvertASCIItoUCS2("checked"), NS_ConvertASCIItoUCS2("true")); - else - mDOMElement->SetAttribute(NS_ConvertASCIItoUCS2("checked"), NS_ConvertASCIItoUCS2("false")); + nsCOMPtr domElement = do_QueryInterface(mDOMNode); + domElement->SetAttribute(NS_ConvertASCIItoUCS2("checked"), NS_ConvertASCIItoUCS2(mIsChecked ? "true" : "false")); // uncheck others if we're a radiomenu if ( mMenuType == eRadio && aIsEnabled ) - UncheckRadioSiblings ( mDOMElement ); + UncheckRadioSiblings (domElement); return NS_OK; } @@ -148,7 +154,7 @@ NS_METHOD nsMenuItem::GetMenuItemType(EMenuItemType *aType) //------------------------------------------------------------------------- NS_METHOD nsMenuItem::GetTarget(nsIWidget *& aTarget) { - aTarget = mTarget; + NS_IF_ADDREF(aTarget = mTarget); return NS_OK; } @@ -162,13 +168,15 @@ NS_METHOD nsMenuItem::GetNativeData(void *& aData) //------------------------------------------------------------------------- NS_METHOD nsMenuItem::AddMenuListener(nsIMenuListener * aMenuListener) { - mXULCommandListener = aMenuListener; - return NS_OK; + mXULCommandListener = aMenuListener; // addref + return NS_OK; } //------------------------------------------------------------------------- NS_METHOD nsMenuItem::RemoveMenuListener(nsIMenuListener * aMenuListener) { + if (mXULCommandListener.get() == aMenuListener) + mXULCommandListener = nsnull; return NS_OK; } @@ -212,11 +220,11 @@ nsEventStatus nsMenuItem::MenuItemSelected(const nsMenuEvent & aMenuEvent) //------------------------------------------------------------------------- nsEventStatus nsMenuItem::MenuSelected(const nsMenuEvent & aMenuEvent) { - //if(mXULCommandListener) - // return mXULCommandListener->MenuSelected(aMenuEvent); - + //if(mXULCommandListener) + // return mXULCommandListener->MenuSelected(aMenuEvent); + DoCommand(); - return nsEventStatus_eIgnore; + return nsEventStatus_eIgnore; } //------------------------------------------------------------------------- @@ -224,7 +232,7 @@ nsEventStatus nsMenuItem::MenuSelected(const nsMenuEvent & aMenuEvent) //------------------------------------------------------------------------- nsEventStatus nsMenuItem::MenuDeselected(const nsMenuEvent & aMenuEvent) { - return nsEventStatus_eIgnore; + return nsEventStatus_eIgnore; } //------------------------------------------------------------------------- @@ -232,15 +240,15 @@ nsEventStatus nsMenuItem::MenuConstruct( const nsMenuEvent & aMenuEvent, nsIWidget * aParentWindow, void * menuNode, - void * aWebShell) + void * aWebShell) { - return nsEventStatus_eIgnore; + return nsEventStatus_eIgnore; } //------------------------------------------------------------------------- nsEventStatus nsMenuItem::MenuDestruct(const nsMenuEvent & aMenuEvent) { - return nsEventStatus_eIgnore; + return nsEventStatus_eIgnore; } @@ -254,21 +262,20 @@ NS_METHOD nsMenuItem::DoCommand() nsresult rv = NS_ERROR_FAILURE; nsCOMPtr presContext; - MenuHelpers::WebShellToPresContext ( mWebShell, getter_AddRefs(presContext) ); + nsCOMPtr webShell = do_QueryReferent(mWebShellWeakRef); + if (!webShell) + { + NS_ERROR("No web shell"); + return nsEventStatus_eConsumeNoDefault; + } + MenuHelpers::WebShellToPresContext(webShell, getter_AddRefs(presContext)); nsEventStatus status = nsEventStatus_eIgnore; nsMouseEvent event; event.eventStructType = NS_MOUSE_EVENT; event.message = NS_MENU_ACTION; - nsCOMPtr element(do_QueryInterface(mDOMNode)); - if(!element) { - NS_ERROR("Unable to QI dom element."); - return rv; - } - - nsCOMPtr contentNode; - contentNode = do_QueryInterface(element); + nsCOMPtr contentNode = do_QueryInterface(mDOMNode); if (!contentNode) { NS_ERROR("DOM Node doesn't support the nsIContent interface required to handle DOM events."); return rv; @@ -284,9 +291,9 @@ NS_METHOD nsMenuItem::DoCommand() //------------------------------------------------------------------------- NS_METHOD nsMenuItem::GetModifiers(PRUint8 * aModifiers) { - nsresult res = NS_OK; - *aModifiers = mModifiers; - return res; + nsresult res = NS_OK; + *aModifiers = mModifiers; + return res; } //------------------------------------------------------------------------- @@ -321,16 +328,16 @@ NS_METHOD nsMenuItem::GetShortcutChar(nsString &aText) // uncheck them all. // void -nsMenuItem :: UncheckRadioSiblings ( nsIDOMElement* inCheckedElement ) +nsMenuItem :: UncheckRadioSiblings(nsIDOMElement* inCheckedElement) { - nsCOMPtr checkedNode ( do_QueryInterface(inCheckedElement) ); + nsCOMPtr checkedNode = do_QueryInterface(inCheckedElement); nsAutoString myGroupName; inCheckedElement->GetAttribute(NS_ConvertASCIItoUCS2("name"), myGroupName); nsCOMPtr parent; checkedNode->GetParentNode(getter_AddRefs(parent)); - if ( !parent ) + if (!parent ) return; nsCOMPtr currSibling; parent->GetFirstChild(getter_AddRefs(currSibling)); @@ -352,7 +359,6 @@ nsMenuItem :: UncheckRadioSiblings ( nsIDOMElement* inCheckedElement ) nsIDOMNode* next; currSibling->GetNextSibling(&next); currSibling = dont_AddRef(next); - } // for each sibling } // UncheckRadioSiblings @@ -369,11 +375,13 @@ nsMenuItem :: AttributeChanged ( nsIDocument *aDocument, PRInt32 aNameSpaceID, n PRInt32 aHint) { nsCOMPtr checkedAtom = NS_NewAtom("checked"); - nsAutoString checked; - if ( aAttribute == checkedAtom.get() ) { - mDOMElement->GetAttribute(NS_ConvertASCIItoUCS2("checked"), checked); - if ( checked.EqualsWithConversion("true") ) - UncheckRadioSiblings ( mDOMElement ); + if (aAttribute == checkedAtom.get()) + { + nsCOMPtr domElement = do_QueryInterface(mDOMNode); + nsAutoString checked; + domElement->GetAttribute(NS_ConvertASCIItoUCS2("checked"), checked); + if (checked.EqualsWithConversion("true")) + UncheckRadioSiblings(domElement); } return NS_OK; diff --git a/widget/src/mac/nsMenuItem.h b/widget/src/mac/nsMenuItem.h index 4f606e3cba25..a0593c66a6c5 100644 --- a/widget/src/mac/nsMenuItem.h +++ b/widget/src/mac/nsMenuItem.h @@ -28,6 +28,7 @@ #include "nsString.h" #include "nsIMenuListener.h" #include "nsIChangeManager.h" +#include "nsWeakReference.h" class nsIMenu; @@ -37,7 +38,10 @@ class nsIWidget; * Native Motif MenuItem wrapper */ -class nsMenuItem : public nsIMenuItem, public nsIMenuListener, public nsIChangeObserver +class nsMenuItem : public nsIMenuItem, + public nsIMenuListener, + public nsIChangeObserver, + public nsSupportsWeakReference { public: nsMenuItem(); @@ -80,24 +84,22 @@ protected: void UncheckRadioSiblings ( nsIDOMElement* inCheckedElement ) ; - nsAutoString mLabel; - nsAutoString mKeyEquivalent; + nsString mLabel; + nsString mKeyEquivalent; - nsIMenu * mMenuParent; // weak, parent owns us - nsIWidget * mTarget; + nsIMenu* mMenuParent; // weak, parent owns us + nsIChangeManager* mManager; // weak + nsCOMPtr mTarget; // never set? nsCOMPtr mXULCommandListener; - PRBool mIsSeparator; - nsIMenuListener * mListener; - nsIWebShell* mWebShell; // weak, document outlives us - nsCOMPtr mDOMElement; // for convenience; strong to manage QI - nsIDOMNode* mDOMNode; // weak, content outlives us - nsIChangeManager* mManager; // weak, manager outlives us + nsWeakPtr mWebShellWeakRef; // weak ref to webshell + nsCOMPtr mDOMNode; PRUint8 mModifiers; - PRBool mEnabled; - PRBool mIsChecked; + PRPackedBool mIsSeparator; + PRPackedBool mEnabled; + PRPackedBool mIsChecked; EMenuItemType mMenuType; };