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
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/
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
15
* The Original Code is globalmenu-extension.
17
* The Initial Developer of the Original Code is
19
* Portions created by the Initial Developer are Copyright (C) 2010
20
* the Initial Developer. All Rights Reserved.
23
* Chris Coulson <chris.coulson@canonical.com>
25
* Alternatively, the contents of this file may be used under the terms of
26
* either the GNU General Public License Version 2 or later (the "GPL"), or
27
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
* in which case the provisions of the GPL or the LGPL are applicable instead
29
* of those above. If you wish to allow use of your version of this file only
30
* under the terms of either the GPL or the LGPL, and not to allow others to
31
* use your version of this file under the terms of the MPL, indicate your
32
* decision by deleting the provisions above and replace them with the notice
33
* and other provisions required by the GPL or the LGPL. If you do not delete
34
* the provisions above, a recipient may use your version of this file under
35
* the terms of any one of the MPL, the GPL or the LGPL.
37
* ***** END LICENSE BLOCK ***** */
40
#include <nsIXBLService.h>
42
#include <nsIDOMEvent.h>
43
#include <nsIDOMMouseEvent.h>
44
#include <nsIDOMWindow.h>
45
#include <nsIDOMDocument.h>
46
#include <nsStringAPI.h>
47
#include <nsIDOMEventTarget.h>
48
#include <nsIPrivateDOMEvent.h>
49
#include <nsPIDOMWindow.h>
50
#include <nsIDOMXULCommandEvent.h>
51
#include <nsIXPConnect.h>
52
#include <nsIScriptGlobalObject.h>
53
#include <nsIScriptContext.h>
55
#include <mozilla/dom/Element.h>
57
#include <glib-object.h>
59
#include "uGlobalMenuService.h"
60
#include "uGlobalMenu.h"
61
#include "uGlobalMenuBar.h"
62
#include "uGlobalMenuUtils.h"
63
#include "uWidgetAtoms.h"
67
uGlobalMenu::RecycleList::RecycleList(uGlobalMenu *aMenu):
68
mMarker(0), mMenu(aMenu)
70
nsRefPtr<nsIRunnable> event =
71
NS_NewNonOwningRunnableMethod(mMenu, &uGlobalMenu::FreeRecycleList);
72
NS_DispatchToCurrentThread(event);
75
uGlobalMenu::RecycleList::~RecycleList()
77
for (PRUint32 i = 0; i < mList.Length(); i++) {
78
dbusmenu_menuitem_child_delete(mMenu->GetDbusMenuItem(), mList[i]);
83
uGlobalMenu::RecycleList::PopRecyclableItem()
85
NS_ASSERTION(mList.Length() > 0, "No more recyclable menuitems");
88
DbusmenuMenuitem *recycled = mList[0];
89
mList.RemoveElementAt(0);
91
if (mList.Length() == 0) {
92
mMenu->FreeRecycleList();
99
uGlobalMenu::RecycleList::PrependRecyclableItem(DbusmenuMenuitem *aItem)
101
mList.InsertElementAt(0, aItem);
105
uGlobalMenu::RecycleList::AppendRecyclableItem(DbusmenuMenuitem *aItem)
107
mList.AppendElement(aItem);
111
uGlobalMenu::MenuEventCallback(DbusmenuMenuitem *menu,
117
uGlobalMenu *self = static_cast<uGlobalMenu *>(data);
118
if (!g_strcmp0("closed", name)) {
123
if (!g_strcmp0("opened", name)) {
132
uGlobalMenu::MenuAboutToOpenCallback(DbusmenuMenuitem *menu,
135
uGlobalMenu *self = static_cast<uGlobalMenu *>(data);
138
// We return false here for "needsUpdate", as we have no way of
139
// knowing in advance if the menu structure is going to be updated.
140
// The menu layout will still update on the client, but we won't block
141
// opening the menu until it's happened
146
uGlobalMenu::Activate()
148
mContent->SetAttr(kNameSpaceID_None, uWidgetAtoms::menuactive,
149
NS_LITERAL_STRING("true"), true);
151
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mContent);
153
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mContent->OwnerDoc());
155
nsCOMPtr<nsIDOMEvent> event;
156
domDoc->CreateEvent(NS_LITERAL_STRING("Events"),
157
getter_AddRefs(event));
159
event->InitEvent(NS_LITERAL_STRING("DOMMenuItemActive"),
161
nsCOMPtr<nsIPrivateDOMEvent> priv = do_QueryInterface(event);
163
priv->SetTrusted(true);
166
target->DispatchEvent(event, &dummy);
173
uGlobalMenu::Deactivate()
175
mContent->UnsetAttr(kNameSpaceID_None, uWidgetAtoms::menuactive, true);
177
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mContent->OwnerDoc());
179
nsCOMPtr<nsIDOMEvent> event;
180
domDoc->CreateEvent(NS_LITERAL_STRING("Events"),
181
getter_AddRefs(event));
183
event->InitEvent(NS_LITERAL_STRING("DOMMenuItemInactive"),
185
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mContent);
187
nsCOMPtr<nsIPrivateDOMEvent> priv = do_QueryInterface(event);
189
priv->SetTrusted(true);
192
target->DispatchEvent(event, &dummy);
199
uGlobalMenu::CanOpen()
201
bool isHidden = IsHidden();
202
bool isDisabled = mContent->AttrValueIs(kNameSpaceID_None,
203
uWidgetAtoms::disabled,
207
return (!isHidden && !isDisabled);
211
uGlobalMenu::AboutToOpen()
213
TRACE_WITH_THIS_MENUOBJECT();
215
// XXX: We ignore the first AboutToOpen on top-level menus, because Unity
216
// sends this signal on all top-levels when the window opens.
217
// This isn't useful for us and it doesn't finish the job by sending
218
// open/close events, so we end up in a state where we resent the
219
// entire menu structure over dbus on every page navigation
220
if (!(mFlags & UNITY_MENU_READY)) {
221
DEBUG_WITH_THIS_MENUOBJECT("Ignoring first AboutToOpen");
222
SetFlags(UNITY_MENU_READY);
226
if (DoesNeedRebuild()) {
230
SetFlags(UNITY_MENU_IS_OPEN_OR_OPENING);
232
// If there is no popup content, then there is nothing to do, and it's
233
// unsafe to proceed anyway
234
if (!mPopupContent) {
235
DEBUG_WITH_THIS_MENUOBJECT("Menu has no popup content");
239
PRUint32 count = mMenuObjects.Length();
240
for (PRUint32 i = 0; i < count; i++) {
241
mMenuObjects[i]->AboutToShowNotify();
244
// XXX: This should happen when the pointer hovers over the menu entry,
245
// but we don't have that information right now. We synthesize it for
246
// menus, but this doesn't work for menuitems at all
249
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mPopupContent->OwnerDoc());
251
nsCOMPtr<nsIDOMEvent> event;
252
domDoc->CreateEvent(NS_LITERAL_STRING("mouseevent"),
253
getter_AddRefs(event));
255
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(event);
257
nsCOMPtr<nsIDOMWindow> window;
258
domDoc->GetDefaultView(getter_AddRefs(window));
260
mouseEvent->InitMouseEvent(NS_LITERAL_STRING("popupshowing"),
261
true, true, window, nsnull,
262
0, 0, 0, 0, false, false,
263
false, false, 0, nsnull);
264
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mPopupContent);
266
nsCOMPtr<nsIPrivateDOMEvent> priv = do_QueryInterface(event);
268
priv->SetTrusted(true);
271
// XXX: dummy == false means that we should prevent the
272
// the menu from opening, but there's no way to do this
273
target->DispatchEvent(event, &dummy);
282
uGlobalMenu::OnOpen()
284
if (!IsOpenOrOpening()) {
285
// If we didn't receive an AboutToOpen, then generate it ourselves
289
mContent->SetAttr(kNameSpaceID_None, uWidgetAtoms::open, NS_LITERAL_STRING("true"), true);
291
// If there is no popup content, then there is nothing to do, and it's
292
// unsafe to proceed anyway
293
if (!mPopupContent) {
297
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mPopupContent->OwnerDoc());
299
nsCOMPtr<nsIDOMEvent> event;
300
domDoc->CreateEvent(NS_LITERAL_STRING("mouseevent"),
301
getter_AddRefs(event));
303
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(event);
305
nsCOMPtr<nsIDOMWindow> window;
306
domDoc->GetDefaultView(getter_AddRefs(window));
308
mouseEvent->InitMouseEvent(NS_LITERAL_STRING("popupshown"),
309
true, true, window, nsnull,
310
0, 0, 0, 0, false, false,
311
false, false, 0, nsnull);
312
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mPopupContent);
314
nsCOMPtr<nsIPrivateDOMEvent> priv = do_QueryInterface(event);
316
priv->SetTrusted(true);
319
target->DispatchEvent(event, &dummy);
328
uGlobalMenu::OnClose()
330
mContent->UnsetAttr(kNameSpaceID_None, uWidgetAtoms::open, true);
332
// If there is no popup content, then there is nothing to do, and it's
333
// unsafe to proceed anyway
334
if (!mPopupContent) {
335
ClearFlags(UNITY_MENU_IS_OPEN_OR_OPENING);
339
nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(mPopupContent->OwnerDoc());
341
nsCOMPtr<nsIDOMEvent> event;
342
domDoc->CreateEvent(NS_LITERAL_STRING("mouseevent"),
343
getter_AddRefs(event));
345
nsCOMPtr<nsIDOMMouseEvent> mouseEvent = do_QueryInterface(event);
347
nsCOMPtr<nsIDOMWindow> window;
348
domDoc->GetDefaultView(getter_AddRefs(window));
350
mouseEvent->InitMouseEvent(NS_LITERAL_STRING("popuphiding"),
351
true, true, window, nsnull,
352
0, 0, 0, 0, false, false,
353
false, false, 0, nsnull);
354
nsCOMPtr<nsIDOMEventTarget> target = do_QueryInterface(mPopupContent);
356
nsCOMPtr<nsIPrivateDOMEvent> priv = do_QueryInterface(event);
358
priv->SetTrusted(true);
361
target->DispatchEvent(event, &dummy);
362
mouseEvent->InitMouseEvent(NS_LITERAL_STRING("popuphidden"),
363
true, true, window, nsnull,
364
0, 0, 0, 0, false, false,
365
false, false, 0, nsnull);
366
target->DispatchEvent(event, &dummy);
373
ClearFlags(UNITY_MENU_IS_OPEN_OR_OPENING);
379
uGlobalMenu::SyncProperties()
381
TRACE_WITH_THIS_MENUOBJECT();
383
UpdateInfoFromContentClass();
384
SyncLabelFromContent();
385
SyncSensitivityFromContent();
386
SyncVisibilityFromContent();
387
SyncIconFromContent();
393
uGlobalMenu::InitializeDbusMenuItem()
395
if (!mDbusMenuItem) {
396
mDbusMenuItem = dbusmenu_menuitem_new();
397
if (!mDbusMenuItem) {
401
OnlyKeepProperties(static_cast<uMenuObjectProperties>(eLabel | eEnabled |
402
eVisible | eIconData |
406
// This happens automatically when we add children, but we have to
407
// do this manually for menus which don't initially have children,
408
// so we can receive about-to-show which triggers a build of the menu
409
dbusmenu_menuitem_property_set(mDbusMenuItem,
410
DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY,
411
DBUSMENU_MENUITEM_CHILD_DISPLAY_SUBMENU);
413
g_signal_connect(G_OBJECT(mDbusMenuItem), "about-to-show",
414
G_CALLBACK(MenuAboutToOpenCallback), this);
415
g_signal_connect(G_OBJECT(mDbusMenuItem), "event",
416
G_CALLBACK(MenuEventCallback), this);
422
uGlobalMenu::GetMenuPopupFromMenu(nsIContent **aResult)
429
// Taken from widget/src/cocoa/nsMenuX.mm. Not sure if we need this
430
nsIXBLService *xblService = uGlobalMenuService::GetXBLService();
435
nsCOMPtr<nsIAtom> tag;
436
xblService->ResolveTag(mContent, &dummy, getter_AddRefs(tag));
437
if (tag == uWidgetAtoms::menupopup) {
443
PRUint32 count = mContent->GetChildCount();
445
for (PRUint32 i = 0; i < count; i++) {
447
nsIContent *child = mContent->GetChildAt(i);
448
nsCOMPtr<nsIAtom> tag;
449
xblService->ResolveTag(child, &dummy, getter_AddRefs(tag));
450
if (tag == uWidgetAtoms::menupopup) {
459
IsRecycledItemCompatible(DbusmenuMenuitem *aRecycled,
460
uGlobalMenuObject *aNewItem)
462
// If the recycled item was a separator, it can only be reused as a separator
463
if (!g_strcmp0(dbusmenu_menuitem_property_get(aRecycled, DBUSMENU_MENUITEM_PROP_TYPE),
465
aNewItem->GetType() != eMenuSeparator) {
469
// Everything else is fine
474
uGlobalMenu::InsertMenuObjectAt(uGlobalMenuObject *menuObj,
477
PRUint32 correctedIndex = index;
479
DbusmenuMenuitem *recycled = nsnull;
481
if (index < mRecycleList->mMarker) {
482
++mRecycleList->mMarker;
483
} else if (index > mRecycleList->mMarker) {
484
correctedIndex += mRecycleList->mList.Length();
486
recycled = mRecycleList->PopRecyclableItem();
487
if (!IsRecycledItemCompatible(recycled, menuObj)) {
489
mRecycleList = nsnull;
496
menuObj->SetDbusMenuItem(recycled);
498
res = dbusmenu_menuitem_child_add_position(mDbusMenuItem,
499
menuObj->GetDbusMenuItem(),
503
return res && mMenuObjects.InsertElementAt(index, menuObj);
507
uGlobalMenu::AppendMenuObject(uGlobalMenuObject *menuObj)
509
DbusmenuMenuitem *recycled = nsnull;
510
if (mRecycleList && mRecycleList->mMarker > mMenuObjects.Length()) {
511
recycled = mRecycleList->PopRecyclableItem();
512
if (!IsRecycledItemCompatible(recycled, menuObj)) {
514
mRecycleList = nsnull;
520
menuObj->SetDbusMenuItem(recycled);
522
res = dbusmenu_menuitem_child_append(mDbusMenuItem,
523
menuObj->GetDbusMenuItem());
526
return res && mMenuObjects.AppendElement(menuObj);
530
uGlobalMenu::RemoveMenuObjectAt(PRUint32 index)
532
NS_ASSERTION(index < mMenuObjects.Length(), "Invalid index");
533
if (index >= mMenuObjects.Length()) {
538
mRecycleList = new RecycleList(this);
542
if (mRecycleList->mList.Length() == 0 || index == mRecycleList->mMarker) {
543
mRecycleList->AppendRecyclableItem(mMenuObjects[index]->GetDbusMenuItem());
544
} else if (index == mRecycleList->mMarker - 1) {
545
mRecycleList->PrependRecyclableItem(mMenuObjects[index]->GetDbusMenuItem());
547
mRecycleList = nsnull;
548
res = dbusmenu_menuitem_child_delete(mDbusMenuItem,
549
mMenuObjects[index]->GetDbusMenuItem());
553
mRecycleList->mMarker = index;
556
mMenuObjects.RemoveElementAt(index);
564
TRACE_WITH_THIS_MENUOBJECT();
566
PRUint32 count = mMenuObjects.Length();
567
for (PRUint32 i = 0; i < count; i++) {
568
RemoveMenuObjectAt(0);
571
// Removing all of the children causes dbusmenu to convert us from a
572
// submenu to a normal menuitem. Adding children changes this back again.
573
// We can avoid the shell ever seeing this by manually making ourself
574
// a submenu again before spinning the event loop
575
dbusmenu_menuitem_property_set(mDbusMenuItem,
576
DBUSMENU_MENUITEM_PROP_CHILD_DISPLAY,
577
DBUSMENU_MENUITEM_CHILD_DISPLAY_SUBMENU);
579
if (mPopupContent && mPopupContent != mContent) {
580
mListener->UnregisterForContentChanges(mPopupContent, this);
583
GetMenuPopupFromMenu(getter_AddRefs(mPopupContent));
585
if (!mPopupContent) {
586
// The menu has no popup, so there are no menuitems here
590
// Manually wrap the menupopup node to make sure it's bounded
591
// Borrowed from widget/src/cocoa/nsMenuX.mm, we need this to make
592
// some menus in Thunderbird work
593
nsIDocument *doc = mPopupContent->GetCurrentDoc();
595
nsIXPConnect *xpconnect = uGlobalMenuService::GetXPConnect();
597
nsIScriptGlobalObject *sgo = doc->GetScriptGlobalObject();
598
nsCOMPtr<nsIScriptContext> scriptContext = sgo->GetContext();
599
JSObject *global = sgo->GetGlobalJSObject();
600
if (scriptContext && global) {
601
JSContext *cx = (JSContext *)scriptContext->GetNativeContext();
603
nsCOMPtr<nsIXPConnectJSObjectHolder> wrapper;
604
xpconnect->WrapNative(cx, global,
605
mPopupContent, NS_GET_IID(nsISupports),
606
getter_AddRefs(wrapper));
612
if (mContent != mPopupContent) {
613
nsresult rv = mListener->RegisterForContentChanges(mPopupContent, this);
615
NS_WARNING("Failed to register for popup content changes");
622
count = mPopupContent->GetChildCount();
624
for (PRUint32 i = 0; i < count; i++) {
625
nsIContent *child = mPopupContent->GetChildAt(i);
626
uGlobalMenuObject *menuObject =
627
NewGlobalMenuItem(static_cast<uGlobalMenuObject *>(this),
628
mListener, child, mMenuBar);
631
res = AppendMenuObject(menuObject);
633
NS_WARN_IF_FALSE(res, "Failed to append menuitem. Marking menu invalid");
636
return NS_ERROR_FAILURE;
644
uGlobalMenu::Init(uGlobalMenuObject *aParent,
645
uGlobalMenuDocListener *aListener,
646
nsIContent *aContent,
647
uGlobalMenuBar *aMenuBar)
649
NS_ENSURE_ARG(aParent);
650
NS_ENSURE_ARG(aListener);
651
NS_ENSURE_ARG(aContent);
652
NS_ENSURE_ARG(aMenuBar);
655
mListener = aListener;
661
// See the hack comment above for why this workaround is here
662
if (mParent->GetType() != eMenuBar || mMenuBar->IsRegistered()) {
663
SetFlags(UNITY_MENU_READY);
666
nsresult rv = mListener->RegisterForContentChanges(mContent, this);
668
NS_WARNING("Failed to register for content changes");
675
uGlobalMenu::uGlobalMenu(): uGlobalMenuObject(eMenu)
677
MOZ_COUNT_CTOR(uGlobalMenu);
680
uGlobalMenu::~uGlobalMenu()
683
mListener->UnregisterForContentChanges(mContent, this);
684
if (mPopupContent && mContent != mPopupContent) {
685
mListener->UnregisterForContentChanges(mPopupContent, this);
692
g_signal_handlers_disconnect_by_func(mDbusMenuItem,
693
reinterpret_cast<gpointer>(MenuAboutToOpenCallback),
695
g_signal_handlers_disconnect_by_func(mDbusMenuItem,
696
reinterpret_cast<gpointer>(MenuEventCallback),
698
g_object_unref(mDbusMenuItem);
701
MOZ_COUNT_DTOR(uGlobalMenu);
704
/*static*/ uGlobalMenuObject*
705
uGlobalMenu::Create(uGlobalMenuObject *aParent,
706
uGlobalMenuDocListener *aListener,
707
nsIContent *aContent,
708
uGlobalMenuBar *aMenuBar)
710
TRACE_WITH_CONTENT(aContent);
712
uGlobalMenu *menu = new uGlobalMenu();
717
if (NS_FAILED(menu->Init(aParent, aListener, aContent, aMenuBar))) {
722
return static_cast<uGlobalMenuObject *>(menu);
726
uGlobalMenu::AboutToShowNotify()
728
TRACE_WITH_THIS_MENUOBJECT();
738
uGlobalMenu::OpenMenu()
744
dbusmenu_menuitem_show_to_user(mDbusMenuItem, 0);
748
uGlobalMenu::ObserveAttributeChanged(nsIDocument *aDocument,
749
nsIContent *aContent,
752
TRACE_WITH_THIS_MENUOBJECT();
753
NS_ASSERTION(aContent == mContent || aContent == mPopupContent,
754
"Received an event that wasn't meant for us!");
757
DEBUG_WITH_THIS_MENUOBJECT("Previously marked as invalid");
761
if (mParent->GetType() == eMenu &&
762
!(static_cast<uGlobalMenu *>(mParent))->IsOpenOrOpening()) {
763
DEBUG_WITH_THIS_MENUOBJECT("Parent isn't open or opening. Marking invalid");
768
if (aAttribute == uWidgetAtoms::open) {
772
if (aAttribute == uWidgetAtoms::disabled) {
773
SyncSensitivityFromContent();
774
} else if (aAttribute == uWidgetAtoms::hidden ||
775
aAttribute == uWidgetAtoms::collapsed) {
776
SyncVisibilityFromContent();
777
} else if (aAttribute == uWidgetAtoms::label ||
778
aAttribute == uWidgetAtoms::accesskey) {
779
SyncLabelFromContent();
780
} else if (aAttribute == uWidgetAtoms::image) {
781
SyncIconFromContent();
782
} else if (aAttribute == uWidgetAtoms::_class) {
783
UpdateInfoFromContentClass();
784
SyncVisibilityFromContent();
785
SyncIconFromContent();
790
uGlobalMenu::ObserveContentRemoved(nsIDocument *aDocument,
791
nsIContent *aContainer,
793
PRInt32 aIndexInContainer)
795
TRACE_WITH_THIS_MENUOBJECT();
796
NS_ASSERTION(aContainer == mContent || aContainer == mPopupContent,
797
"Received an event that wasn't meant for us!");
799
if (DoesNeedRebuild()) {
800
DEBUG_WITH_THIS_MENUOBJECT("Previously marked as needing a rebuild");
804
if (!IsOpenOrOpening()) {
805
DEBUG_WITH_THIS_MENUOBJECT("Not open or opening - Marking as needing a rebuild");
810
if (aContainer == mPopupContent) {
811
bool res = RemoveMenuObjectAt(aIndexInContainer);
812
NS_WARN_IF_FALSE(res, "Failed to remove menuitem. Marking menu invalid");
822
uGlobalMenu::ObserveContentInserted(nsIDocument *aDocument,
823
nsIContent *aContainer,
825
PRInt32 aIndexInContainer)
827
TRACE_WITH_THIS_MENUOBJECT();
828
NS_ASSERTION(aContainer == mContent || aContainer == mPopupContent,
829
"Received an event that wasn't meant for us!");
831
if (DoesNeedRebuild()) {
832
DEBUG_WITH_THIS_MENUOBJECT("Previously marked as needing a rebuild");
836
if (!IsOpenOrOpening()) {
837
DEBUG_WITH_THIS_MENUOBJECT("Not open or opening - Marking as needing a rebuild");
842
if (aContainer == mPopupContent) {
843
uGlobalMenuObject *newItem =
844
NewGlobalMenuItem(static_cast<uGlobalMenuObject *>(this),
845
mListener, aChild, mMenuBar);
848
res = InsertMenuObjectAt(newItem, aIndexInContainer);
850
NS_WARN_IF_FALSE(res, "Failed to insert menuitem. Marking menu invalid");