widget/cocoa/nsMenuUtilsX.mm

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial