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/. */
5 
6 #ifndef nsMenuBarX_h_
7 #define nsMenuBarX_h_
8 
9 #import <Cocoa/Cocoa.h>
10 
11 #include "mozilla/UniquePtr.h"
12 #include "mozilla/WeakPtr.h"
13 
14 #include "nsISupports.h"
15 #include "nsMenuParentX.h"
16 #include "nsMenuGroupOwnerX.h"
17 #include "nsChangeObserver.h"
18 #include "nsTArray.h"
19 #include "nsString.h"
20 
21 class nsMenuBarX;
22 class nsMenuX;
23 class nsIWidget;
24 class nsIContent;
25 
26 namespace mozilla {
27 namespace dom {
28 class Document;
29 class Element;
30 }
31 }
32 
33 // ApplicationMenuDelegate is used to receive Cocoa notifications.
34 @interface ApplicationMenuDelegate : NSObject <NSMenuDelegate> {
35   nsMenuBarX* mApplicationMenu;  // weak ref
36 }
37 - (id)initWithApplicationMenu:(nsMenuBarX*)aApplicationMenu;
38 @end
39 
40 // Objective-C class used to allow us to intervene with keyboard event handling.
41 // We allow mouse actions to work normally.
42 @interface GeckoNSMenu : NSMenu {
43 }
44 - (BOOL)performSuperKeyEquivalent:(NSEvent*)aEvent;
45 @end
46 
47 // Objective-C class used as action target for menu items
48 @interface NativeMenuItemTarget : NSObject {
49 }
50 - (IBAction)menuItemHit:(id)aSender;
51 @end
52 
53 // Objective-C class used for menu items on the Services menu to allow Gecko
54 // to override their standard behavior in order to stop key equivalents from
55 // firing in certain instances.
56 @interface GeckoServicesNSMenuItem : NSMenuItem {
57 }
58 - (id)target;
59 - (SEL)action;
60 - (void)_doNothing:(id)aSender;
61 @end
62 
63 // Objective-C class used as the Services menu so that Gecko can override the
64 // standard behavior of the Services menu in order to stop key equivalents
65 // from firing in certain instances.
66 @interface GeckoServicesNSMenu : NSMenu {
67 }
68 - (void)addItem:(NSMenuItem*)aNewItem;
69 - (NSMenuItem*)addItemWithTitle:(NSString*)aString
70                          action:(SEL)aSelector
71                   keyEquivalent:(NSString*)aKeyEquiv;
72 - (void)insertItem:(NSMenuItem*)aNewItem atIndex:(NSInteger)aIndex;
73 - (NSMenuItem*)insertItemWithTitle:(NSString*)aString
74                             action:(SEL)aSelector
75                      keyEquivalent:(NSString*)aKeyEquiv
76                            atIndex:(NSInteger)aIndex;
77 - (void)_overrideClassOfMenuItem:(NSMenuItem*)aMenuItem;
78 @end
79 
80 // Once instantiated, this object lives until its DOM node or its parent window is destroyed.
81 // Do not hold references to this, they can become invalid any time the DOM node can be destroyed.
82 class nsMenuBarX : public nsMenuParentX, public nsChangeObserver, public mozilla::SupportsWeakPtr {
83  public:
84   explicit nsMenuBarX(mozilla::dom::Element* aElement);
85 
86   NS_INLINE_DECL_REFCOUNTING(nsMenuBarX)
87 
88   static NativeMenuItemTarget* sNativeEventTarget;
89   static nsMenuBarX* sLastGeckoMenuBarPainted;
90 
91   // The following content nodes have been removed from the menu system.
92   // We save them here for use in command handling.
93   RefPtr<nsIContent> mAboutItemContent;
94   RefPtr<nsIContent> mPrefItemContent;
95   RefPtr<nsIContent> mQuitItemContent;
96 
97   // nsChangeObserver
98   NS_DECL_CHANGEOBSERVER
99 
100   // nsMenuParentX
AsMenuBar()101   nsMenuBarX* AsMenuBar() override { return this; }
102 
103   // nsMenuBarX
104   uint32_t GetMenuCount();
105   bool MenuContainsAppMenu();
106   nsMenuX* GetMenuAt(uint32_t aIndex);
107   nsMenuX* GetXULHelpMenu();
108   void SetSystemHelpMenu();
109   nsresult Paint();
110   void ForceUpdateNativeMenuAt(const nsAString& aIndexString);
111   void ForceNativeMenuReload();  // used for testing
112   static void ResetNativeApplicationMenu();
113   void SetNeedsRebuild();
114   void ApplicationMenuOpened();
115   bool PerformKeyEquivalent(NSEvent* aEvent);
NativeNSMenu()116   GeckoNSMenu* NativeNSMenu() { return mNativeMenu; }
117 
118   // nsMenuParentX
119   void MenuChildChangedVisibility(const MenuChild& aChild, bool aIsVisible) override;
120 
121  protected:
122   virtual ~nsMenuBarX();
123 
124   void ConstructNativeMenus();
125   void ConstructFallbackNativeMenus();
126   void InsertMenuAtIndex(RefPtr<nsMenuX>&& aMenu, uint32_t aIndex);
127   void RemoveMenuAtIndex(uint32_t aIndex);
128   RefPtr<mozilla::dom::Element> HideItem(mozilla::dom::Document* aDocument, const nsAString& aID);
129   void AquifyMenuBar();
130   NSMenuItem* CreateNativeAppMenuItem(nsMenuX* aMenu, const nsAString& aNodeID, SEL aAction,
131                                       int aTag, NativeMenuItemTarget* aTarget);
132   void CreateApplicationMenu(nsMenuX* aMenu);
133 
134   // Calculates the index at which aChild's NSMenuItem should be inserted into our NSMenu.
135   // The order of NSMenuItems in the NSMenu is the same as the order of nsMenuX objects in
136   // mMenuArray; there are two differences:
137   //  - mMenuArray contains both visible and invisible menus, and the NSMenu only contains visible
138   //    menus.
139   //  - Our NSMenu may also contain an item for the app menu, whereas mMenuArray never does.
140   // So the insertion index is equal to the number of visible previous siblings of aChild in
141   // mMenuArray, plus one if the app menu is present.
142   NSInteger CalculateNativeInsertionPoint(nsMenuX* aChild);
143 
144   RefPtr<nsIContent> mContent;
145   RefPtr<nsMenuGroupOwnerX> mMenuGroupOwner;
146   nsTArray<RefPtr<nsMenuX>> mMenuArray;
147   GeckoNSMenu* mNativeMenu;  // root menu, representing entire menu bar
148   bool mNeedsRebuild;
149   ApplicationMenuDelegate* mApplicationMenuDelegate;
150 };
151 
152 #endif  // nsMenuBarX_h_
153