From 97fd40e7548255208f61903fc24af90735fe7102 Mon Sep 17 00:00:00 2001 From: "bryner%netscape.com" Date: Tue, 12 Mar 2002 21:49:23 +0000 Subject: [PATCH] Changing XUL menus to use a :-moz-menuactive pseudoclass rather than a menuactive attribute for styling the active item. This will allow XBL select widgets to not modify the HTML DOM. Bug 128947, r=dbaron, sr=hyatt, a=asa. git-svn-id: svn://10.0.0.236/trunk@116424 18797224-902f-48f8-a5cc-f745e15eee43 --- .../src/xul/nsXULMenuAccessible.cpp | 21 +++++++-- .../base/public/nsIStyleRuleProcessor.h | 1 + .../content/html/style/src/nsCSSParser.cpp | 1 + .../html/style/src/nsCSSStyleSheet.cpp | 36 ++++++++++++++ mozilla/content/shared/public/nsCSSAtomList.h | 1 + mozilla/dom/macbuild/dom_xulIDL.xml | 30 ++++++++++++ mozilla/dom/public/idl/xul/MANIFEST_IDL | 1 + mozilla/dom/public/idl/xul/Makefile.in | 1 + mozilla/dom/public/idl/xul/makefile.win | 1 + .../idl/xul/nsIDOMXULMenuBarElement.idl | 45 ++++++++++++++++++ .../public/idl/xul/nsIDOMXULPopupElement.idl | 3 +- mozilla/layout/style/nsCSSParser.cpp | 1 + mozilla/layout/style/nsCSSStyleSheet.cpp | 36 ++++++++++++++ mozilla/layout/style/nsIStyleRuleProcessor.h | 1 + mozilla/layout/xul/base/public/nsIMenuFrame.h | 2 + .../layout/xul/base/src/nsMenuBarFrame.cpp | 47 ++++++++++++++++++- mozilla/layout/xul/base/src/nsMenuFrame.cpp | 29 +++++++++--- mozilla/layout/xul/base/src/nsMenuFrame.h | 2 + .../layout/xul/base/src/nsMenuPopupFrame.cpp | 28 +++++++++++ mozilla/themes/classic/global/mac/menu.css | 30 ++++++------ mozilla/themes/classic/global/win/menu.css | 26 +++++----- mozilla/themes/modern/global/menu.css | 26 +++++----- .../resources/content/bindings/menu.xml | 8 ++-- .../resources/content/bindings/popup.xml | 1 + .../resources/content/bindings/toolbar.xml | 3 +- 25 files changed, 321 insertions(+), 60 deletions(-) create mode 100644 mozilla/dom/public/idl/xul/nsIDOMXULMenuBarElement.idl diff --git a/mozilla/accessible/src/xul/nsXULMenuAccessible.cpp b/mozilla/accessible/src/xul/nsXULMenuAccessible.cpp index 54eb3a13bb9..bc7fd89b412 100644 --- a/mozilla/accessible/src/xul/nsXULMenuAccessible.cpp +++ b/mozilla/accessible/src/xul/nsXULMenuAccessible.cpp @@ -42,6 +42,7 @@ #include "nsIAccessible.h" #include "nsIDOMElement.h" #include "nsIDOMXULPopupElement.h" +#include "nsIDOMXULMenuBarElement.h" // ------------------------ Menu Item ----------------------------- @@ -58,10 +59,22 @@ NS_IMETHODIMP nsXULMenuitemAccessible::GetAccState(PRUint32 *_retval) // Focused? nsCOMPtr element(do_QueryInterface(mDOMNode)); NS_ASSERTION(element, "No DOM element for menu node!"); - PRBool isFocused = PR_FALSE; - element->HasAttribute(NS_LITERAL_STRING("menuactive"), &isFocused); - if (isFocused) - *_retval |= STATE_FOCUSED; + nsCOMPtr parentNode; + mDOMNode->GetParentNode(getter_AddRefs(parentNode)); + if (parentNode) { + nsCOMPtr currentItem; + nsCOMPtr popupEl = do_QueryInterface(parentNode); + if (popupEl) + popupEl->GetActiveItem(getter_AddRefs(currentItem)); + else { + nsCOMPtr menubar = do_QueryInterface(parentNode); + if (menubar) + menubar->GetActiveMenu(getter_AddRefs(currentItem)); + } + + if (currentItem == element) + *_retval |= STATE_FOCUSED; + } // Has Popup? nsAutoString tagName; diff --git a/mozilla/content/base/public/nsIStyleRuleProcessor.h b/mozilla/content/base/public/nsIStyleRuleProcessor.h index 7079ad111cc..01066ca7542 100644 --- a/mozilla/content/base/public/nsIStyleRuleProcessor.h +++ b/mozilla/content/base/public/nsIStyleRuleProcessor.h @@ -93,6 +93,7 @@ struct RuleProcessorData { PRPackedBool mIsQuirkMode; // Possibly remove use of this in SelectorMatches? PRPackedBool mHasAttributes; // if content, content->GetAttrCount() > 0 PRPackedBool mIsChecked; // checked/selected attribute for option and select elements + PRPackedBool mIsMenuActive; // menuactive state for options/menus/menuitems nsLinkState mLinkState; // if a link, this is the state, otherwise unknown PRInt32 mEventState; // if content, eventStateMgr->GetContentState() PRInt32 mNameSpaceID; // if content, content->GetNameSapce() diff --git a/mozilla/content/html/style/src/nsCSSParser.cpp b/mozilla/content/html/style/src/nsCSSParser.cpp index 62de0569841..42724e08c5d 100644 --- a/mozilla/content/html/style/src/nsCSSParser.cpp +++ b/mozilla/content/html/style/src/nsCSSParser.cpp @@ -1557,6 +1557,7 @@ static PRBool IsPseudoClass(const nsIAtom* aAtom) (nsCSSAtoms::lastChildPseudo == aAtom) || (nsCSSAtoms::lastNodePseudo == aAtom) || (nsCSSAtoms::linkPseudo == aAtom) || + (nsCSSAtoms::menuActivePseudo == aAtom) || (nsCSSAtoms::rootPseudo == aAtom) || (nsCSSAtoms::xblBoundElementPseudo == aAtom) || (nsCSSAtoms::visitedPseudo == aAtom)); diff --git a/mozilla/content/html/style/src/nsCSSStyleSheet.cpp b/mozilla/content/html/style/src/nsCSSStyleSheet.cpp index d5347bc050f..51ceaef5422 100644 --- a/mozilla/content/html/style/src/nsCSSStyleSheet.cpp +++ b/mozilla/content/html/style/src/nsCSSStyleSheet.cpp @@ -94,6 +94,9 @@ #include "nsQuickSort.h" #ifdef MOZ_XUL #include "nsIXULContent.h" +#include "nsIDOMXULPopupElement.h" +#include "nsIDOMXULMenuBarElement.h" +#include "nsXULAtoms.h" #endif #include "nsContentUtils.h" @@ -3234,6 +3237,7 @@ RuleProcessorData::RuleProcessorData(nsIPresContext* aPresContext, mIsHTMLLink = PR_FALSE; mIsSimpleXLink = PR_FALSE; mIsChecked = PR_FALSE; + mIsMenuActive = PR_FALSE; mLinkState = eLinkState_Unknown; mEventState = NS_EVENT_STATE_UNSPECIFIED; mNameSpaceID = kNameSpaceID_Unknown; @@ -3302,14 +3306,39 @@ RuleProcessorData::RuleProcessorData(nsIPresContext* aPresContext, mIsSimpleXLink = PR_TRUE; } + // The :checked pseudoclass applies to input and option elements if (mIsHTMLContent) { PRBool isChecked = PR_FALSE; if (mContentTag == nsHTMLAtoms::option) { nsCOMPtr optEl = do_QueryInterface(mContent); optEl->GetSelected(&isChecked); } + mIsChecked = isChecked; } + + // The :-moz-menuactive pseudoclass applies to HTML option elements, + // XUL menuitem elements, and XUL menu elements. + if ((mIsHTMLContent && mContentTag == nsHTMLAtoms::option) || + (mContent->IsContentOfType(nsIContent::eXUL) && + (mContentTag == nsXULAtoms::menuitem || mContentTag == nsXULAtoms::menu))) { + + nsCOMPtr currentItem; + nsCOMPtr popupEl = do_QueryInterface(mParentContent); + if (popupEl) + popupEl->GetActiveItem(getter_AddRefs(currentItem)); + else { + nsCOMPtr menubar = do_QueryInterface(mParentContent); + if (menubar) + menubar->GetActiveMenu(getter_AddRefs(currentItem)); + } + + if (currentItem) { + nsCOMPtr element = do_QueryInterface(mContent); + if (currentItem == element) + mIsMenuActive = PR_TRUE; + } + } } } @@ -3609,6 +3638,12 @@ static PRBool SelectorMatches(RuleProcessorData &data, if (aTestState) result = data.mIsChecked ? localTrue : localFalse; } + else if (nsCSSAtoms::menuActivePseudo == pseudoClass->mAtom) { + // This pseudoclass will match on at most one child of + // a menupopup. + if (aTestState) + result = data.mIsMenuActive ? localTrue : localFalse; + } else { result = localFalse; // unknown pseudo class } @@ -4242,6 +4277,7 @@ PRBool IsStateSelector(nsCSSSelector& aSelector) (pseudoClass->mAtom == nsCSSAtoms::focusPseudo) || (pseudoClass->mAtom == nsCSSAtoms::hoverPseudo) || (pseudoClass->mAtom == nsCSSAtoms::linkPseudo) || + (pseudoClass->mAtom == nsCSSAtoms::menuActivePseudo) || (pseudoClass->mAtom == nsCSSAtoms::selectionPseudo) || (pseudoClass->mAtom == nsCSSAtoms::visitedPseudo)) { return PR_TRUE; diff --git a/mozilla/content/shared/public/nsCSSAtomList.h b/mozilla/content/shared/public/nsCSSAtomList.h index 78b03221176..76d2df0b4e1 100644 --- a/mozilla/content/shared/public/nsCSSAtomList.h +++ b/mozilla/content/shared/public/nsCSSAtomList.h @@ -85,6 +85,7 @@ CSS_ATOM(langPseudo, ":lang") CSS_ATOM(linkPseudo, ":link") CSS_ATOM(menuPseudo, ":menu") +CSS_ATOM(menuActivePseudo, ":-moz-menuactive"); CSS_ATOM(notPseudo, ":not") diff --git a/mozilla/dom/macbuild/dom_xulIDL.xml b/mozilla/dom/macbuild/dom_xulIDL.xml index 0f651ca53f7..27fcb046f7c 100644 --- a/mozilla/dom/macbuild/dom_xulIDL.xml +++ b/mozilla/dom/macbuild/dom_xulIDL.xml @@ -815,6 +815,13 @@ Text + + Name + nsIDOMXULMenuBarElement.idl + MacOS + Text + + @@ -892,6 +899,11 @@ nsIDOMXULPopupElement.idl MacOS + + Name + nsIDOMXULMenuBarElement.idl + MacOS + @@ -1656,6 +1668,13 @@ Text + + Name + nsIDOMXULMenuBarElement.idl + MacOS + Text + + @@ -1733,6 +1752,11 @@ nsIDOMXULPopupElement.idl MacOS + + Name + nsIDOMXULMenuBarElement.idl + MacOS + @@ -1821,6 +1845,12 @@ nsIDOMXULPopupElement.idl MacOS + + headers + Name + nsIDOMXULMenuBarElement.idl + MacOS + headers Name diff --git a/mozilla/dom/public/idl/xul/MANIFEST_IDL b/mozilla/dom/public/idl/xul/MANIFEST_IDL index 89b917e2fc1..95d6e70ad1a 100644 --- a/mozilla/dom/public/idl/xul/MANIFEST_IDL +++ b/mozilla/dom/public/idl/xul/MANIFEST_IDL @@ -1,3 +1,4 @@ nsIDOMXULCommandDispatcher.idl nsIDOMXULDocument.idl nsIDOMXULElement.idl +nsIDOMXULMenuBarElement.idl diff --git a/mozilla/dom/public/idl/xul/Makefile.in b/mozilla/dom/public/idl/xul/Makefile.in index c57f4a788b3..e0f257dba8a 100644 --- a/mozilla/dom/public/idl/xul/Makefile.in +++ b/mozilla/dom/public/idl/xul/Makefile.in @@ -45,6 +45,7 @@ XPIDLSRCS = \ nsIDOMXULSelectCntrlEl.idl \ nsIDOMXULSelectCntrlItemEl.idl \ nsIDOMXULMultSelectCntrlEl.idl \ + nsIDOMXULMenuBarElement.idl \ $(NULL) include $(topsrcdir)/config/rules.mk diff --git a/mozilla/dom/public/idl/xul/makefile.win b/mozilla/dom/public/idl/xul/makefile.win index 1beb2253fa8..4c6ee81ede9 100644 --- a/mozilla/dom/public/idl/xul/makefile.win +++ b/mozilla/dom/public/idl/xul/makefile.win @@ -41,6 +41,7 @@ XPIDLSRCS = \ .\nsIDOMXULSelectCntrlEl.idl \ .\nsIDOMXULSelectCntrlItemEl.idl \ .\nsIDOMXULMultSelectCntrlEl.idl \ + .\nsIDOMXULMenuBarElement.idl \ $(NULL) include <$(DEPTH)\config\rules.mak> diff --git a/mozilla/dom/public/idl/xul/nsIDOMXULMenuBarElement.idl b/mozilla/dom/public/idl/xul/nsIDOMXULMenuBarElement.idl new file mode 100644 index 00000000000..2f201b89208 --- /dev/null +++ b/mozilla/dom/public/idl/xul/nsIDOMXULMenuBarElement.idl @@ -0,0 +1,45 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2002 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Brian Ryner + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "nsIDOMXULElement.idl" + +[scriptable, uuid(159c637c-1dd2-11b2-ab18-811904c2e7fb)] +interface nsIDOMXULMenuBarElement : nsIDOMXULElement { + + attribute nsIDOMElement activeMenu; + +}; diff --git a/mozilla/dom/public/idl/xul/nsIDOMXULPopupElement.idl b/mozilla/dom/public/idl/xul/nsIDOMXULPopupElement.idl index 1922750811e..99856d6c2b6 100644 --- a/mozilla/dom/public/idl/xul/nsIDOMXULPopupElement.idl +++ b/mozilla/dom/public/idl/xul/nsIDOMXULPopupElement.idl @@ -54,7 +54,8 @@ interface nsIDOMXULPopupElement : nsIDOMXULElement { const unsigned short AFTER_POINTER = 11; attribute DOMString position; - + attribute nsIDOMElement activeItem; + void showPopup(in unsigned short alignment, in nsIDOMElement target, in nsIDOMElement anchor); diff --git a/mozilla/layout/style/nsCSSParser.cpp b/mozilla/layout/style/nsCSSParser.cpp index 62de0569841..42724e08c5d 100644 --- a/mozilla/layout/style/nsCSSParser.cpp +++ b/mozilla/layout/style/nsCSSParser.cpp @@ -1557,6 +1557,7 @@ static PRBool IsPseudoClass(const nsIAtom* aAtom) (nsCSSAtoms::lastChildPseudo == aAtom) || (nsCSSAtoms::lastNodePseudo == aAtom) || (nsCSSAtoms::linkPseudo == aAtom) || + (nsCSSAtoms::menuActivePseudo == aAtom) || (nsCSSAtoms::rootPseudo == aAtom) || (nsCSSAtoms::xblBoundElementPseudo == aAtom) || (nsCSSAtoms::visitedPseudo == aAtom)); diff --git a/mozilla/layout/style/nsCSSStyleSheet.cpp b/mozilla/layout/style/nsCSSStyleSheet.cpp index d5347bc050f..51ceaef5422 100644 --- a/mozilla/layout/style/nsCSSStyleSheet.cpp +++ b/mozilla/layout/style/nsCSSStyleSheet.cpp @@ -94,6 +94,9 @@ #include "nsQuickSort.h" #ifdef MOZ_XUL #include "nsIXULContent.h" +#include "nsIDOMXULPopupElement.h" +#include "nsIDOMXULMenuBarElement.h" +#include "nsXULAtoms.h" #endif #include "nsContentUtils.h" @@ -3234,6 +3237,7 @@ RuleProcessorData::RuleProcessorData(nsIPresContext* aPresContext, mIsHTMLLink = PR_FALSE; mIsSimpleXLink = PR_FALSE; mIsChecked = PR_FALSE; + mIsMenuActive = PR_FALSE; mLinkState = eLinkState_Unknown; mEventState = NS_EVENT_STATE_UNSPECIFIED; mNameSpaceID = kNameSpaceID_Unknown; @@ -3302,14 +3306,39 @@ RuleProcessorData::RuleProcessorData(nsIPresContext* aPresContext, mIsSimpleXLink = PR_TRUE; } + // The :checked pseudoclass applies to input and option elements if (mIsHTMLContent) { PRBool isChecked = PR_FALSE; if (mContentTag == nsHTMLAtoms::option) { nsCOMPtr optEl = do_QueryInterface(mContent); optEl->GetSelected(&isChecked); } + mIsChecked = isChecked; } + + // The :-moz-menuactive pseudoclass applies to HTML option elements, + // XUL menuitem elements, and XUL menu elements. + if ((mIsHTMLContent && mContentTag == nsHTMLAtoms::option) || + (mContent->IsContentOfType(nsIContent::eXUL) && + (mContentTag == nsXULAtoms::menuitem || mContentTag == nsXULAtoms::menu))) { + + nsCOMPtr currentItem; + nsCOMPtr popupEl = do_QueryInterface(mParentContent); + if (popupEl) + popupEl->GetActiveItem(getter_AddRefs(currentItem)); + else { + nsCOMPtr menubar = do_QueryInterface(mParentContent); + if (menubar) + menubar->GetActiveMenu(getter_AddRefs(currentItem)); + } + + if (currentItem) { + nsCOMPtr element = do_QueryInterface(mContent); + if (currentItem == element) + mIsMenuActive = PR_TRUE; + } + } } } @@ -3609,6 +3638,12 @@ static PRBool SelectorMatches(RuleProcessorData &data, if (aTestState) result = data.mIsChecked ? localTrue : localFalse; } + else if (nsCSSAtoms::menuActivePseudo == pseudoClass->mAtom) { + // This pseudoclass will match on at most one child of + // a menupopup. + if (aTestState) + result = data.mIsMenuActive ? localTrue : localFalse; + } else { result = localFalse; // unknown pseudo class } @@ -4242,6 +4277,7 @@ PRBool IsStateSelector(nsCSSSelector& aSelector) (pseudoClass->mAtom == nsCSSAtoms::focusPseudo) || (pseudoClass->mAtom == nsCSSAtoms::hoverPseudo) || (pseudoClass->mAtom == nsCSSAtoms::linkPseudo) || + (pseudoClass->mAtom == nsCSSAtoms::menuActivePseudo) || (pseudoClass->mAtom == nsCSSAtoms::selectionPseudo) || (pseudoClass->mAtom == nsCSSAtoms::visitedPseudo)) { return PR_TRUE; diff --git a/mozilla/layout/style/nsIStyleRuleProcessor.h b/mozilla/layout/style/nsIStyleRuleProcessor.h index 7079ad111cc..01066ca7542 100644 --- a/mozilla/layout/style/nsIStyleRuleProcessor.h +++ b/mozilla/layout/style/nsIStyleRuleProcessor.h @@ -93,6 +93,7 @@ struct RuleProcessorData { PRPackedBool mIsQuirkMode; // Possibly remove use of this in SelectorMatches? PRPackedBool mHasAttributes; // if content, content->GetAttrCount() > 0 PRPackedBool mIsChecked; // checked/selected attribute for option and select elements + PRPackedBool mIsMenuActive; // menuactive state for options/menus/menuitems nsLinkState mLinkState; // if a link, this is the state, otherwise unknown PRInt32 mEventState; // if content, eventStateMgr->GetContentState() PRInt32 mNameSpaceID; // if content, content->GetNameSapce() diff --git a/mozilla/layout/xul/base/public/nsIMenuFrame.h b/mozilla/layout/xul/base/public/nsIMenuFrame.h index 30643013e1e..68141a33bc5 100644 --- a/mozilla/layout/xul/base/public/nsIMenuFrame.h +++ b/mozilla/layout/xul/base/public/nsIMenuFrame.h @@ -84,6 +84,8 @@ public: NS_IMETHOD GetActiveChild(nsIDOMElement** aResult)=0; NS_IMETHOD SetActiveChild(nsIDOMElement* aChild)=0; + + NS_IMETHOD NotifyStateChanged(nsIMenuFrame* aOtherMenuFrame) = 0; }; #endif diff --git a/mozilla/layout/xul/base/src/nsMenuBarFrame.cpp b/mozilla/layout/xul/base/src/nsMenuBarFrame.cpp index 8015d670be4..e5673cc64e9 100644 --- a/mozilla/layout/xul/base/src/nsMenuBarFrame.cpp +++ b/mozilla/layout/xul/base/src/nsMenuBarFrame.cpp @@ -58,6 +58,7 @@ #include "nsMenuPopupFrame.h" #include "nsGUIEvent.h" #include "nsUnicharUtils.h" +#include "nsIDOMXULMenuBarElement.h" #ifdef XP_WIN #include "nsISound.h" #include "nsWidgetsCID.h" @@ -172,7 +173,7 @@ nsMenuBarFrame::IsOpen() mCurrentMenu->MenuIsOpen(isOpen); if (isOpen) { return PR_TRUE; - } + } } return PR_FALSE; } @@ -199,6 +200,8 @@ nsMenuBarFrame::SetActive(PRBool aActiveFlag) void nsMenuBarFrame::ToggleMenuActiveState() { + nsIMenuFrame* oldCurrent = mCurrentMenu; + if (mIsActive) { // Deactivate the menu bar mIsActive = PR_FALSE; @@ -221,7 +224,7 @@ nsMenuBarFrame::ToggleMenuActiveState() InstallKeyboardNavigator(); // Set the active menu to be the top left item (e.g., the File menu). - // We use an attribute called "menuactive" to track the current active menu. + // We use the -moz-menuactive pseudoclass to track the current active menu. nsIMenuFrame* firstFrame; GetNextMenuItem(nsnull, &firstFrame); if (firstFrame) { @@ -231,6 +234,25 @@ nsMenuBarFrame::ToggleMenuActiveState() mCurrentMenu = firstFrame; } } + + // Update the state on the menubar content node + nsCOMPtr menubar = do_QueryInterface(mContent); + nsCOMPtr newActive; + if (mCurrentMenu) { + nsIFrame* frame = nsnull; + CallQueryInterface(mCurrentMenu, &frame); + nsCOMPtr content; + frame->GetContent(getter_AddRefs(content)); + newActive = do_QueryInterface(content); + } + menubar->SetActiveMenu(newActive); + + // Now send a CSS state change notification + if (mCurrentMenu) + mCurrentMenu->NotifyStateChanged(oldCurrent); + else if (oldCurrent) + oldCurrent->NotifyStateChanged(nsnull); + } static void GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aFrame, nsIFrame* aChild, @@ -515,6 +537,8 @@ NS_IMETHODIMP nsMenuBarFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem) PRBool wasOpen = PR_FALSE; // Unset the current child. + nsIMenuFrame* oldMenuFrame = mCurrentMenu; + if (mCurrentMenu) { mCurrentMenu->MenuIsOpen(wasOpen); mCurrentMenu->SelectMenu(PR_FALSE); @@ -533,6 +557,25 @@ NS_IMETHODIMP nsMenuBarFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem) mCurrentMenu = aMenuItem; + // Update the menubar content node + nsCOMPtr menubar = do_QueryInterface(mContent); + nsCOMPtr newActive; + if (mCurrentMenu) { + nsIFrame* frame = nsnull; + CallQueryInterface(mCurrentMenu, &frame); + nsCOMPtr content; + frame->GetContent(getter_AddRefs(content)); + newActive = do_QueryInterface(content); + } + + menubar->SetActiveMenu(newActive); + + // Now send a CSS state change notification + if (mCurrentMenu) + mCurrentMenu->NotifyStateChanged(oldMenuFrame); + else if (oldMenuFrame) + oldMenuFrame->NotifyStateChanged(nsnull); + return NS_OK; } diff --git a/mozilla/layout/xul/base/src/nsMenuFrame.cpp b/mozilla/layout/xul/base/src/nsMenuFrame.cpp index 4d49e16929b..822aa0642f2 100644 --- a/mozilla/layout/xul/base/src/nsMenuFrame.cpp +++ b/mozilla/layout/xul/base/src/nsMenuFrame.cpp @@ -85,6 +85,7 @@ #include "nsGUIEvent.h" #include "nsIEventListenerManager.h" #include "nsIEventStateManager.h" +#include "nsCSSAtoms.h" #define NS_MENU_POPUP_LIST_INDEX 0 @@ -583,14 +584,10 @@ nsMenuFrame::SelectMenu(PRBool aActivateFlag) nsAutoString domEventToFire; if (aActivateFlag) { - // Highlight the menu. - mContent->SetAttr(kNameSpaceID_None, nsXULAtoms::menuactive, NS_LITERAL_STRING("true"), PR_TRUE); // The menuactivated event is used by accessibility to track the user's movements through menus domEventToFire.Assign(NS_LITERAL_STRING("DOMMenuItemActive")); } else { - // Unhighlight the menu. - mContent->UnsetAttr(kNameSpaceID_None, nsXULAtoms::menuactive, PR_TRUE); domEventToFire.Assign(NS_LITERAL_STRING("DOMMenuItemInactive")); } @@ -1307,9 +1304,9 @@ nsMenuFrame::Notify(nsITimer* aTimer) // Our timer has fired. if (aTimer == mOpenTimer.get()) { if (!mMenuOpen && mMenuParent) { - nsAutoString active; - mContent->GetAttr(kNameSpaceID_None, nsXULAtoms::menuactive, active); - if (active.Equals(NS_LITERAL_STRING("true"))) { + nsIMenuFrame* activeMenu = nsnull; + mMenuParent->GetCurrentMenuItem(&activeMenu); + if (activeMenu == this) { // We're still the active menu. Make sure all submenus/timers are closed // before opening this one mMenuParent->KillPendingTimers(); @@ -2094,6 +2091,24 @@ nsMenuFrame::GetScrollableView(nsIScrollableView** aView) return NS_OK; } +NS_IMETHODIMP +nsMenuFrame::NotifyStateChanged(nsIMenuFrame* aOtherMenuFrame) +{ + nsCOMPtr otherContent; + if (aOtherMenuFrame) { + nsIFrame* otherFrame = nsnull; + CallQueryInterface(aOtherMenuFrame, &otherFrame); + otherFrame->GetContent(getter_AddRefs(otherContent)); + } + + nsCOMPtr document; + mContent->GetDocument(*getter_AddRefs(document)); + if (document) + document->ContentStatesChanged(mContent, otherContent, nsCSSAtoms::menuActivePseudo); + + return NS_OK; +} + /* Need to figure out what this does. NS_IMETHODIMP nsMenuFrame::GetBoxInfo(nsIPresContext* aPresContext, const nsHTMLReflowState& aReflowState, nsBoxInfo& aSize) diff --git a/mozilla/layout/xul/base/src/nsMenuFrame.h b/mozilla/layout/xul/base/src/nsMenuFrame.h index 35c514f0ebe..b2e16278a63 100644 --- a/mozilla/layout/xul/base/src/nsMenuFrame.h +++ b/mozilla/layout/xul/base/src/nsMenuFrame.h @@ -167,6 +167,8 @@ public: NS_IMETHOD MarkChildrenStyleChange(); NS_IMETHOD MarkAsGenerated(); + NS_IMETHOD NotifyStateChanged(nsIMenuFrame* aOtherFrame); + // nsIScrollableViewProvider methods NS_IMETHOD GetScrollableView(nsIScrollableView** aView); diff --git a/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp b/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp index 63ae99bfc9d..7dc28775928 100644 --- a/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp +++ b/mozilla/layout/xul/base/src/nsMenuPopupFrame.cpp @@ -69,6 +69,7 @@ #include "nsIFrameManager.h" #include "nsGUIEvent.h" #include "nsIRootBox.h" +#include "nsIDOMXULPopupElement.h" #ifdef XP_WIN #include "nsISound.h" #endif @@ -1401,6 +1402,8 @@ NS_IMETHODIMP nsMenuPopupFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem) return NS_OK; // Unset the current child. + nsIMenuFrame* oldMenuFrame = nsnull; + if (mCurrentMenu) { PRBool isOpen = PR_FALSE; mCurrentMenu->MenuIsOpen(isOpen); @@ -1423,6 +1426,8 @@ NS_IMETHODIMP nsMenuPopupFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem) mCloseTimer->Init(this, menuDelay, NS_PRIORITY_HIGHEST); mTimerMenu = mCurrentMenu; } + + oldMenuFrame = mCurrentMenu; } // Set the new child. @@ -1433,6 +1438,24 @@ NS_IMETHODIMP nsMenuPopupFrame::SetCurrentMenuItem(nsIMenuFrame* aMenuItem) mCurrentMenu = aMenuItem; + // Update the content node's idea of the current item. + nsCOMPtr newContent; + if (mCurrentMenu) { + nsIFrame* frame = nsnull; + CallQueryInterface(mCurrentMenu, &frame); + frame->GetContent(getter_AddRefs(newContent)); + } + + nsCOMPtr popupEl = do_QueryInterface(mContent); + nsCOMPtr domEl = do_QueryInterface(newContent); + popupEl->SetActiveItem(domEl); + + // Send menuactive state notification. + if (mCurrentMenu) + mCurrentMenu->NotifyStateChanged(oldMenuFrame); + else if (oldMenuFrame) + oldMenuFrame->NotifyStateChanged(nsnull); + return NS_OK; } @@ -1846,6 +1869,11 @@ nsMenuPopupFrame::HandleEvent(nsIPresContext* aPresContext, NS_IMETHODIMP nsMenuPopupFrame::Destroy(nsIPresContext* aPresContext) { + // Make sure the content node doesn't think we still have an active item. + nsCOMPtr popupEl = do_QueryInterface(mContent); + if (popupEl) + popupEl->SetActiveItem(nsnull); + return nsBoxFrame::Destroy(aPresContext); } diff --git a/mozilla/themes/classic/global/mac/menu.css b/mozilla/themes/classic/global/mac/menu.css index 82f78db4e8a..67d7ed02be1 100644 --- a/mozilla/themes/classic/global/mac/menu.css +++ b/mozilla/themes/classic/global/mac/menu.css @@ -45,8 +45,8 @@ menuitem[default="true"] { menu[disabled="true"], menuitem[disabled="true"], -menu[menuactive="true"][disabled="true"], -menuitem[menuactive="true"][disabled="true"] { +menu[disabled="true"]:-moz-menuactive, +menuitem[disabled="true"]:-moz-menuactive { background-color: transparent !important; color: GrayText !important; } @@ -92,11 +92,11 @@ menuitem[menuactive="true"][disabled="true"] { } .menu-right[disabled="true"], -.menu-right[menuactive="true"][disabled="true"] { +menu:-moz-menuactive > .menu-right[disabled="true"] { list-style-image: url("chrome://global/skin/menu/menu-arrow-dis.gif); } -.menu-right[menuactive="true"] { +menu:-moz-menuactive > .menu-right { list-style-image: url("chrome://global/skin/menu/menu-arrow-hov.gif"); } @@ -108,14 +108,14 @@ menubar > menu { margin: 1px 0px 1px 0px; } -menubar > menu[menuactive="true"] { +menubar > menu:-moz-menuactive { border-top: 1px solid ThreeDHighlight; border-right: 1px solid ThreeDShadow; border-bottom: 1px solid ThreeDShadow; border-left: 1px solid ThreeDHighlight; } -menubar > menu[menuactive="true"][open="true"] { +menubar > menu[open="true"]:-moz-menuactive { border-top: 1px solid ThreeDShadow; border-right: 1px solid ThreeDHighlight; border-bottom: 1px solid ThreeDHighlight; @@ -144,10 +144,10 @@ popup > menuitem { max-width: 42em; } -menupopup > menu[menuactive="true"], -menupopup > menuitem[menuactive="true"], -popup > menu[menuactive="true"], -popup > menuitem[menuactive="true"] { +menupopup > menu:-moz-menuactive, +menupopup > menuitem:-moz-menuactive, +popup > menu:-moz-menuactive, +popup > menuitem:-moz-menuactive { background-color: -moz-mac-menuselect; color: -moz-mac-menutextselect; } @@ -162,7 +162,7 @@ menuitem[checked="true"][disabled="true"] { list-style-image: url("chrome://global/skin/menu/menu-check-dis.gif"); } -menuitem[checked="true"][menuactive="true"] { +menuitem[checked="true"]:-moz-menuactive { list-style-image: url("chrome://global/skin/menu/menu-check-hov.gif"); } @@ -172,7 +172,7 @@ menuitem[checked="true"][type="radio"] { list-style-image: url("chrome://global/skin/menu/menu-radio.gif"); } -menuitem[checked="true"][type="radio"][menuactive="true"] { +menuitem[checked="true"][type="radio"]:-moz-menuactive { list-style-image: url("chrome://global/skin/menu/menu-radio-hov.gif"); } @@ -194,8 +194,8 @@ menulist > menupopup > menuitem[selected="true"], list-style-image: url("chrome://global/skin/menu/menu-radio.gif"); } -menulist > menupopup > menuitem[menuactive="true"][selected="true"], -.menulist-menupopup > menuitem[menuactive="true"][selected="true"] { +menulist > menupopup > menuitem[selected="true"]:-moz-menuactive, +.menulist-menupopup > menuitem[selected="true"]:-moz-menuactive { list-style-image: url("chrome://global/skin/menu/menu-radio-hov.gif"); } @@ -227,4 +227,4 @@ menulist > menupopup > menuseparator, .treecell-popupcell-menu { margin-left: -2px; list-style-image: url("chrome://global/skin/columnselect.gif"); -} \ No newline at end of file +} diff --git a/mozilla/themes/classic/global/win/menu.css b/mozilla/themes/classic/global/win/menu.css index c42fd388c8c..939e34bb57f 100644 --- a/mozilla/themes/classic/global/win/menu.css +++ b/mozilla/themes/classic/global/win/menu.css @@ -43,8 +43,8 @@ menuitem[default="true"] { } menu[disabled="true"], menuitem[disabled="true"], -menu[menuactive="true"][disabled="true"], -menuitem[menuactive="true"][disabled="true"] { +menu[disabled="true"]:-moz-menuactive, +menuitem[disabled="true"]:-moz-menuactive { color: GrayText; } @@ -88,7 +88,7 @@ menuitem[menuactive="true"][disabled="true"] { list-style-image: url("chrome://global/skin/menu/menu-arrow.gif"); } -.menu-right[menuactive="true"] { +menu:-moz-menuactive > .menu-right { list-style-image: url("chrome://global/skin/menu/menu-arrow-hover.gif"); } @@ -104,14 +104,14 @@ menubar > menu { margin: 1px 0px 1px 0px; } -menubar > menu[menuactive="true"] { +menubar > menu:-moz-menuactive { border-top: 1px solid ThreeDHighlight; border-right: 1px solid ThreeDShadow; border-bottom: 1px solid ThreeDShadow; border-left: 1px solid ThreeDHighlight; } -menubar > menu[menuactive="true"][open="true"] { +menubar > menu[open="true"]:-moz-menuactive { border-top: 1px solid ThreeDShadow; border-right: 1px solid ThreeDHighlight; border-bottom: 1px solid ThreeDHighlight; @@ -140,10 +140,10 @@ popup > menuitem { max-width: 42em; } -menupopup > menu[menuactive="true"], -menupopup > menuitem[menuactive="true"], -popup > menu[menuactive="true"], -popup > menuitem[menuactive="true"] { +menupopup > menu:-moz-menuactive, +menupopup > menuitem:-moz-menuactive, +popup > menu:-moz-menuactive, +popup > menuitem:-moz-menuactive { background-color: Highlight; color: HighlightText; } @@ -168,7 +168,7 @@ menulist > menupopup > menu > .menu-iconic-left { display: none; } -menulist > menupopup > menuitem[menuactive="true"] { +menulist > menupopup > menuitem:-moz-menuactive { border: 1px dotted #F5DB95; } @@ -182,7 +182,7 @@ menuitem[checked="true"][disabled="true"] { list-style-image: url("chrome://global/skin/menu/menu-check-disabled.gif"); } -menuitem[checked="true"][menuactive="true"] { +menuitem[checked="true"]:-moz-menuactive { list-style-image: url("chrome://global/skin/menu/menu-check-hover.gif"); } @@ -196,7 +196,7 @@ menuitem[checked="true"][type="radio"][disabled="true"] { list-style-image: url("chrome://global/skin/menu/menu-radio-disabled.gif"); } -menuitem[checked="true"][type="radio"][menuactive="true"] { +menuitem[checked="true"][type="radio"]:-moz-menuactive { list-style-image: url("chrome://global/skin/menu/menu-radio-hover.gif"); } @@ -227,4 +227,4 @@ menulist > menupopup > menuseparator, .treecell-popupcell-menu { margin-left: -2px; list-style-image: url("chrome://global/skin/columnselect.gif"); -} \ No newline at end of file +} diff --git a/mozilla/themes/modern/global/menu.css b/mozilla/themes/modern/global/menu.css index b615225db7a..eaf0f607a3e 100644 --- a/mozilla/themes/modern/global/menu.css +++ b/mozilla/themes/modern/global/menu.css @@ -57,8 +57,8 @@ menuitem[default="true"] { menu[disabled="true"], menuitem[disabled="true"], -menu[menuactive="true"][disabled="true"], -menuitem[menuactive="true"][disabled="true"] { +menu[disabled="true"]:-moz-menuactive, +menuitem[disabled="true"]:-moz-menuactive { color: #838E9B; } @@ -102,7 +102,7 @@ menuitem[menuactive="true"][disabled="true"] { list-style-image: url("chrome://global/skin/menu/menu-arrow.gif"); } -.menu-right[menuactive="true"] { +menu:-moz-menuactive > .menu-right { list-style-image: url("chrome://global/skin/menu/menu-arrow-hov.gif"); } @@ -118,11 +118,11 @@ menubar > menu { margin: 1px 0px 1px 0px; } -menubar > menu[menuactive="true"] { +menubar > menu:-moz-menuactive { border: 1px outset #DDE3EB; } -menubar > menu[menuactive="true"][open="true"] { +menubar > menu[open="true"]:-moz-menuactive { border-style: inset; } @@ -148,10 +148,10 @@ popup > menuitem { max-width: 42em; } -menupopup > menu[menuactive="true"], -menupopup > menuitem[menuactive="true"], -popup > menu[menuactive="true"], -popup > menuitem[menuactive="true"] { +menupopup > menu:-moz-menuactive, +menupopup > menuitem:-moz-menuactive, +popup > menu:-moz-menuactive, +popup > menuitem:-moz-menuactive { background-color: #424F63; color: #FFFFFF; } @@ -175,7 +175,7 @@ menulist > menupopup > menuitem[selected="true"] { list-style-image: url("chrome://global/skin/menu/menu-check.gif"); } -menulist > menupopup > menuitem[menuactive="true"][selected="true"] { +menulist > menupopup > menuitem[selected="true"]:-moz-menuactive { list-style-image: url("chrome://global/skin/menu/menu-check-hov.gif"); } @@ -189,7 +189,7 @@ menuitem[checked="true"][disabled="true"] { list-style-image: url("chrome://global/skin/menu/menu-check-dis.gif"); } -menuitem[checked="true"][menuactive="true"] { +menuitem[checked="true"]:-moz-menuactive { list-style-image: url("chrome://global/skin/menu/menu-check-hov.gif"); } @@ -203,7 +203,7 @@ menuitem[checked="true"][type="radio"][disabled="true"] { list-style-image: url("chrome://global/skin/menu/menu-radio-dis.gif"); } -menuitem[checked="true"][type="radio"][menuactive="true"] { +menuitem[checked="true"][type="radio"]:-moz-menuactive { list-style-image: url("chrome://global/skin/menu/menu-radio-hov.gif"); } @@ -234,4 +234,4 @@ menulist > menupopup > menuseparator, .treecell-popupcell-menu { margin-left: -2px; list-style-image: url("chrome://global/skin/tree/columnpicker.gif"); -} \ No newline at end of file +} diff --git a/mozilla/xpfe/global/resources/content/bindings/menu.xml b/mozilla/xpfe/global/resources/content/bindings/menu.xml index fd4e4e0edaf..103ed45a7a5 100644 --- a/mozilla/xpfe/global/resources/content/bindings/menu.xml +++ b/mozilla/xpfe/global/resources/content/bindings/menu.xml @@ -29,7 +29,7 @@ - + @@ -71,7 +71,7 @@ + inherits="selected,disabled,checked"> @@ -91,7 +91,7 @@ - + @@ -112,4 +112,4 @@ - \ No newline at end of file + diff --git a/mozilla/xpfe/global/resources/content/bindings/popup.xml b/mozilla/xpfe/global/resources/content/bindings/popup.xml index 529771d7418..d7b2d70cd10 100644 --- a/mozilla/xpfe/global/resources/content/bindings/popup.xml +++ b/mozilla/xpfe/global/resources/content/bindings/popup.xml @@ -18,6 +18,7 @@ + - + +