widget/cocoa/nsMenuUtilsX.mm

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     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 #include "mozilla/dom/Event.h"
     7 #include "nsMenuUtilsX.h"
     8 #include "nsMenuBarX.h"
     9 #include "nsMenuX.h"
    10 #include "nsMenuItemX.h"
    11 #include "nsStandaloneNativeMenu.h"
    12 #include "nsObjCExceptions.h"
    13 #include "nsCocoaUtils.h"
    14 #include "nsCocoaWindow.h"
    15 #include "nsGkAtoms.h"
    16 #include "nsIDocument.h"
    17 #include "nsIDOMDocument.h"
    18 #include "nsIDOMXULCommandEvent.h"
    19 #include "nsPIDOMWindow.h"
    21 using namespace mozilla;
    23 void nsMenuUtilsX::DispatchCommandTo(nsIContent* aTargetContent)
    24 {
    25   NS_PRECONDITION(aTargetContent, "null ptr");
    27   nsIDocument* doc = aTargetContent->OwnerDoc();
    28   if (doc) {
    29     ErrorResult rv;
    30     nsRefPtr<dom::Event> event =
    31       doc->CreateEvent(NS_LITERAL_STRING("xulcommandevent"), rv);
    32     nsCOMPtr<nsIDOMXULCommandEvent> command = do_QueryObject(event);
    34     // FIXME: Should probably figure out how to init this with the actual
    35     // pressed keys, but this is a big old edge case anyway. -dwh
    36     if (command &&
    37         NS_SUCCEEDED(command->InitCommandEvent(NS_LITERAL_STRING("command"),
    38                                                true, true,
    39                                                doc->GetWindow(), 0,
    40                                                false, false, false,
    41                                                false, nullptr))) {
    42       event->SetTrusted(true);
    43       bool dummy;
    44       aTargetContent->DispatchEvent(event, &dummy);
    45     }
    46   }
    47 }
    49 NSString* nsMenuUtilsX::GetTruncatedCocoaLabel(const nsString& itemLabel)
    50 {
    51   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
    53   // We want to truncate long strings to some reasonable pixel length but there is no
    54   // good API for doing that which works for all OS versions and architectures. For now
    55   // we'll do nothing for consistency and depend on good user interface design to limit
    56   // string lengths.
    57   return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(itemLabel.get())
    58                                  length:itemLabel.Length()];
    60   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
    61 }
    63 uint8_t nsMenuUtilsX::GeckoModifiersForNodeAttribute(const nsString& modifiersAttribute)
    64 {
    65   uint8_t modifiers = knsMenuItemNoModifier;
    66   char* str = ToNewCString(modifiersAttribute);
    67   char* newStr;
    68   char* token = strtok_r(str, ", \t", &newStr);
    69   while (token != NULL) {
    70     if (strcmp(token, "shift") == 0)
    71       modifiers |= knsMenuItemShiftModifier;
    72     else if (strcmp(token, "alt") == 0) 
    73       modifiers |= knsMenuItemAltModifier;
    74     else if (strcmp(token, "control") == 0) 
    75       modifiers |= knsMenuItemControlModifier;
    76     else if ((strcmp(token, "accel") == 0) ||
    77              (strcmp(token, "meta") == 0)) {
    78       modifiers |= knsMenuItemCommandModifier;
    79     }
    80     token = strtok_r(newStr, ", \t", &newStr);
    81   }
    82   free(str);
    84   return modifiers;
    85 }
    87 unsigned int nsMenuUtilsX::MacModifiersForGeckoModifiers(uint8_t geckoModifiers)
    88 {
    89   unsigned int macModifiers = 0;
    91   if (geckoModifiers & knsMenuItemShiftModifier)
    92     macModifiers |= NSShiftKeyMask;
    93   if (geckoModifiers & knsMenuItemAltModifier)
    94     macModifiers |= NSAlternateKeyMask;
    95   if (geckoModifiers & knsMenuItemControlModifier)
    96     macModifiers |= NSControlKeyMask;
    97   if (geckoModifiers & knsMenuItemCommandModifier)
    98     macModifiers |= NSCommandKeyMask;
   100   return macModifiers;
   101 }
   103 nsMenuBarX* nsMenuUtilsX::GetHiddenWindowMenuBar()
   104 {
   105   nsIWidget* hiddenWindowWidgetNoCOMPtr = nsCocoaUtils::GetHiddenWindowWidget();
   106   if (hiddenWindowWidgetNoCOMPtr)
   107     return static_cast<nsCocoaWindow*>(hiddenWindowWidgetNoCOMPtr)->GetMenuBar();
   108   else
   109     return nullptr;
   110 }
   112 // It would be nice if we could localize these edit menu names.
   113 NSMenuItem* nsMenuUtilsX::GetStandardEditMenuItem()
   114 {
   115   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   117   // In principle we should be able to allocate this once and then always
   118   // return the same object.  But wierd interactions happen between native
   119   // app-modal dialogs and Gecko-modal dialogs that open above them.  So what
   120   // we return here isn't always released before it needs to be added to
   121   // another menu.  See bmo bug 468393.
   122   NSMenuItem* standardEditMenuItem =
   123     [[[NSMenuItem alloc] initWithTitle:@"Edit" action:nil keyEquivalent:@""] autorelease];
   124   NSMenu* standardEditMenu = [[NSMenu alloc] initWithTitle:@"Edit"];
   125   [standardEditMenuItem setSubmenu:standardEditMenu];
   126   [standardEditMenu release];
   128   // Add Undo
   129   NSMenuItem* undoItem = [[NSMenuItem alloc] initWithTitle:@"Undo" action:@selector(undo:) keyEquivalent:@"z"];
   130   [standardEditMenu addItem:undoItem];
   131   [undoItem release];
   133   // Add Redo
   134   NSMenuItem* redoItem = [[NSMenuItem alloc] initWithTitle:@"Redo" action:@selector(redo:) keyEquivalent:@"Z"];
   135   [standardEditMenu addItem:redoItem];
   136   [redoItem release];
   138   // Add separator
   139   [standardEditMenu addItem:[NSMenuItem separatorItem]];
   141   // Add Cut
   142   NSMenuItem* cutItem = [[NSMenuItem alloc] initWithTitle:@"Cut" action:@selector(cut:) keyEquivalent:@"x"];
   143   [standardEditMenu addItem:cutItem];
   144   [cutItem release];
   146   // Add Copy
   147   NSMenuItem* copyItem = [[NSMenuItem alloc] initWithTitle:@"Copy" action:@selector(copy:) keyEquivalent:@"c"];
   148   [standardEditMenu addItem:copyItem];
   149   [copyItem release];
   151   // Add Paste
   152   NSMenuItem* pasteItem = [[NSMenuItem alloc] initWithTitle:@"Paste" action:@selector(paste:) keyEquivalent:@"v"];
   153   [standardEditMenu addItem:pasteItem];
   154   [pasteItem release];
   156   // Add Delete
   157   NSMenuItem* deleteItem = [[NSMenuItem alloc] initWithTitle:@"Delete" action:@selector(delete:) keyEquivalent:@""];
   158   [standardEditMenu addItem:deleteItem];
   159   [deleteItem release];
   161   // Add Select All
   162   NSMenuItem* selectAllItem = [[NSMenuItem alloc] initWithTitle:@"Select All" action:@selector(selectAll:) keyEquivalent:@"a"];
   163   [standardEditMenu addItem:selectAllItem];
   164   [selectAllItem release];
   166   return standardEditMenuItem;
   168   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   169 }
   171 bool nsMenuUtilsX::NodeIsHiddenOrCollapsed(nsIContent* inContent)
   172 {
   173   return (inContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::hidden,
   174                                  nsGkAtoms::_true, eCaseMatters) ||
   175           inContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::collapsed,
   176                                  nsGkAtoms::_true, eCaseMatters));
   177 }
   179 // Determines how many items are visible among the siblings in a menu that are
   180 // before the given child. This will not count the application menu.
   181 int nsMenuUtilsX::CalculateNativeInsertionPoint(nsMenuObjectX* aParent,
   182                                                 nsMenuObjectX* aChild)
   183 {
   184   int insertionPoint = 0;
   185   nsMenuObjectTypeX parentType = aParent->MenuObjectType();
   186   if (parentType == eMenuBarObjectType) {
   187     nsMenuBarX* menubarParent = static_cast<nsMenuBarX*>(aParent);
   188     uint32_t numMenus = menubarParent->GetMenuCount();
   189     for (uint32_t i = 0; i < numMenus; i++) {
   190       nsMenuX* currMenu = menubarParent->GetMenuAt(i);
   191       if (currMenu == aChild)
   192         return insertionPoint; // we found ourselves, break out
   193       if (currMenu && [currMenu->NativeMenuItem() menu])
   194         insertionPoint++;
   195     }
   196   }
   197   else if (parentType == eSubmenuObjectType ||
   198            parentType == eStandaloneNativeMenuObjectType) {
   199     nsMenuX* menuParent;
   200     if (parentType == eSubmenuObjectType)
   201       menuParent = static_cast<nsMenuX*>(aParent);
   202     else
   203       menuParent = static_cast<nsStandaloneNativeMenu*>(aParent)->GetMenuXObject();
   205     uint32_t numItems = menuParent->GetItemCount();
   206     for (uint32_t i = 0; i < numItems; i++) {
   207       // Using GetItemAt instead of GetVisibleItemAt to avoid O(N^2)
   208       nsMenuObjectX* currItem = menuParent->GetItemAt(i);
   209       if (currItem == aChild)
   210         return insertionPoint; // we found ourselves, break out
   211       NSMenuItem* nativeItem = nil;
   212       nsMenuObjectTypeX currItemType = currItem->MenuObjectType();
   213       if (currItemType == eSubmenuObjectType)
   214         nativeItem = static_cast<nsMenuX*>(currItem)->NativeMenuItem();
   215       else
   216         nativeItem = (NSMenuItem*)(currItem->NativeData());
   217       if ([nativeItem menu])
   218         insertionPoint++;
   219     }
   220   }
   221   return insertionPoint;
   222 }

mercurial