LCOV - app.info - layout/xul/base/src/nsMenuBarFrame.cpp

LCOV - code coverage report
| Current view: | directory - layout/xul/base/src - nsMenuBarFrame.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 198 | 0 | 0.0 %
| Date: | 2012-06-02 | Functions: | 23 | 0 | 0.0 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is mozilla.org code.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Netscape Communications Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *   Dan Rosen <dr@netscape.com>
          24                 :  *   Dean Tessman <dean_tessman@hotmail.com>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : #include "nsMenuBarFrame.h"
          41                 : #include "nsIServiceManager.h"
          42                 : #include "nsIContent.h"
          43                 : #include "prtypes.h"
          44                 : #include "nsIAtom.h"
          45                 : #include "nsPresContext.h"
          46                 : #include "nsStyleContext.h"
          47                 : #include "nsCSSRendering.h"
          48                 : #include "nsINameSpaceManager.h"
          49                 : #include "nsIDocument.h"
          50                 : #include "nsIDOMEventTarget.h"
          51                 : #include "nsGkAtoms.h"
          52                 : #include "nsMenuFrame.h"
          53                 : #include "nsMenuPopupFrame.h"
          54                 : #include "nsGUIEvent.h"
          55                 : #include "nsUnicharUtils.h"
          56                 : #include "nsIDOMDocument.h"
          57                 : #include "nsPIDOMWindow.h"
          58                 : #include "nsIInterfaceRequestorUtils.h"
          59                 : #include "nsCSSFrameConstructor.h"
          60                 : #ifdef XP_WIN
          61                 : #include "nsISound.h"
          62                 : #include "nsWidgetsCID.h"
          63                 : #endif
          64                 : #include "nsContentUtils.h"
          65                 : #include "nsUTF8Utils.h"
          66                 :
          67                 :
          68                 : //
          69                 : // NS_NewMenuBarFrame
          70                 : //
          71                 : // Wrapper for creating a new menu Bar container
          72                 : //
          73                 : nsIFrame*
          74               0 : NS_NewMenuBarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
          75                 : {
          76               0 :   return new (aPresShell) nsMenuBarFrame (aPresShell, aContext);
          77                 : }
          78                 :
          79               0 : NS_IMPL_FRAMEARENA_HELPERS(nsMenuBarFrame)
          80                 :
          81               0 : NS_QUERYFRAME_HEAD(nsMenuBarFrame)
          82               0 :   NS_QUERYFRAME_ENTRY(nsMenuBarFrame)
          83               0 : NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
          84                 :
          85                 : //
          86                 : // nsMenuBarFrame cntr
          87                 : //
          88               0 : nsMenuBarFrame::nsMenuBarFrame(nsIPresShell* aShell, nsStyleContext* aContext):
          89                 :   nsBoxFrame(aShell, aContext),
          90                 :     mMenuBarListener(nsnull),
          91                 :     mStayActive(false),
          92                 :     mIsActive(false),
          93                 :     mCurrentMenu(nsnull),
          94               0 :     mTarget(nsnull)
          95                 : {
          96               0 : } // cntr
          97                 :
          98                 : NS_IMETHODIMP
          99               0 : nsMenuBarFrame::Init(nsIContent*      aContent,
         100                 :                      nsIFrame*        aParent,
         101                 :                      nsIFrame*        aPrevInFlow)
         102                 : {
         103               0 :   nsresult  rv = nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
         104                 :
         105                 :   // Create the menu bar listener.
         106               0 :   mMenuBarListener = new nsMenuBarListener(this);
         107               0 :   NS_IF_ADDREF(mMenuBarListener);
         108               0 :   if (! mMenuBarListener)
         109               0 :     return NS_ERROR_OUT_OF_MEMORY;
         110                 :
         111                 :   // Hook up the menu bar as a key listener on the whole document.  It will see every
         112                 :   // key press that occurs, but after everyone else does.
         113               0 :   nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(aContent->GetDocument());
         114                 :
         115               0 :   mTarget = target;
         116                 :
         117                 :   // Also hook up the listener to the window listening for focus events. This is so we can keep proper
         118                 :   // state as the user alt-tabs through processes.
         119                 :
         120               0 :   target->AddEventListener(NS_LITERAL_STRING("keypress"), mMenuBarListener, false);
         121               0 :   target->AddEventListener(NS_LITERAL_STRING("keydown"), mMenuBarListener, false);
         122               0 :   target->AddEventListener(NS_LITERAL_STRING("keyup"), mMenuBarListener, false);
         123                 :
         124                 :   // mousedown event should be handled in all phase
         125               0 :   target->AddEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, true);
         126               0 :   target->AddEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, false);
         127               0 :   target->AddEventListener(NS_LITERAL_STRING("blur"), mMenuBarListener, true);
         128                 :
         129               0 :   return rv;
         130                 : }
         131                 :
         132                 : NS_IMETHODIMP
         133               0 : nsMenuBarFrame::SetActive(bool aActiveFlag)
         134                 : {
         135                 :   // If the activity is not changed, there is nothing to do.
         136               0 :   if (mIsActive == aActiveFlag)
         137               0 :     return NS_OK;
         138                 :
         139               0 :   if (!aActiveFlag) {
         140                 :     // Don't deactivate when switching between menus on the menubar.
         141               0 :     if (mStayActive)
         142               0 :       return NS_OK;
         143                 :
         144                 :     // if there is a request to deactivate the menu bar, check to see whether
         145                 :     // there is a menu popup open for the menu bar. In this case, don't
         146                 :     // deactivate the menu bar.
         147               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
         148               0 :     if (pm && pm->IsPopupOpenForMenuParent(this))
         149               0 :       return NS_OK;
         150                 :   }
         151                 :
         152               0 :   mIsActive = aActiveFlag;
         153               0 :   if (mIsActive) {
         154               0 :     InstallKeyboardNavigator();
         155                 :   }
         156                 :   else {
         157               0 :     mActiveByKeyboard = false;
         158               0 :     RemoveKeyboardNavigator();
         159                 :   }
         160                 :
         161               0 :   NS_NAMED_LITERAL_STRING(active, "DOMMenuBarActive");
         162               0 :   NS_NAMED_LITERAL_STRING(inactive, "DOMMenuBarInactive");
         163                 :
         164               0 :   FireDOMEvent(mIsActive ? active : inactive, mContent);
         165                 :
         166               0 :   return NS_OK;
         167                 : }
         168                 :
         169                 : nsMenuFrame*
         170               0 : nsMenuBarFrame::ToggleMenuActiveState()
         171                 : {
         172               0 :   if (mIsActive) {
         173                 :     // Deactivate the menu bar
         174               0 :     SetActive(false);
         175               0 :     if (mCurrentMenu) {
         176               0 :       nsMenuFrame* closeframe = mCurrentMenu;
         177               0 :       closeframe->SelectMenu(false);
         178               0 :       mCurrentMenu = nsnull;
         179               0 :       return closeframe;
         180                 :     }
         181                 :   }
         182                 :   else {
         183                 :     // if the menu bar is already selected (eg. mouseover), deselect it
         184               0 :     if (mCurrentMenu)
         185               0 :       mCurrentMenu->SelectMenu(false);
         186                 :
         187                 :     // Activate the menu bar
         188               0 :     SetActive(true);
         189                 :
         190                 :     // Set the active menu to be the top left item (e.g., the File menu).
         191                 :     // We use an attribute called "menuactive" to track the current
         192                 :     // active menu.
         193               0 :     nsMenuFrame* firstFrame = nsXULPopupManager::GetNextMenuItem(this, nsnull, false);
         194               0 :     if (firstFrame) {
         195               0 :       firstFrame->SelectMenu(true);
         196                 :
         197                 :       // Track this item for keyboard navigation.
         198               0 :       mCurrentMenu = firstFrame;
         199                 :     }
         200                 :   }
         201                 :
         202               0 :   return nsnull;
         203                 : }
         204                 :
         205                 : static void
         206               0 : GetInsertionPoint(nsIPresShell* aShell, nsIFrame* aFrame, nsIFrame* aChild,
         207                 :                   nsIFrame** aResult)
         208                 : {
         209               0 :   nsIContent* child = nsnull;
         210               0 :   if (aChild)
         211               0 :     child = aChild->GetContent();
         212               0 :   aShell->FrameConstructor()->GetInsertionPoint(aFrame, child, aResult);
         213               0 : }
         214                 :
         215                 : nsMenuFrame*
         216               0 : nsMenuBarFrame::FindMenuWithShortcut(nsIDOMKeyEvent* aKeyEvent)
         217                 : {
         218                 :   PRUint32 charCode;
         219               0 :   aKeyEvent->GetCharCode(&charCode);
         220                 :
         221               0 :   nsAutoTArray<PRUint32, 10> accessKeys;
         222               0 :   nsEvent* nativeEvent = nsContentUtils::GetNativeEvent(aKeyEvent);
         223               0 :   nsKeyEvent* nativeKeyEvent = static_cast<nsKeyEvent*>(nativeEvent);
         224               0 :   if (nativeKeyEvent)
         225               0 :     nsContentUtils::GetAccessKeyCandidates(nativeKeyEvent, accessKeys);
         226               0 :   if (accessKeys.IsEmpty() && charCode)
         227               0 :     accessKeys.AppendElement(charCode);
         228                 :
         229               0 :   if (accessKeys.IsEmpty())
         230               0 :     return nsnull; // no character was pressed so just return
         231                 :
         232                 :   // Enumerate over our list of frames.
         233               0 :   nsIFrame* immediateParent = nsnull;
         234               0 :   GetInsertionPoint(PresContext()->PresShell(), this, nsnull, &immediateParent);
         235               0 :   if (!immediateParent)
         236               0 :     immediateParent = this;
         237                 :
         238                 :   // Find a most preferred accesskey which should be returned.
         239               0 :   nsIFrame* foundMenu = nsnull;
         240               0 :   PRUint32 foundIndex = accessKeys.NoIndex;
         241               0 :   nsIFrame* currFrame = immediateParent->GetFirstPrincipalChild();
         242                 :
         243               0 :   while (currFrame) {
         244               0 :     nsIContent* current = currFrame->GetContent();
         245                 :
         246                 :     // See if it's a menu item.
         247               0 :     if (nsXULPopupManager::IsValidMenuItem(PresContext(), current, false)) {
         248                 :       // Get the shortcut attribute.
         249               0 :       nsAutoString shortcutKey;
         250               0 :       current->GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, shortcutKey);
         251               0 :       if (!shortcutKey.IsEmpty()) {
         252               0 :         ToLowerCase(shortcutKey);
         253               0 :         const PRUnichar* start = shortcutKey.BeginReading();
         254               0 :         const PRUnichar* end = shortcutKey.EndReading();
         255               0 :         PRUint32 ch = UTF16CharEnumerator::NextChar(&start, end);
         256               0 :         PRUint32 index = accessKeys.IndexOf(ch);
         257               0 :         if (index != accessKeys.NoIndex &&
         258                 :             (foundIndex == accessKeys.NoIndex || index < foundIndex)) {
         259               0 :           foundMenu = currFrame;
         260               0 :           foundIndex = index;
         261                 :         }
         262                 :       }
         263                 :     }
         264               0 :     currFrame = currFrame->GetNextSibling();
         265                 :   }
         266               0 :   if (foundMenu) {
         267               0 :     return (foundMenu->GetType() == nsGkAtoms::menuFrame) ?
         268               0 :            static_cast<nsMenuFrame *>(foundMenu) : nsnull;
         269                 :   }
         270                 :
         271                 :   // didn't find a matching menu item
         272                 : #ifdef XP_WIN
         273                 :   // behavior on Windows - this item is on the menu bar, beep and deactivate the menu bar
         274                 :   if (mIsActive) {
         275                 :     nsCOMPtr<nsISound> soundInterface = do_CreateInstance("@mozilla.org/sound;1");
         276                 :     if (soundInterface)
         277                 :       soundInterface->Beep();
         278                 :   }
         279                 :
         280                 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
         281                 :   if (pm) {
         282                 :     nsIFrame* popup = pm->GetTopPopup(ePopupTypeAny);
         283                 :     if (popup)
         284                 :       pm->HidePopup(popup->GetContent(), true, true, true);
         285                 :   }
         286                 :
         287                 :   SetCurrentMenuItem(nsnull);
         288                 :   SetActive(false);
         289                 :
         290                 : #endif  // #ifdef XP_WIN
         291                 :
         292               0 :   return nsnull;
         293                 : }
         294                 :
         295                 : /* virtual */ nsMenuFrame*
         296               0 : nsMenuBarFrame::GetCurrentMenuItem()
         297                 : {
         298               0 :   return mCurrentMenu;
         299                 : }
         300                 :
         301                 : NS_IMETHODIMP
         302               0 : nsMenuBarFrame::SetCurrentMenuItem(nsMenuFrame* aMenuItem)
         303                 : {
         304               0 :   if (mCurrentMenu == aMenuItem)
         305               0 :     return NS_OK;
         306                 :
         307               0 :   if (mCurrentMenu)
         308               0 :     mCurrentMenu->SelectMenu(false);
         309                 :
         310               0 :   if (aMenuItem)
         311               0 :     aMenuItem->SelectMenu(true);
         312                 :
         313               0 :   mCurrentMenu = aMenuItem;
         314                 :
         315               0 :   return NS_OK;
         316                 : }
         317                 :
         318                 : void
         319               0 : nsMenuBarFrame::CurrentMenuIsBeingDestroyed()
         320                 : {
         321               0 :   mCurrentMenu->SelectMenu(false);
         322               0 :   mCurrentMenu = nsnull;
         323               0 : }
         324                 :
         325                 : class nsMenuBarSwitchMenu : public nsRunnable
         326               0 : {
         327                 : public:
         328               0 :   nsMenuBarSwitchMenu(nsIContent* aMenuBar,
         329                 :                       nsIContent *aOldMenu,
         330                 :                       nsIContent *aNewMenu,
         331                 :                       bool aSelectFirstItem)
         332                 :     : mMenuBar(aMenuBar), mOldMenu(aOldMenu), mNewMenu(aNewMenu),
         333               0 :       mSelectFirstItem(aSelectFirstItem)
         334                 :   {
         335               0 :   }
         336                 :
         337               0 :   NS_IMETHOD Run()
         338                 :   {
         339               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
         340               0 :     if (!pm)
         341               0 :       return NS_ERROR_UNEXPECTED;
         342                 :
         343                 :     // if switching from one menu to another, set a flag so that the call to
         344                 :     // HidePopup doesn't deactivate the menubar when the first menu closes.
         345               0 :     nsMenuBarFrame* menubar = nsnull;
         346               0 :     if (mOldMenu && mNewMenu) {
         347                 :       menubar = static_cast<nsMenuBarFrame *>
         348               0 :         (pm->GetFrameOfTypeForContent(mMenuBar, nsGkAtoms::menuBarFrame, false));
         349               0 :       if (menubar)
         350               0 :         menubar->SetStayActive(true);
         351                 :     }
         352                 :
         353               0 :     if (mOldMenu) {
         354               0 :       nsWeakFrame weakMenuBar(menubar);
         355               0 :       pm->HidePopup(mOldMenu, false, false, false);
         356                 :       // clear the flag again
         357               0 :       if (mNewMenu && weakMenuBar.IsAlive())
         358               0 :         menubar->SetStayActive(false);
         359                 :     }
         360                 :
         361               0 :     if (mNewMenu)
         362               0 :       pm->ShowMenu(mNewMenu, mSelectFirstItem, false);
         363                 :
         364               0 :     return NS_OK;
         365                 :   }
         366                 :
         367                 : private:
         368                 :   nsCOMPtr<nsIContent> mMenuBar;
         369                 :   nsCOMPtr<nsIContent> mOldMenu;
         370                 :   nsCOMPtr<nsIContent> mNewMenu;
         371                 :   bool mSelectFirstItem;
         372                 : };
         373                 :
         374                 : NS_IMETHODIMP
         375               0 : nsMenuBarFrame::ChangeMenuItem(nsMenuFrame* aMenuItem,
         376                 :                                bool aSelectFirstItem)
         377                 : {
         378               0 :   if (mCurrentMenu == aMenuItem)
         379               0 :     return NS_OK;
         380                 :
         381                 :   // check if there's an open context menu, we ignore this
         382               0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
         383               0 :   if (pm && pm->HasContextMenu(nsnull))
         384               0 :     return NS_OK;
         385                 :
         386               0 :   nsIContent* aOldMenu = nsnull, *aNewMenu = nsnull;
         387                 :
         388                 :   // Unset the current child.
         389               0 :   bool wasOpen = false;
         390               0 :   if (mCurrentMenu) {
         391               0 :     wasOpen = mCurrentMenu->IsOpen();
         392               0 :     mCurrentMenu->SelectMenu(false);
         393               0 :     if (wasOpen) {
         394               0 :       nsMenuPopupFrame* popupFrame = mCurrentMenu->GetPopup();
         395               0 :       if (popupFrame)
         396               0 :         aOldMenu = popupFrame->GetContent();
         397                 :     }
         398                 :   }
         399                 :
         400                 :   // set to null first in case the IsAlive check below returns false
         401               0 :   mCurrentMenu = nsnull;
         402                 :
         403                 :   // Set the new child.
         404               0 :   if (aMenuItem) {
         405               0 :     nsCOMPtr<nsIContent> content = aMenuItem->GetContent();
         406               0 :     aMenuItem->SelectMenu(true);
         407               0 :     mCurrentMenu = aMenuItem;
         408               0 :     if (wasOpen && !aMenuItem->IsDisabled())
         409               0 :       aNewMenu = content;
         410                 :   }
         411                 :
         412                 :   // use an event so that hiding and showing can be done synchronously, which
         413                 :   // avoids flickering
         414                 :   nsCOMPtr<nsIRunnable> event =
         415               0 :     new nsMenuBarSwitchMenu(GetContent(), aOldMenu, aNewMenu, aSelectFirstItem);
         416               0 :   return NS_DispatchToCurrentThread(event);
         417                 : }
         418                 :
         419                 : nsMenuFrame*
         420               0 : nsMenuBarFrame::Enter(nsGUIEvent* aEvent)
         421                 : {
         422               0 :   if (!mCurrentMenu)
         423               0 :     return nsnull;
         424                 :
         425               0 :   if (mCurrentMenu->IsOpen())
         426               0 :     return mCurrentMenu->Enter(aEvent);
         427                 :
         428               0 :   return mCurrentMenu;
         429                 : }
         430                 :
         431                 : bool
         432               0 : nsMenuBarFrame::MenuClosed()
         433                 : {
         434               0 :   SetActive(false);
         435               0 :   if (!mIsActive && mCurrentMenu) {
         436               0 :     mCurrentMenu->SelectMenu(false);
         437               0 :     mCurrentMenu = nsnull;
         438               0 :     return true;
         439                 :   }
         440               0 :   return false;
         441                 : }
         442                 :
         443                 : void
         444               0 : nsMenuBarFrame::InstallKeyboardNavigator()
         445                 : {
         446               0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
         447               0 :   if (pm)
         448               0 :     pm->SetActiveMenuBar(this, true);
         449               0 : }
         450                 :
         451                 : void
         452               0 : nsMenuBarFrame::RemoveKeyboardNavigator()
         453                 : {
         454               0 :   if (!mIsActive) {
         455               0 :     nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
         456               0 :     if (pm)
         457               0 :       pm->SetActiveMenuBar(this, false);
         458                 :   }
         459               0 : }
         460                 :
         461                 : void
         462               0 : nsMenuBarFrame::DestroyFrom(nsIFrame* aDestructRoot)
         463                 : {
         464               0 :   nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
         465               0 :   if (pm)
         466               0 :     pm->SetActiveMenuBar(this, false);
         467                 :
         468               0 :   mTarget->RemoveEventListener(NS_LITERAL_STRING("keypress"), mMenuBarListener, false);
         469               0 :   mTarget->RemoveEventListener(NS_LITERAL_STRING("keydown"), mMenuBarListener, false);
         470               0 :   mTarget->RemoveEventListener(NS_LITERAL_STRING("keyup"), mMenuBarListener, false);
         471                 :
         472               0 :   mTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, true);
         473               0 :   mTarget->RemoveEventListener(NS_LITERAL_STRING("mousedown"), mMenuBarListener, false);
         474               0 :   mTarget->RemoveEventListener(NS_LITERAL_STRING("blur"), mMenuBarListener, true);
         475                 :
         476               0 :   NS_IF_RELEASE(mMenuBarListener);
         477                 :
         478               0 :   nsBoxFrame::DestroyFrom(aDestructRoot);
         479               0 : }

Generated by: LCOV version 1.7