Fix the menu code to not hold onto webshells, and to use weak refs for the previous menu stack etc. This allows menus to be cleaned up properly on quit (look ma, no leaks!). Bug 41695. r=saari, pinkerton

This commit is contained in:
sfraser%netscape.com 2000-06-17 03:38:00 +00:00
Родитель 2d3e888817
Коммит 2c326989df
8 изменённых файлов: 1000 добавлений и 816 удалений

Просмотреть файл

@ -32,18 +32,17 @@
#include <MixedMode.h>
#include <A4Stuff.h>
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<nsIMenuBar> 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<nsISupports> elementPtr = getter_AddRefs(mMenuArray.ElementAt(aIndex));
if (!elementPtr)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIWeakReference> weakRef = do_QueryInterface(elementPtr);
return weakRef->QueryReferent(NS_GET_IID(nsIMenu), NS_REINTERPRET_CAST(void**, outMenu));
}
PRBool
nsMenuStack::HaveMenuAt(PRInt32 aIndex)
{
nsCOMPtr<nsISupports> elementPtr = getter_AddRefs(mMenuArray.ElementAt(aIndex));
if (!elementPtr)
return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsIWeakReference> weakRef = do_QueryInterface(elementPtr);
nsCOMPtr<nsIMenu> 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<nsISupportsWeakReference> weakRefFactory = do_QueryInterface(inMenuItem);
if (!weakRefFactory) return NS_ERROR_NULL_POINTER;
nsCOMPtr<nsISupports> 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<nsIMenu> 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<nsIMenuListener> 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<nsIMenuListener> 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<nsIMenuBar> 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<nsIMenu> menu;
menubar->GetMenuAt(i, *getter_AddRefs(menu));
if(menu) {
nsCOMPtr<nsIMenuListener> 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<nsIMenu> menu;
menubar->GetMenuAt(i, *getter_AddRefs(menu));
if(menu) {
nsCOMPtr<nsIMenuListener> 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 <sigh>
// 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<nsIMenu> 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<nsIMenu> menu(do_QueryInterface(supports));
if(menu) {
nsCOMPtr<nsIMenuListener> menulistener(do_QueryInterface(supports));
menulistener->MenuSelected(mevent);
nsPostBuild(menu, theMenu, isChild);
}
}
}
}
if(prevMenu)
{
nsCOMPtr<nsISupports> supports;
prevMenu->GetItemAt(gCurrentMenuItem - 1, *getter_AddRefs(supports));
nsCOMPtr<nsIMenu> menu = do_QueryInterface(supports);
if (menu)
{
nsCOMPtr<nsIMenuListener> 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<nsIMenu> 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<nsIMenuListener> 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<nsIMenuListener> 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());

Просмотреть файл

@ -25,7 +25,9 @@
#ifndef nsDynamicMDEF_h__
#define nsDynamicMDEF_h__
#include "nsSupportsArray.h"
#include "nsIMenu.h"
#include <Menus.h>
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__

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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 <Menus.h>
#include <UnicodeConverter.h>
@ -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<nsIDOMElement> 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<nsIDOMNode> mDOMNode; //strong ref
nsCOMPtr<nsIMenuListener> 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);

Просмотреть файл

