Wed, 31 Dec 2014 06:09:35 +0100
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; 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 }