widget/cocoa/nsStandaloneNativeMenu.mm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #import <Cocoa/Cocoa.h>
     8 #include "nsStandaloneNativeMenu.h"
     9 #include "nsMenuUtilsX.h"
    10 #include "nsIDOMElement.h"
    11 #include "nsIMutationObserver.h"
    12 #include "nsGkAtoms.h"
    13 #include "nsObjCExceptions.h"
    16 NS_IMPL_ISUPPORTS(nsStandaloneNativeMenu, nsIMutationObserver, nsIStandaloneNativeMenu)
    18 nsStandaloneNativeMenu::nsStandaloneNativeMenu()
    19 : mMenu(nullptr)
    20 {
    21 }
    23 nsStandaloneNativeMenu::~nsStandaloneNativeMenu()
    24 {
    25   if (mMenu) delete mMenu;
    26 }
    28 NS_IMETHODIMP
    29 nsStandaloneNativeMenu::Init(nsIDOMElement * aDOMElement)
    30 {
    31   NS_ASSERTION(mMenu == nullptr, "nsNativeMenu::Init - mMenu not null!");
    33   nsresult rv;
    35   nsCOMPtr<nsIContent> content = do_QueryInterface(aDOMElement, &rv);
    36   NS_ENSURE_SUCCESS(rv, rv);
    38   nsIAtom * tag = content->Tag();
    39   if (!content->IsXUL() ||
    40       (tag != nsGkAtoms::menu && tag != nsGkAtoms::menupopup))
    41     return NS_ERROR_FAILURE;
    43   rv = nsMenuGroupOwnerX::Create(content);
    44   if (NS_FAILED(rv))
    45     return rv;
    47   mMenu = new nsMenuX();
    48   rv = mMenu->Create(this, this, content);
    49   if (NS_FAILED(rv)) {
    50     delete mMenu;
    51     mMenu = nullptr;
    52     return rv;
    53   }
    55   return NS_OK;
    56 }
    58 static void
    59 UpdateMenu(nsMenuX * aMenu)
    60 {
    61   aMenu->MenuOpened();
    62   aMenu->MenuClosed();
    64   uint32_t itemCount = aMenu->GetItemCount();
    65   for (uint32_t i = 0; i < itemCount; i++) {
    66     nsMenuObjectX * menuObject = aMenu->GetItemAt(i);
    67     if (menuObject->MenuObjectType() == eSubmenuObjectType) {
    68       UpdateMenu(static_cast<nsMenuX*>(menuObject));
    69     }
    70   }
    71 }
    73 NS_IMETHODIMP
    74 nsStandaloneNativeMenu::MenuWillOpen(bool * aResult)
    75 {
    76   NS_ASSERTION(mMenu != nullptr, "nsStandaloneNativeMenu::OnOpen - mMenu is null!");
    78   // Force an update on the mMenu by faking an open/close on all of
    79   // its submenus.
    80   UpdateMenu(mMenu);
    82   *aResult = true;
    83   return NS_OK;
    84 }
    86 NS_IMETHODIMP
    87 nsStandaloneNativeMenu::GetNativeMenu(void ** aVoidPointer)
    88 {
    89   if (mMenu) {
    90     *aVoidPointer = mMenu->NativeData();
    91     [[(NSObject *)(*aVoidPointer) retain] autorelease];
    92     return NS_OK;
    93   }  else {
    94     *aVoidPointer = nullptr;
    95     return NS_ERROR_NOT_INITIALIZED;
    96   }
    97 }
    99 static NSMenuItem *
   100 NativeMenuItemWithLocation(NSMenu * currentSubmenu, NSString * locationString)
   101 {
   102   NSArray * indexes = [locationString componentsSeparatedByString:@"|"];
   103   NSUInteger indexCount = [indexes count];
   104   if (indexCount == 0)
   105     return nil;
   107   for (NSUInteger i = 0; i < indexCount; i++) {
   108     NSInteger targetIndex = [[indexes objectAtIndex:i] integerValue];
   109     NSInteger itemCount = [currentSubmenu numberOfItems];
   110     if (targetIndex < itemCount) {
   111       NSMenuItem* menuItem = [currentSubmenu itemAtIndex:targetIndex];
   113       // If this is the last index, just return the menu item.
   114       if (i == (indexCount - 1))
   115         return menuItem;
   117       // If this is not the last index, find the submenu and keep going.
   118       if ([menuItem hasSubmenu])
   119         currentSubmenu = [menuItem submenu];
   120       else
   121         return nil;
   122     }
   123   }
   125   return nil;
   126 }
   128 NS_IMETHODIMP
   129 nsStandaloneNativeMenu::ActivateNativeMenuItemAt(const nsAString& indexString)
   130 {
   131   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   133   if (!mMenu)
   134     return NS_ERROR_NOT_INITIALIZED;
   136   NSString * locationString = [NSString stringWithCharacters:reinterpret_cast<const unichar*>(indexString.BeginReading())
   137                                                       length:indexString.Length()];
   138   NSMenu * menu = static_cast<NSMenu *> (mMenu->NativeData());
   139   NSMenuItem * item = NativeMenuItemWithLocation(menu, locationString);
   141   // We can't perform an action on an item with a submenu, that will raise
   142   // an obj-c exception.
   143   if (item && ![item hasSubmenu]) {
   144     NSMenu * parent = [item menu];
   145     if (parent) {
   146       // NSLog(@"Performing action for native menu item titled: %@\n",
   147       //       [[currentSubmenu itemAtIndex:targetIndex] title]);
   148       [parent performActionForItemAtIndex:[parent indexOfItem:item]];
   149       return NS_OK;
   150     }
   151   }
   153   return NS_ERROR_FAILURE;
   155   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   156 }
   158 NS_IMETHODIMP
   159 nsStandaloneNativeMenu::ForceUpdateNativeMenuAt(const nsAString& indexString)
   160 {
   161   if (!mMenu)
   162     return NS_ERROR_NOT_INITIALIZED;
   164   NSString* locationString = [NSString stringWithCharacters:reinterpret_cast<const unichar*>(indexString.BeginReading())
   165                                                      length:indexString.Length()];
   166   NSArray* indexes = [locationString componentsSeparatedByString:@"|"];
   167   unsigned int indexCount = [indexes count];
   168   if (indexCount == 0)
   169     return NS_OK;
   171   nsMenuX* currentMenu = mMenu;
   173   // now find the correct submenu
   174   for (unsigned int i = 1; currentMenu && i < indexCount; i++) {
   175     int targetIndex = [[indexes objectAtIndex:i] intValue];
   176     int visible = 0;
   177     uint32_t length = currentMenu->GetItemCount();
   178     for (unsigned int j = 0; j < length; j++) {
   179       nsMenuObjectX* targetMenu = currentMenu->GetItemAt(j);
   180       if (!targetMenu)
   181         return NS_OK;
   182       if (!nsMenuUtilsX::NodeIsHiddenOrCollapsed(targetMenu->Content())) {
   183         visible++;
   184         if (targetMenu->MenuObjectType() == eSubmenuObjectType && visible == (targetIndex + 1)) {
   185           currentMenu = static_cast<nsMenuX*>(targetMenu);
   186           // fake open/close to cause lazy update to happen
   187           currentMenu->MenuOpened();
   188           currentMenu->MenuClosed();
   189           break;
   190         }
   191       }
   192     }
   193   }
   195   return NS_OK;
   196 }

mercurial