@ -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<nsISupports> menuSupports = getter_AddRefs(mMenusArray.ElementAt(i - 1));
nsCOMPtr<nsIMenuListener> 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<nsIMenuListener> 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<nsIMenu> 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<nsISupports> menuSupports = getter_AddRefs(mMenusArray.ElementAt(i - 1));
nsCOMPtr<nsIMenuListener> 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<nsIWebShell> webShell = do_QueryReferent(mWebShellWeakRef);
if (webShell)
RegisterAsDocumentObserver(webShell);
// set pnsMenuBar as a nsMenuListener on aParentWindow
nsCOMPtr<nsIMenuListener> 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<nsIDOMNode> menuNode;
mDOMNode->GetFirstChild(getter_AddRefs(menuNode));
while (menuNode)
{
nsCOMPtr<nsIDOMElement> 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<nsIMenu> pnsMenu ( do_CreateInstance(kMenuCID) );
if ( pnsMenu ) {
nsCOMPtr<nsISupports> supports ( do_QueryInterface(pnsMenuBar) );
nsCOMPtr<nsIChangeManager> 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<nsIDOMNode> oldmenuNode(do_QueryInterface(menuNode));
oldmenuNode->GetNextSibling(&menuNode);
nsCOMPtr<nsIDOMNode> 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<nsISupports> 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<nsIStringBundleService> 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<nsIStringBundle> 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<nsIDOMNode> domNode;
aMenu->GetDOMNode(getter_AddRefs(domNode));
nsCOMPtr<nsIDOMElement> 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<nsISupports> 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<nsISupports> thisItem = getter_AddRefs(mMenusArray.ElementAt(i));
nsCOMPtr<nsIMenu> 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<nsIMenuListener> listener(do_QueryInterface((nsIMenu*)mMenuVoidArray[i]));
nsCOMPtr<nsIMenuListener> 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;

Просмотреть файл

@ -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 <MacTypes.h>
#include <UnicodeConverter.h>
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<nsIDOMNode> 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__

Просмотреть файл

@ -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<nsIContent> content ( do_QueryInterface(mDOMNode) );
mManager->Unregister ( content );
if (mMenuType == eRadio) {
nsCOMPtr<nsIContent> 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<nsIContent> content ( do_QueryInterface(mDOMNode) );
nsCOMPtr<nsIChangeObserver> obs ( do_QueryInterface(NS_STATIC_CAST(nsIChangeObserver*,this)) );
mManager->Register ( content, obs );
nsCOMPtr<nsIContent> content = do_QueryInterface(mDOMNode);
nsCOMPtr<nsIChangeObserver> 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<nsIDOMElement> 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<nsIPresContext> presContext;
MenuHelpers::WebShellToPresContext ( mWebShell, getter_AddRefs(presContext) );
nsCOMPtr<nsIWebShell> 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<nsIDOMElement> element(do_QueryInterface(mDOMNode));
if(!element) {
NS_ERROR("Unable to QI dom element.");
return rv;
}
nsCOMPtr<nsIContent> contentNode;
contentNode = do_QueryInterface(element);
nsCOMPtr<nsIContent> 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<nsIDOMNode> checkedNode ( do_QueryInterface(inCheckedElement) );
nsCOMPtr<nsIDOMNode> checkedNode = do_QueryInterface(inCheckedElement);
nsAutoString myGroupName;
inCheckedElement->GetAttribute(NS_ConvertASCIItoUCS2("name"), myGroupName);
nsCOMPtr<nsIDOMNode> parent;
checkedNode->GetParentNode(getter_AddRefs(parent));
if ( !parent )
if (!parent )
return;
nsCOMPtr<nsIDOMNode> 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<nsIAtom> 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<nsIDOMElement> domElement = do_QueryInterface(mDOMNode);
nsAutoString checked;
domElement->GetAttribute(NS_ConvertASCIItoUCS2("checked"), checked);
if (checked.EqualsWithConversion("true"))
UncheckRadioSiblings(domElement);
}
return NS_OK;

Просмотреть файл

@ -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<nsIWidget> mTarget; // never set?
nsCOMPtr<nsIMenuListener> mXULCommandListener;
PRBool mIsSeparator;
nsIMenuListener * mListener;
nsIWebShell* mWebShell; // weak, document outlives us
nsCOMPtr<nsIDOMElement> 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<nsIDOMNode> mDOMNode;
PRUint8 mModifiers;
PRBool mEnabled;
PRBool mIsChecked;
PRPackedBool mIsSeparator;
PRPackedBool mEnabled;
PRPackedBool mIsChecked;
EMenuItemType mMenuType;
};