summaryrefslogtreecommitdiffstats
path: root/widget/cocoa/nsMenuBarX.h
blob: 9990c59bc5d1493dce47aee63223fce5f9a3c914 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef nsMenuBarX_h_
#define nsMenuBarX_h_

#import <Cocoa/Cocoa.h>

#include "mozilla/UniquePtr.h"
#include "mozilla/WeakPtr.h"

#include "nsISupports.h"
#include "nsMenuParentX.h"
#include "nsChangeObserver.h"
#include "nsTArray.h"
#include "nsString.h"

class nsMenuBarX;
class nsMenuGroupOwnerX;
class nsMenuX;
class nsIWidget;
class nsIContent;

namespace mozilla {
namespace dom {
class Document;
class Element;
}  // namespace dom
}  // namespace mozilla

// ApplicationMenuDelegate is used to receive Cocoa notifications.
@interface ApplicationMenuDelegate : NSObject <NSMenuDelegate> {
  nsMenuBarX* mApplicationMenu;  // weak ref
}
- (id)initWithApplicationMenu:(nsMenuBarX*)aApplicationMenu;
@end

// Objective-C class used to allow us to intervene with keyboard event handling.
// We allow mouse actions to work normally.
@interface GeckoNSMenu : NSMenu {
}
- (BOOL)performSuperKeyEquivalent:(NSEvent*)aEvent;
@end

// Objective-C class used as action target for menu items
@interface NativeMenuItemTarget : NSObject {
}
- (IBAction)menuItemHit:(id)aSender;
@end

// Objective-C class used for menu items on the Services menu to allow Gecko
// to override their standard behavior in order to stop key equivalents from
// firing in certain instances.
@interface GeckoServicesNSMenuItem : NSMenuItem {
}
- (id)target;
- (SEL)action;
- (void)_doNothing:(id)aSender;
@end

// Objective-C class used as the Services menu so that Gecko can override the
// standard behavior of the Services menu in order to stop key equivalents
// from firing in certain instances.
@interface GeckoServicesNSMenu : NSMenu {
}
- (void)addItem:(NSMenuItem*)aNewItem;
- (NSMenuItem*)addItemWithTitle:(NSString*)aString
                         action:(SEL)aSelector
                  keyEquivalent:(NSString*)aKeyEquiv;
- (void)insertItem:(NSMenuItem*)aNewItem atIndex:(NSInteger)aIndex;
- (NSMenuItem*)insertItemWithTitle:(NSString*)aString
                            action:(SEL)aSelector
                     keyEquivalent:(NSString*)aKeyEquiv
                           atIndex:(NSInteger)aIndex;
- (void)_overrideClassOfMenuItem:(NSMenuItem*)aMenuItem;
@end

// Once instantiated, this object lives until its DOM node or its parent window is destroyed.
// Do not hold references to this, they can become invalid any time the DOM node can be destroyed.
class nsMenuBarX : public nsMenuParentX, public nsChangeObserver, public mozilla::SupportsWeakPtr {
 public:
  explicit nsMenuBarX(mozilla::dom::Element* aElement);

  NS_INLINE_DECL_REFCOUNTING(nsMenuBarX)

  static NativeMenuItemTarget* sNativeEventTarget;
  static nsMenuBarX* sLastGeckoMenuBarPainted;

  // The following content nodes have been removed from the menu system.
  // We save them here for use in command handling.
  RefPtr<nsIContent> mAboutItemContent;
  RefPtr<nsIContent> mPrefItemContent;
  RefPtr<nsIContent> mAccountItemContent;
  RefPtr<nsIContent> mQuitItemContent;

  // nsChangeObserver
  NS_DECL_CHANGEOBSERVER

  // nsMenuParentX
  nsMenuBarX* AsMenuBar() override { return this; }

  // nsMenuBarX
  uint32_t GetMenuCount();
  bool MenuContainsAppMenu();
  nsMenuX* GetMenuAt(uint32_t aIndex);
  nsMenuX* GetXULHelpMenu();
  void SetSystemHelpMenu();
  nsresult Paint();
  void ForceUpdateNativeMenuAt(const nsAString& aIndexString);
  void ForceNativeMenuReload();  // used for testing
  static void ResetNativeApplicationMenu();
  void SetNeedsRebuild();
  void ApplicationMenuOpened();
  bool PerformKeyEquivalent(NSEvent* aEvent);
  GeckoNSMenu* NativeNSMenu() { return mNativeMenu; }

  // nsMenuParentX
  void MenuChildChangedVisibility(const MenuChild& aChild, bool aIsVisible) override;

 protected:
  virtual ~nsMenuBarX();

  void ConstructNativeMenus();
  void ConstructFallbackNativeMenus();
  void InsertMenuAtIndex(RefPtr<nsMenuX>&& aMenu, uint32_t aIndex);
  void RemoveMenuAtIndex(uint32_t aIndex);
  RefPtr<mozilla::dom::Element> HideItem(mozilla::dom::Document* aDocument, const nsAString& aID);
  void AquifyMenuBar();
  NSMenuItem* CreateNativeAppMenuItem(nsMenuX* aMenu, const nsAString& aNodeID, SEL aAction,
                                      int aTag, NativeMenuItemTarget* aTarget);
  void CreateApplicationMenu(nsMenuX* aMenu);

  // Calculates the index at which aChild's NSMenuItem should be inserted into our NSMenu.
  // The order of NSMenuItems in the NSMenu is the same as the order of nsMenuX objects in
  // mMenuArray; there are two differences:
  //  - mMenuArray contains both visible and invisible menus, and the NSMenu only contains visible
  //    menus.
  //  - Our NSMenu may also contain an item for the app menu, whereas mMenuArray never does.
  // So the insertion index is equal to the number of visible previous siblings of aChild in
  // mMenuArray, plus one if the app menu is present.
  NSInteger CalculateNativeInsertionPoint(nsMenuX* aChild);

  RefPtr<nsIContent> mContent;
  RefPtr<nsMenuGroupOwnerX> mMenuGroupOwner;
  nsTArray<RefPtr<nsMenuX>> mMenuArray;
  GeckoNSMenu* mNativeMenu;  // root menu, representing entire menu bar
  bool mNeedsRebuild;
  ApplicationMenuDelegate* mApplicationMenuDelegate;
};

#endif  // nsMenuBarX_h_