Merge pull request #83987 from bruvzg/macos_window_and_help

[macOS] Add default Window and Help menus, allow special menu customization.
This commit is contained in:
Yuri Sizov 2023-12-18 18:17:41 +01:00
commit 644e236e5c
11 changed files with 477 additions and 228 deletions

View File

@ -235,6 +235,9 @@
[codeblock] [codeblock]
"_main" - Main menu (macOS). "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS). "_dock" - Dock popup menu (macOS).
"_apple" - Apple menu (macOS, custom items added before "Services").
"_window" - Window menu (macOS, custom items added after "Bring All to Front").
"_help" - Help menu (macOS).
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -258,6 +261,9 @@
[codeblock] [codeblock]
"_main" - Main menu (macOS). "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS). "_dock" - Dock popup menu (macOS).
"_apple" - Apple menu (macOS, custom items added before "Services").
"_window" - Window menu (macOS, custom items added after "Bring All to Front").
"_help" - Help menu (macOS).
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -281,6 +287,9 @@
[codeblock] [codeblock]
"_main" - Main menu (macOS). "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS). "_dock" - Dock popup menu (macOS).
"_apple" - Apple menu (macOS, custom items added before "Services").
"_window" - Window menu (macOS, custom items added after "Bring All to Front").
"_help" - Help menu (macOS).
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -305,6 +314,9 @@
[codeblock] [codeblock]
"_main" - Main menu (macOS). "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS). "_dock" - Dock popup menu (macOS).
"_apple" - Apple menu (macOS, custom items added before "Services").
"_window" - Window menu (macOS, custom items added after "Bring All to Front").
"_help" - Help menu (macOS).
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -327,6 +339,9 @@
[codeblock] [codeblock]
"_main" - Main menu (macOS). "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS). "_dock" - Dock popup menu (macOS).
"_apple" - Apple menu (macOS, custom items added before "Services").
"_window" - Window menu (macOS, custom items added after "Bring All to Front").
"_help" - Help menu (macOS).
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -353,6 +368,9 @@
[codeblock] [codeblock]
"_main" - Main menu (macOS). "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS). "_dock" - Dock popup menu (macOS).
"_apple" - Apple menu (macOS, custom items added before "Services").
"_window" - Window menu (macOS, custom items added after "Bring All to Front").
"_help" - Help menu (macOS).
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -376,6 +394,9 @@
[codeblock] [codeblock]
"_main" - Main menu (macOS). "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS). "_dock" - Dock popup menu (macOS).
"_apple" - Apple menu (macOS, custom items added before "Services").
"_window" - Window menu (macOS, custom items added after "Bring All to Front").
"_help" - Help menu (macOS).
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -391,6 +412,9 @@
[codeblock] [codeblock]
"_main" - Main menu (macOS). "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS). "_dock" - Dock popup menu (macOS).
"_apple" - Apple menu (macOS, custom items added before "Services").
"_window" - Window menu (macOS, custom items added after "Bring All to Front").
"_help" - Help menu (macOS).
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -408,6 +432,9 @@
[codeblock] [codeblock]
"_main" - Main menu (macOS). "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS). "_dock" - Dock popup menu (macOS).
"_apple" - Apple menu (macOS, custom items added before "Services").
"_window" - Window menu (macOS, custom items added after "Bring All to Front").
"_help" - Help menu (macOS).
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -421,6 +448,9 @@
[codeblock] [codeblock]
"_main" - Main menu (macOS). "_main" - Main menu (macOS).
"_dock" - Dock popup menu (macOS). "_dock" - Dock popup menu (macOS).
"_apple" - Apple menu (macOS, custom items added before "Services").
"_window" - Window menu (macOS, custom items added after "Bring All to Front").
"_help" - Help menu (macOS).
[/codeblock] [/codeblock]
</description> </description>
</method> </method>
@ -549,6 +579,13 @@
[b]Note:[/b] This method is implemented only on macOS. [b]Note:[/b] This method is implemented only on macOS.
</description> </description>
</method> </method>
<method name="global_menu_get_system_menu_roots" qualifiers="const">
<return type="Dictionary" />
<description>
Returns Dictionary of supported system menu IDs and names.
[b]Note:[/b] This method is implemented only on macOS.
</description>
</method>
<method name="global_menu_is_item_checkable" qualifiers="const"> <method name="global_menu_is_item_checkable" qualifiers="const">
<return type="bool" /> <return type="bool" />
<param index="0" name="menu_root" type="String" /> <param index="0" name="menu_root" type="String" />

View File

@ -346,6 +346,12 @@
Returns [code]true[/code] if the specified item's shortcut is disabled. Returns [code]true[/code] if the specified item's shortcut is disabled.
</description> </description>
</method> </method>
<method name="is_system_menu" qualifiers="const">
<return type="bool" />
<description>
Returns [code]true[/code] if the menu is bound to the special system menu.
</description>
</method>
<method name="remove_item"> <method name="remove_item">
<return type="void" /> <return type="void" />
<param index="0" name="index" type="int" /> <param index="0" name="index" type="int" />
@ -566,6 +572,9 @@
<member name="submenu_popup_delay" type="float" setter="set_submenu_popup_delay" getter="get_submenu_popup_delay" default="0.3"> <member name="submenu_popup_delay" type="float" setter="set_submenu_popup_delay" getter="get_submenu_popup_delay" default="0.3">
Sets the delay time in seconds for the submenu item to popup on mouse hovering. If the popup menu is added as a child of another (acting as a submenu), it will inherit the delay time of the parent menu item. Sets the delay time in seconds for the submenu item to popup on mouse hovering. If the popup menu is added as a child of another (acting as a submenu), it will inherit the delay time of the parent menu item.
</member> </member>
<member name="system_menu_root" type="String" setter="set_system_menu_root" getter="get_system_menu_root" default="&quot;&quot;">
If set to one of the values returned by [method DisplayServer.global_menu_get_system_menu_roots], this [PopupMenu] is bound to the special system menu. Only one [PopupMenu] can be bound to each special menu at a time.
</member>
</members> </members>
<signals> <signals>
<signal name="id_focused"> <signal name="id_focused">

View File

@ -7357,6 +7357,20 @@ EditorNode::EditorNode() {
file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/file_quit", TTR("Quit"), KeyModifierMask::CMD_OR_CTRL + Key::Q), FILE_QUIT, true); file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/file_quit", TTR("Quit"), KeyModifierMask::CMD_OR_CTRL + Key::Q), FILE_QUIT, true);
} }
ED_SHORTCUT_AND_COMMAND("editor/editor_settings", TTR("Editor Settings..."));
ED_SHORTCUT_OVERRIDE("editor/editor_settings", "macos", KeyModifierMask::META + Key::COMMA);
#ifdef MACOS_ENABLED
if (global_menu) {
apple_menu = memnew(PopupMenu);
apple_menu->set_system_menu_root("_apple");
main_menu->add_child(apple_menu);
apple_menu->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES);
apple_menu->add_separator();
apple_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));
}
#endif
project_menu = memnew(PopupMenu); project_menu = memnew(PopupMenu);
project_menu->set_name(TTR("Project")); project_menu->set_name(TTR("Project"));
main_menu->add_child(project_menu); main_menu->add_child(project_menu);
@ -7422,9 +7436,13 @@ EditorNode::EditorNode() {
settings_menu->set_name(TTR("Editor")); settings_menu->set_name(TTR("Editor"));
main_menu->add_child(settings_menu); main_menu->add_child(settings_menu);
ED_SHORTCUT_AND_COMMAND("editor/editor_settings", TTR("Editor Settings...")); #ifdef MACOS_ENABLED
ED_SHORTCUT_OVERRIDE("editor/editor_settings", "macos", KeyModifierMask::META + Key::COMMA); if (!global_menu) {
settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES);
}
#else
settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES); settings_menu->add_shortcut(ED_GET_SHORTCUT("editor/editor_settings"), SETTINGS_PREFERENCES);
#endif
settings_menu->add_shortcut(ED_SHORTCUT("editor/command_palette", TTR("Command Palette..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::P), HELP_COMMAND_PALETTE); settings_menu->add_shortcut(ED_SHORTCUT("editor/command_palette", TTR("Command Palette..."), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::P), HELP_COMMAND_PALETTE);
settings_menu->add_separator(); settings_menu->add_separator();
@ -7471,6 +7489,7 @@ EditorNode::EditorNode() {
help_menu = memnew(PopupMenu); help_menu = memnew(PopupMenu);
help_menu->set_name(TTR("Help")); help_menu->set_name(TTR("Help"));
help_menu->set_system_menu_root("_help");
main_menu->add_child(help_menu); main_menu->add_child(help_menu);
help_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option)); help_menu->connect("id_pressed", callable_mp(this, &EditorNode::_menu_option));

View File

@ -346,6 +346,7 @@ private:
EditorRunBar *project_run_bar = nullptr; EditorRunBar *project_run_bar = nullptr;
VBoxContainer *main_screen_vbox = nullptr; VBoxContainer *main_screen_vbox = nullptr;
MenuBar *main_menu = nullptr; MenuBar *main_menu = nullptr;
PopupMenu *apple_menu = nullptr;
PopupMenu *file_menu = nullptr; PopupMenu *file_menu = nullptr;
PopupMenu *project_menu = nullptr; PopupMenu *project_menu = nullptr;
PopupMenu *debug_menu = nullptr; PopupMenu *debug_menu = nullptr;

View File

@ -140,6 +140,8 @@ private:
String rendering_driver; String rendering_driver;
NSMenu *apple_menu = nullptr; NSMenu *apple_menu = nullptr;
NSMenu *window_menu = nullptr;
NSMenu *help_menu = nullptr;
NSMenu *dock_menu = nullptr; NSMenu *dock_menu = nullptr;
struct MenuData { struct MenuData {
Callable open; Callable open;
@ -226,7 +228,8 @@ private:
static NSCursor *_cursor_from_selector(SEL p_selector, SEL p_fallback = nil); static NSCursor *_cursor_from_selector(SEL p_selector, SEL p_fallback = nil);
bool _has_help_menu() const; int _get_system_menu_start(const NSMenu *p_menu) const;
int _get_system_menu_count(const NSMenu *p_menu) const;
NSMenuItem *_menu_add_item(const String &p_menu_root, const String &p_label, Key p_accel, int p_index, int *r_out); NSMenuItem *_menu_add_item(const String &p_menu_root, const String &p_label, Key p_accel, int p_index, int *r_out);
public: public:
@ -321,6 +324,8 @@ public:
virtual void global_menu_remove_item(const String &p_menu_root, int p_idx) override; virtual void global_menu_remove_item(const String &p_menu_root, int p_idx) override;
virtual void global_menu_clear(const String &p_menu_root) override; virtual void global_menu_clear(const String &p_menu_root) override;
virtual Dictionary global_menu_get_system_menu_roots() const override;
virtual bool tts_is_speaking() const override; virtual bool tts_is_speaking() const override;
virtual bool tts_is_paused() const override; virtual bool tts_is_paused() const override;
virtual TypedArray<Dictionary> tts_get_voices() const override; virtual TypedArray<Dictionary> tts_get_voices() const override;

View File

@ -64,6 +64,9 @@
#import <IOKit/hid/IOHIDKeys.h> #import <IOKit/hid/IOHIDKeys.h>
#import <IOKit/hid/IOHIDLib.h> #import <IOKit/hid/IOHIDLib.h>
#define MENU_TAG_START 0x00004447
#define MENU_TAG_END 0xFFFF4447
const NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) const { const NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) const {
const NSMenu *menu = nullptr; const NSMenu *menu = nullptr;
if (p_menu_root == "" || p_menu_root.to_lower() == "_main") { if (p_menu_root == "" || p_menu_root.to_lower() == "_main") {
@ -72,16 +75,21 @@ const NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) cons
} else if (p_menu_root.to_lower() == "_dock") { } else if (p_menu_root.to_lower() == "_dock") {
// macOS dock menu. // macOS dock menu.
menu = dock_menu; menu = dock_menu;
} else if (p_menu_root.to_lower() == "_apple") {
// macOS Apple menu.
menu = apple_menu;
} else if (p_menu_root.to_lower() == "_window") {
// macOS Window menu.
menu = window_menu;
} else if (p_menu_root.to_lower() == "_help") {
// macOS Help menu.
menu = help_menu;
} else { } else {
// Submenu. // Submenu.
if (submenu.has(p_menu_root)) { if (submenu.has(p_menu_root)) {
menu = submenu[p_menu_root].menu; menu = submenu[p_menu_root].menu;
} }
} }
if (menu == apple_menu) {
// Do not allow to change Apple menu.
return nullptr;
}
return menu; return menu;
} }
@ -93,6 +101,15 @@ NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) {
} else if (p_menu_root.to_lower() == "_dock") { } else if (p_menu_root.to_lower() == "_dock") {
// macOS dock menu. // macOS dock menu.
menu = dock_menu; menu = dock_menu;
} else if (p_menu_root.to_lower() == "_apple") {
// macOS Apple menu.
menu = apple_menu;
} else if (p_menu_root.to_lower() == "_window") {
// macOS Window menu.
menu = window_menu;
} else if (p_menu_root.to_lower() == "_help") {
// macOS Help menu.
menu = help_menu;
} else { } else {
// Submenu. // Submenu.
if (!submenu.has(p_menu_root)) { if (!submenu.has(p_menu_root)) {
@ -104,10 +121,6 @@ NSMenu *DisplayServerMacOS::_get_menu_root(const String &p_menu_root) {
} }
menu = submenu[p_menu_root].menu; menu = submenu[p_menu_root].menu;
} }
if (menu == apple_menu) {
// Do not allow to change Apple menu.
return nullptr;
}
return menu; return menu;
} }
@ -820,22 +833,6 @@ String DisplayServerMacOS::get_name() const {
return "macOS"; return "macOS";
} }
bool DisplayServerMacOS::_has_help_menu() const {
if ([NSApp helpMenu]) {
return true;
} else {
NSMenu *menu = [NSApp mainMenu];
const NSMenuItem *menu_item = [menu itemAtIndex:[menu numberOfItems] - 1];
if (menu_item) {
String menu_name = String::utf8([[menu_item title] UTF8String]);
if (menu_name == "Help" || menu_name == RTR("Help")) {
return true;
}
}
return false;
}
}
bool DisplayServerMacOS::_is_menu_opened(NSMenu *p_menu) const { bool DisplayServerMacOS::_is_menu_opened(NSMenu *p_menu) const {
if (submenu_inv.has(p_menu)) { if (submenu_inv.has(p_menu)) {
const MenuData &md = submenu[submenu_inv[p_menu]]; const MenuData &md = submenu[submenu_inv[p_menu]];
@ -854,24 +851,57 @@ bool DisplayServerMacOS::_is_menu_opened(NSMenu *p_menu) const {
return false; return false;
} }
int DisplayServerMacOS::_get_system_menu_start(const NSMenu *p_menu) const {
if (p_menu == [NSApp mainMenu]) { // Skip Apple menu.
return 1;
}
if (p_menu == apple_menu || p_menu == window_menu || p_menu == help_menu) {
int count = [p_menu numberOfItems];
for (int i = 0; i < count; i++) {
NSMenuItem *menu_item = [p_menu itemAtIndex:i];
if (menu_item.tag == MENU_TAG_START) {
return i + 1;
}
}
}
return 0;
}
int DisplayServerMacOS::_get_system_menu_count(const NSMenu *p_menu) const {
if (p_menu == [NSApp mainMenu]) { // Skip Apple, Window and Help menu.
return [p_menu numberOfItems] - 3;
}
if (p_menu == apple_menu || p_menu == window_menu || p_menu == help_menu) {
int start = 0;
int count = [p_menu numberOfItems];
for (int i = 0; i < count; i++) {
NSMenuItem *menu_item = [p_menu itemAtIndex:i];
if (menu_item.tag == MENU_TAG_START) {
start = i + 1;
}
if (menu_item.tag == MENU_TAG_END) {
return i - start;
}
}
}
return [p_menu numberOfItems];
}
NSMenuItem *DisplayServerMacOS::_menu_add_item(const String &p_menu_root, const String &p_label, Key p_accel, int p_index, int *r_out) { NSMenuItem *DisplayServerMacOS::_menu_add_item(const String &p_menu_root, const String &p_label, Key p_accel, int p_index, int *r_out) {
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK); String keycode = KeyMappingMacOS::keycode_get_native_string(p_accel & KeyModifierMask::CODE_MASK);
NSMenuItem *menu_item; NSMenuItem *menu_item;
int item_count = ((menu == [NSApp mainMenu]) && _has_help_menu()) ? [menu numberOfItems] - 1 : [menu numberOfItems]; int item_start = _get_system_menu_start(menu);
if ((menu == [NSApp mainMenu]) && (p_label == "Help" || p_label == RTR("Help"))) { int item_count = _get_system_menu_count(menu);
p_index = [menu numberOfItems]; if (p_index < 0) {
} else if (p_index < 0) { p_index = item_start + item_count;
p_index = item_count;
} else { } else {
if (menu == [NSApp mainMenu]) { // Skip Apple menu. p_index += item_start;
p_index++; p_index = CLAMP(p_index, item_start, item_start + item_count);
}
p_index = CLAMP(p_index, 0, item_count);
} }
menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index]; menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()] atIndex:p_index];
*r_out = (menu == [NSApp mainMenu]) ? p_index - 1 : p_index; *r_out = p_index - item_start;
return menu_item; return menu_item;
} }
return nullptr; return nullptr;
@ -1070,19 +1100,16 @@ int DisplayServerMacOS::global_menu_add_submenu_item(const String &p_menu_root,
return -1; return -1;
} }
NSMenuItem *menu_item; NSMenuItem *menu_item;
int item_count = ((menu == [NSApp mainMenu]) && _has_help_menu()) ? [menu numberOfItems] - 1 : [menu numberOfItems]; int item_start = _get_system_menu_start(menu);
if ((menu == [NSApp mainMenu]) && (p_label == "Help" || p_label == RTR("Help"))) { int item_count = _get_system_menu_count(menu);
p_index = [menu numberOfItems]; if (p_index < 0) {
} else if (p_index < 0) { p_index = item_start + item_count;
p_index = item_count;
} else { } else {
if (menu == [NSApp mainMenu]) { // Skip Apple menu. p_index += item_start;
p_index++; p_index = CLAMP(p_index, item_start, item_start + item_count);
}
p_index = CLAMP(p_index, 0, item_count);
} }
menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index]; menu_item = [menu insertItemWithTitle:[NSString stringWithUTF8String:p_label.utf8().get_data()] action:nil keyEquivalent:@"" atIndex:p_index];
out = (menu == [NSApp mainMenu]) ? p_index - 1 : p_index; out = p_index - item_start;
GodotMenuItem *obj = [[GodotMenuItem alloc] init]; GodotMenuItem *obj = [[GodotMenuItem alloc] init];
obj->callback = Callable(); obj->callback = Callable();
@ -1105,13 +1132,16 @@ int DisplayServerMacOS::global_menu_add_separator(const String &p_menu_root, int
if (menu == [NSApp mainMenu]) { // Do not add separators into main menu. if (menu == [NSApp mainMenu]) { // Do not add separators into main menu.
return -1; return -1;
} }
int item_start = _get_system_menu_start(menu);
int item_count = _get_system_menu_count(menu);
if (p_index < 0) { if (p_index < 0) {
p_index = [menu numberOfItems]; p_index = item_start + item_count;
} else { } else {
p_index = CLAMP(p_index, 0, [menu numberOfItems]); p_index += item_start;
p_index = CLAMP(p_index, item_start, item_start + item_count);
} }
[menu insertItem:[NSMenuItem separatorItem] atIndex:p_index]; [menu insertItem:[NSMenuItem separatorItem] atIndex:p_index];
return p_index; return p_index - item_start;
} }
return -1; return -1;
} }
@ -1121,11 +1151,8 @@ int DisplayServerMacOS::global_menu_get_item_index_from_text(const String &p_men
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]] - 1; return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]] - item_start;
} else {
return [menu indexOfItemWithTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]];
}
} }
return -1; return -1;
@ -1136,16 +1163,14 @@ int DisplayServerMacOS::global_menu_get_item_index_from_tag(const String &p_menu
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
for (NSInteger i = (menu == [NSApp mainMenu]) ? 1 : 0; i < [menu numberOfItems]; i++) { int item_start = _get_system_menu_start(menu);
int item_count = _get_system_menu_count(menu);
for (NSInteger i = item_start; i < item_start + item_count; i++) {
const NSMenuItem *menu_item = [menu itemAtIndex:i]; const NSMenuItem *menu_item = [menu itemAtIndex:i];
if (menu_item) { if (menu_item) {
const GodotMenuItem *obj = [menu_item representedObject]; const GodotMenuItem *obj = [menu_item representedObject];
if (obj && obj->meta == p_tag) { if (obj && obj->meta == p_tag) {
if (menu == [NSApp mainMenu]) { // Skip Apple menu. return i - item_start;
return i - 1;
} else {
return i;
}
} }
} }
} }
@ -1160,10 +1185,10 @@ bool DisplayServerMacOS::global_menu_is_item_checked(const String &p_menu_root,
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, false); ERR_FAIL_COND_V(p_idx < 0, false);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false); ERR_FAIL_COND_V(p_idx >= item_start + item_count, false);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
return ([menu_item state] == NSControlStateValueOn); return ([menu_item state] == NSControlStateValueOn);
@ -1178,10 +1203,10 @@ bool DisplayServerMacOS::global_menu_is_item_checkable(const String &p_menu_root
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, false); ERR_FAIL_COND_V(p_idx < 0, false);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false); ERR_FAIL_COND_V(p_idx >= item_start + item_count, false);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1199,10 +1224,10 @@ bool DisplayServerMacOS::global_menu_is_item_radio_checkable(const String &p_men
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, false); ERR_FAIL_COND_V(p_idx < 0, false);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false); ERR_FAIL_COND_V(p_idx >= item_start + item_count, false);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1220,10 +1245,10 @@ Callable DisplayServerMacOS::global_menu_get_item_callback(const String &p_menu_
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, Callable()); ERR_FAIL_COND_V(p_idx < 0, Callable());
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Callable()); ERR_FAIL_COND_V(p_idx >= item_start + item_count, Callable());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1241,10 +1266,10 @@ Callable DisplayServerMacOS::global_menu_get_item_key_callback(const String &p_m
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, Callable()); ERR_FAIL_COND_V(p_idx < 0, Callable());
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Callable()); ERR_FAIL_COND_V(p_idx >= item_start + item_count, Callable());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1262,10 +1287,10 @@ Variant DisplayServerMacOS::global_menu_get_item_tag(const String &p_menu_root,
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, Variant()); ERR_FAIL_COND_V(p_idx < 0, Variant());
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Variant()); ERR_FAIL_COND_V(p_idx >= item_start + item_count, Variant());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1283,10 +1308,10 @@ String DisplayServerMacOS::global_menu_get_item_text(const String &p_menu_root,
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, String()); ERR_FAIL_COND_V(p_idx < 0, String());
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], String()); ERR_FAIL_COND_V(p_idx >= item_start + item_count, String());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
return String::utf8([[menu_item title] UTF8String]); return String::utf8([[menu_item title] UTF8String]);
@ -1301,10 +1326,10 @@ String DisplayServerMacOS::global_menu_get_item_submenu(const String &p_menu_roo
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, String()); ERR_FAIL_COND_V(p_idx < 0, String());
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], String()); ERR_FAIL_COND_V(p_idx >= item_start + item_count, String());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
NSMenu *sub_menu = [menu_item submenu]; NSMenu *sub_menu = [menu_item submenu];
@ -1322,10 +1347,10 @@ Key DisplayServerMacOS::global_menu_get_item_accelerator(const String &p_menu_ro
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, Key::NONE); ERR_FAIL_COND_V(p_idx < 0, Key::NONE);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Key::NONE); ERR_FAIL_COND_V(p_idx >= item_start + item_count, Key::NONE);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
String ret = String::utf8([[menu_item keyEquivalent] UTF8String]); String ret = String::utf8([[menu_item keyEquivalent] UTF8String]);
@ -1358,10 +1383,10 @@ bool DisplayServerMacOS::global_menu_is_item_disabled(const String &p_menu_root,
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, false); ERR_FAIL_COND_V(p_idx < 0, false);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false); ERR_FAIL_COND_V(p_idx >= item_start + item_count, false);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
return ![menu_item isEnabled]; return ![menu_item isEnabled];
@ -1376,10 +1401,10 @@ bool DisplayServerMacOS::global_menu_is_item_hidden(const String &p_menu_root, i
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, false); ERR_FAIL_COND_V(p_idx < 0, false);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], false); ERR_FAIL_COND_V(p_idx >= item_start + item_count, false);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
return [menu_item isHidden]; return [menu_item isHidden];
@ -1394,10 +1419,10 @@ String DisplayServerMacOS::global_menu_get_item_tooltip(const String &p_menu_roo
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, String()); ERR_FAIL_COND_V(p_idx < 0, String());
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], String()); ERR_FAIL_COND_V(p_idx >= item_start + item_count, String());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
return String::utf8([[menu_item toolTip] UTF8String]); return String::utf8([[menu_item toolTip] UTF8String]);
@ -1412,10 +1437,10 @@ int DisplayServerMacOS::global_menu_get_item_state(const String &p_menu_root, in
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, 0); ERR_FAIL_COND_V(p_idx < 0, 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], 0); ERR_FAIL_COND_V(p_idx >= item_start + item_count, 0);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1433,10 +1458,10 @@ int DisplayServerMacOS::global_menu_get_item_max_states(const String &p_menu_roo
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, 0); ERR_FAIL_COND_V(p_idx < 0, 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], 0); ERR_FAIL_COND_V(p_idx >= item_start + item_count, 0);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1454,10 +1479,10 @@ Ref<Texture2D> DisplayServerMacOS::global_menu_get_item_icon(const String &p_men
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>()); ERR_FAIL_COND_V(p_idx < 0, Ref<Texture2D>());
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], Ref<Texture2D>()); ERR_FAIL_COND_V(p_idx >= item_start + item_count, Ref<Texture2D>());
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1477,10 +1502,10 @@ int DisplayServerMacOS::global_menu_get_item_indentation_level(const String &p_m
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND_V(p_idx < 0, 0); ERR_FAIL_COND_V(p_idx < 0, 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND_V(p_idx >= [menu numberOfItems], 0); ERR_FAIL_COND_V(p_idx >= item_start + item_count, 0);
const NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; const NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
return [menu_item indentationLevel]; return [menu_item indentationLevel];
@ -1495,10 +1520,10 @@ void DisplayServerMacOS::global_menu_set_item_checked(const String &p_menu_root,
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
if (p_checked) { if (p_checked) {
@ -1516,10 +1541,10 @@ void DisplayServerMacOS::global_menu_set_item_checkable(const String &p_menu_roo
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1535,10 +1560,10 @@ void DisplayServerMacOS::global_menu_set_item_radio_checkable(const String &p_me
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1554,10 +1579,10 @@ void DisplayServerMacOS::global_menu_set_item_callback(const String &p_menu_root
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1573,10 +1598,10 @@ void DisplayServerMacOS::global_menu_set_item_hover_callbacks(const String &p_me
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1592,10 +1617,10 @@ void DisplayServerMacOS::global_menu_set_item_key_callback(const String &p_menu_
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1611,10 +1636,10 @@ void DisplayServerMacOS::global_menu_set_item_tag(const String &p_menu_root, int
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1630,10 +1655,10 @@ void DisplayServerMacOS::global_menu_set_item_text(const String &p_menu_root, in
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
[menu_item setTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]]; [menu_item setTitle:[NSString stringWithUTF8String:p_text.utf8().get_data()]];
@ -1647,10 +1672,10 @@ void DisplayServerMacOS::global_menu_set_item_submenu(const String &p_menu_root,
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu && p_submenu.is_empty()) { if (menu && p_submenu.is_empty()) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
if ([menu_item submenu] && _is_menu_opened([menu_item submenu])) { if ([menu_item submenu] && _is_menu_opened([menu_item submenu])) {
@ -1673,10 +1698,10 @@ void DisplayServerMacOS::global_menu_set_item_submenu(const String &p_menu_root,
return; return;
} }
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
[menu setSubmenu:sub_menu forItem:menu_item]; [menu setSubmenu:sub_menu forItem:menu_item];
@ -1690,10 +1715,10 @@ void DisplayServerMacOS::global_menu_set_item_accelerator(const String &p_menu_r
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
if (p_keycode == Key::NONE) { if (p_keycode == Key::NONE) {
@ -1713,10 +1738,10 @@ void DisplayServerMacOS::global_menu_set_item_disabled(const String &p_menu_root
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
[menu_item setEnabled:(!p_disabled)]; [menu_item setEnabled:(!p_disabled)];
@ -1730,10 +1755,10 @@ void DisplayServerMacOS::global_menu_set_item_hidden(const String &p_menu_root,
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
[menu_item setHidden:p_hidden]; [menu_item setHidden:p_hidden];
@ -1747,10 +1772,10 @@ void DisplayServerMacOS::global_menu_set_item_tooltip(const String &p_menu_root,
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
[menu_item setToolTip:[NSString stringWithUTF8String:p_tooltip.utf8().get_data()]]; [menu_item setToolTip:[NSString stringWithUTF8String:p_tooltip.utf8().get_data()]];
@ -1764,10 +1789,10 @@ void DisplayServerMacOS::global_menu_set_item_state(const String &p_menu_root, i
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1783,10 +1808,10 @@ void DisplayServerMacOS::global_menu_set_item_max_states(const String &p_menu_ro
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1802,10 +1827,10 @@ void DisplayServerMacOS::global_menu_set_item_icon(const String &p_menu_root, in
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject]; GodotMenuItem *obj = [menu_item representedObject];
@ -1832,10 +1857,10 @@ void DisplayServerMacOS::global_menu_set_item_indentation_level(const String &p_
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) { if (menu_item) {
[menu_item setIndentationLevel:p_level]; [menu_item setIndentationLevel:p_level];
@ -1848,11 +1873,7 @@ int DisplayServerMacOS::global_menu_get_item_count(const String &p_menu_root) co
const NSMenu *menu = _get_menu_root(p_menu_root); const NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
if (menu == [NSApp mainMenu]) { // Skip Apple menu. return _get_system_menu_count(menu);
return [menu numberOfItems] - 1;
} else {
return [menu numberOfItems];
}
} else { } else {
return 0; return 0;
} }
@ -1864,10 +1885,10 @@ void DisplayServerMacOS::global_menu_remove_item(const String &p_menu_root, int
NSMenu *menu = _get_menu_root(p_menu_root); NSMenu *menu = _get_menu_root(p_menu_root);
if (menu) { if (menu) {
ERR_FAIL_COND(p_idx < 0); ERR_FAIL_COND(p_idx < 0);
if (menu == [NSApp mainMenu]) { // Skip Apple menu. int item_start = _get_system_menu_start(menu);
p_idx++; int item_count = _get_system_menu_count(menu);
} p_idx += item_start;
ERR_FAIL_COND(p_idx >= [menu numberOfItems]); ERR_FAIL_COND(p_idx >= item_start + item_count);
NSMenuItem *menu_item = [menu itemAtIndex:p_idx]; NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if ([menu_item submenu] && _is_menu_opened([menu_item submenu])) { if ([menu_item submenu] && _is_menu_opened([menu_item submenu])) {
ERR_PRINT("Can't remove open menu!"); ERR_PRINT("Can't remove open menu!");
@ -1886,12 +1907,41 @@ void DisplayServerMacOS::global_menu_clear(const String &p_menu_root) {
ERR_PRINT("Can't remove open menu!"); ERR_PRINT("Can't remove open menu!");
return; return;
} }
[menu removeAllItems];
// Restore Apple menu. if (menu == apple_menu) {
int start = _get_system_menu_start(apple_menu);
int count = _get_system_menu_count(apple_menu);
for (int i = start + count - 1; i >= start; i--) {
[apple_menu removeItemAtIndex:i];
}
} else if (menu == window_menu) {
int start = _get_system_menu_start(window_menu);
int count = _get_system_menu_count(window_menu);
for (int i = start + count - 1; i >= start; i--) {
[window_menu removeItemAtIndex:i];
}
} else if (menu == help_menu) {
int start = _get_system_menu_start(help_menu);
int count = _get_system_menu_count(help_menu);
for (int i = start + count - 1; i >= start; i--) {
[help_menu removeItemAtIndex:i];
}
} else {
[menu removeAllItems];
}
// Restore Apple, Window and Help menu.
if (menu == [NSApp mainMenu]) { if (menu == [NSApp mainMenu]) {
NSMenuItem *menu_item = [menu addItemWithTitle:@"" action:nil keyEquivalent:@""]; NSMenuItem *menu_item = [menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
[menu setSubmenu:apple_menu forItem:menu_item]; [menu setSubmenu:apple_menu forItem:menu_item];
menu_item = [menu addItemWithTitle:@"Window" action:nil keyEquivalent:@""];
[menu setSubmenu:window_menu forItem:menu_item];
menu_item = [menu addItemWithTitle:@"Help" action:nil keyEquivalent:@""];
[menu setSubmenu:help_menu forItem:menu_item];
} }
if (submenu.has(p_menu_root)) { if (submenu.has(p_menu_root)) {
submenu_inv.erase(submenu[p_menu_root].menu); submenu_inv.erase(submenu[p_menu_root].menu);
submenu.erase(p_menu_root); submenu.erase(p_menu_root);
@ -1899,6 +1949,15 @@ void DisplayServerMacOS::global_menu_clear(const String &p_menu_root) {
} }
} }
Dictionary DisplayServerMacOS::global_menu_get_system_menu_roots() const {
Dictionary out;
out["_dock"] = "@Dock";
out["_apple"] = "@Apple";
out["_window"] = "Window";
out["_help"] = "Help";
return out;
}
bool DisplayServerMacOS::tts_is_speaking() const { bool DisplayServerMacOS::tts_is_speaking() const {
ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech."); ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return [tts isSpeaking]; return [tts isSpeaking];
@ -3564,6 +3623,9 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
} break; } break;
case WINDOW_FLAG_NO_FOCUS: { case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled; wd.no_focus = p_enabled;
NSWindow *w = wd.window_object;
w.excludedFromWindowsMenu = wd.is_popup || wd.no_focus;
} break; } break;
case WINDOW_FLAG_MOUSE_PASSTHROUGH: { case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
wd.mpass = p_enabled; wd.mpass = p_enabled;
@ -3572,6 +3634,9 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup."); ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
ERR_FAIL_COND_MSG([wd.window_object isVisible] && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened."); ERR_FAIL_COND_MSG([wd.window_object isVisible] && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened.");
wd.is_popup = p_enabled; wd.is_popup = p_enabled;
NSWindow *w = wd.window_object;
w.excludedFromWindowsMenu = wd.is_popup || wd.no_focus;
} break; } break;
default: { default: {
} }
@ -4488,6 +4553,13 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
[apple_menu addItem:[NSMenuItem separatorItem]]; [apple_menu addItem:[NSMenuItem separatorItem]];
menu_item = [apple_menu addItemWithTitle:@"_start_" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
menu_item.tag = MENU_TAG_START;
menu_item = [apple_menu addItemWithTitle:@"_end_" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
menu_item.tag = MENU_TAG_END;
NSMenu *services = [[NSMenu alloc] initWithTitle:@""]; NSMenu *services = [[NSMenu alloc] initWithTitle:@""];
menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Services", nil) action:nil keyEquivalent:@""]; menu_item = [apple_menu addItemWithTitle:NSLocalizedString(@"Services", nil) action:nil keyEquivalent:@""];
[apple_menu setSubmenu:services forItem:menu_item]; [apple_menu setSubmenu:services forItem:menu_item];
@ -4508,10 +4580,41 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname]; title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname];
[apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; [apple_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
window_menu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Window", nil)];
[window_menu addItemWithTitle:NSLocalizedString(@"Minimize", nil) action:@selector(performMiniaturize:) keyEquivalent:@"m"];
[window_menu addItemWithTitle:NSLocalizedString(@"Zoom", nil) action:@selector(performZoom:) keyEquivalent:@""];
[window_menu addItem:[NSMenuItem separatorItem]];
[window_menu addItemWithTitle:NSLocalizedString(@"Bring All to Front", nil) action:@selector(bringAllToFront:) keyEquivalent:@""];
[window_menu addItem:[NSMenuItem separatorItem]];
menu_item = [window_menu addItemWithTitle:@"_start_" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
menu_item.tag = MENU_TAG_START;
menu_item = [window_menu addItemWithTitle:@"_end_" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
menu_item.tag = MENU_TAG_END;
help_menu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Help", nil)];
menu_item = [help_menu addItemWithTitle:@"_start_" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
menu_item.tag = MENU_TAG_START;
menu_item = [help_menu addItemWithTitle:@"_end_" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
menu_item.tag = MENU_TAG_END;
[NSApp setWindowsMenu:window_menu];
[NSApp setHelpMenu:help_menu];
// Add items to the menu bar. // Add items to the menu bar.
NSMenu *main_menu = [NSApp mainMenu]; NSMenu *main_menu = [NSApp mainMenu];
menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""]; menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
[main_menu setSubmenu:apple_menu forItem:menu_item]; [main_menu setSubmenu:apple_menu forItem:menu_item];
menu_item = [main_menu addItemWithTitle:NSLocalizedString(@"Window", nil) action:nil keyEquivalent:@""];
[main_menu setSubmenu:window_menu forItem:menu_item];
menu_item = [main_menu addItemWithTitle:NSLocalizedString(@"Help", nil) action:nil keyEquivalent:@""];
[main_menu setSubmenu:help_menu forItem:menu_item];
[main_menu setAutoenablesItems:NO]; [main_menu setAutoenablesItems:NO];
//!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!

View File

@ -249,11 +249,13 @@ String MenuBar::bind_global_menu() {
Vector<PopupMenu *> popups = _get_popups(); Vector<PopupMenu *> popups = _get_popups();
for (int i = 0; i < menu_cache.size(); i++) { for (int i = 0; i < menu_cache.size(); i++) {
String submenu_name = popups[i]->bind_global_menu(); String submenu_name = popups[i]->bind_global_menu();
int index = ds->global_menu_add_submenu_item("_main", menu_cache[i].name, submenu_name, global_start_idx + i); if (!popups[i]->is_system_menu()) {
ds->global_menu_set_item_tag("_main", index, global_menu_name + "#" + itos(i)); int index = ds->global_menu_add_submenu_item("_main", menu_cache[i].name, submenu_name, global_start_idx + i);
ds->global_menu_set_item_hidden("_main", index, menu_cache[i].hidden); ds->global_menu_set_item_tag("_main", index, global_menu_name + "#" + itos(i));
ds->global_menu_set_item_disabled("_main", index, menu_cache[i].disabled); ds->global_menu_set_item_hidden("_main", index, menu_cache[i].hidden);
ds->global_menu_set_item_tooltip("_main", index, menu_cache[i].tooltip); ds->global_menu_set_item_disabled("_main", index, menu_cache[i].disabled);
ds->global_menu_set_item_tooltip("_main", index, menu_cache[i].tooltip);
}
} }
return global_menu_name; return global_menu_name;
@ -268,8 +270,10 @@ void MenuBar::unbind_global_menu() {
int global_start = _find_global_start_index(); int global_start = _find_global_start_index();
Vector<PopupMenu *> popups = _get_popups(); Vector<PopupMenu *> popups = _get_popups();
for (int i = menu_cache.size() - 1; i >= 0; i--) { for (int i = menu_cache.size() - 1; i >= 0; i--) {
popups[i]->unbind_global_menu(); if (!popups[i]->is_system_menu()) {
ds->global_menu_remove_item("_main", global_start + i); popups[i]->unbind_global_menu();
ds->global_menu_remove_item("_main", global_start + i);
}
} }
global_menu_name = String(); global_menu_name = String();
@ -558,8 +562,10 @@ void MenuBar::add_child_notify(Node *p_child) {
if (!global_menu_name.is_empty()) { if (!global_menu_name.is_empty()) {
String submenu_name = pm->bind_global_menu(); String submenu_name = pm->bind_global_menu();
int index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", atr(menu.name), submenu_name, _find_global_start_index() + menu_cache.size() - 1); if (!pm->is_system_menu()) {
DisplayServer::get_singleton()->global_menu_set_item_tag("_main", index, global_menu_name + "#" + itos(menu_cache.size() - 1)); int index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", atr(menu.name), submenu_name, _find_global_start_index() + menu_cache.size() - 1);
DisplayServer::get_singleton()->global_menu_set_item_tag("_main", index, global_menu_name + "#" + itos(menu_cache.size() - 1));
}
} }
update_minimum_size(); update_minimum_size();
} }
@ -587,14 +593,16 @@ void MenuBar::move_child_notify(Node *p_child) {
menu_cache.insert(new_idx, menu); menu_cache.insert(new_idx, menu);
if (!global_menu_name.is_empty()) { if (!global_menu_name.is_empty()) {
int global_start = _find_global_start_index(); if (!pm->is_system_menu()) {
if (old_idx != -1) { int global_start = _find_global_start_index();
DisplayServer::get_singleton()->global_menu_remove_item("_main", global_start + old_idx); if (old_idx != -1) {
} DisplayServer::get_singleton()->global_menu_remove_item("_main", global_start + old_idx);
if (new_idx != -1) { }
String submenu_name = pm->bind_global_menu(); if (new_idx != -1) {
int index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", atr(menu.name), submenu_name, global_start + new_idx); String submenu_name = pm->bind_global_menu();
DisplayServer::get_singleton()->global_menu_set_item_tag("_main", index, global_menu_name + "#" + itos(new_idx)); int index = DisplayServer::get_singleton()->global_menu_add_submenu_item("_main", atr(menu.name), submenu_name, global_start + new_idx);
DisplayServer::get_singleton()->global_menu_set_item_tag("_main", index, global_menu_name + "#" + itos(new_idx));
}
} }
} }
} }
@ -612,8 +620,10 @@ void MenuBar::remove_child_notify(Node *p_child) {
menu_cache.remove_at(idx); menu_cache.remove_at(idx);
if (!global_menu_name.is_empty()) { if (!global_menu_name.is_empty()) {
pm->unbind_global_menu(); if (!pm->is_system_menu()) {
DisplayServer::get_singleton()->global_menu_remove_item("_main", _find_global_start_index() + idx); pm->unbind_global_menu();
DisplayServer::get_singleton()->global_menu_remove_item("_main", _find_global_start_index() + idx);
}
} }
p_child->remove_meta("_menu_name"); p_child->remove_meta("_menu_name");

View File

@ -40,6 +40,8 @@
#include "scene/gui/menu_bar.h" #include "scene/gui/menu_bar.h"
#include "scene/theme/theme_db.h" #include "scene/theme/theme_db.h"
HashMap<String, PopupMenu *> PopupMenu::system_menus;
String PopupMenu::bind_global_menu() { String PopupMenu::bind_global_menu() {
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if (is_part_of_edited_scene()) { if (is_part_of_edited_scene()) {
@ -54,8 +56,20 @@ String PopupMenu::bind_global_menu() {
return global_menu_name; // Already bound; return global_menu_name; // Already bound;
} }
DisplayServer *ds = DisplayServer::get_singleton();
global_menu_name = "__PopupMenu#" + itos(get_instance_id()); global_menu_name = "__PopupMenu#" + itos(get_instance_id());
if (system_menu_name.length() > 0) {
if (system_menus.has(system_menu_name)) {
WARN_PRINT(vformat("Attempting to bind PopupMenu to the special menu %s, but another menu is already bound to it. This menu: %s, current menu: %s", system_menu_name, this->get_description(), system_menus[system_menu_name]->get_description()));
} else {
const Dictionary &supported_special_names = DisplayServer::get_singleton()->global_menu_get_system_menu_roots();
if (supported_special_names.has(system_menu_name)) {
system_menus[system_menu_name] = this;
global_menu_name = system_menu_name;
}
}
}
DisplayServer *ds = DisplayServer::get_singleton();
ds->global_menu_set_popup_callbacks(global_menu_name, callable_mp(this, &PopupMenu::_about_to_popup), callable_mp(this, &PopupMenu::_about_to_close)); ds->global_menu_set_popup_callbacks(global_menu_name, callable_mp(this, &PopupMenu::_about_to_popup), callable_mp(this, &PopupMenu::_about_to_close));
for (int i = 0; i < items.size(); i++) { for (int i = 0; i < items.size(); i++) {
Item &item = items.write[i]; Item &item = items.write[i];
@ -105,6 +119,10 @@ void PopupMenu::unbind_global_menu() {
return; return;
} }
if (global_menu_name == system_menu_name && system_menus[system_menu_name] == this) {
system_menus.erase(system_menu_name);
}
for (int i = 0; i < items.size(); i++) { for (int i = 0; i < items.size(); i++) {
Item &item = items.write[i]; Item &item = items.write[i];
if (!item.submenu.is_empty()) { if (!item.submenu.is_empty()) {
@ -120,6 +138,24 @@ void PopupMenu::unbind_global_menu() {
global_menu_name = String(); global_menu_name = String();
} }
bool PopupMenu::is_system_menu() const {
return (global_menu_name == system_menu_name) && (system_menu_name.length() > 0);
}
void PopupMenu::set_system_menu_root(const String &p_special) {
if (is_inside_tree() && system_menu_name.length() > 0) {
unbind_global_menu();
}
system_menu_name = p_special;
if (is_inside_tree() && system_menu_name.length() > 0) {
bind_global_menu();
}
}
String PopupMenu::get_system_menu_root() const {
return system_menu_name;
}
String PopupMenu::_get_accel_text(const Item &p_item) const { String PopupMenu::_get_accel_text(const Item &p_item) const {
if (p_item.shortcut.is_valid()) { if (p_item.shortcut.is_valid()) {
return p_item.shortcut->get_as_text(); return p_item.shortcut->get_as_text();
@ -947,6 +983,15 @@ void PopupMenu::_notification(int p_what) {
if (!is_embedded()) { if (!is_embedded()) {
set_flag(FLAG_NO_FOCUS, true); set_flag(FLAG_NO_FOCUS, true);
} }
if (system_menu_name.length() > 0) {
bind_global_menu();
}
} break;
case NOTIFICATION_EXIT_TREE: {
if (system_menu_name.length() > 0) {
unbind_global_menu();
}
} break; } break;
case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_THEME_CHANGED:
@ -2716,11 +2761,16 @@ void PopupMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_allow_search", "allow"), &PopupMenu::set_allow_search); ClassDB::bind_method(D_METHOD("set_allow_search", "allow"), &PopupMenu::set_allow_search);
ClassDB::bind_method(D_METHOD("get_allow_search"), &PopupMenu::get_allow_search); ClassDB::bind_method(D_METHOD("get_allow_search"), &PopupMenu::get_allow_search);
ClassDB::bind_method(D_METHOD("is_system_menu"), &PopupMenu::is_system_menu);
ClassDB::bind_method(D_METHOD("set_system_menu_root", "special"), &PopupMenu::set_system_menu_root);
ClassDB::bind_method(D_METHOD("get_system_menu_root"), &PopupMenu::get_system_menu_root);
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_item_selection"), "set_hide_on_item_selection", "is_hide_on_item_selection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_item_selection"), "set_hide_on_item_selection", "is_hide_on_item_selection");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_checkable_item_selection"), "set_hide_on_checkable_item_selection", "is_hide_on_checkable_item_selection");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_on_state_item_selection"), "set_hide_on_state_item_selection", "is_hide_on_state_item_selection");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "submenu_popup_delay", PROPERTY_HINT_NONE, "suffix:s"), "set_submenu_popup_delay", "get_submenu_popup_delay"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "submenu_popup_delay", PROPERTY_HINT_NONE, "suffix:s"), "set_submenu_popup_delay", "get_submenu_popup_delay");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_search"), "set_allow_search", "get_allow_search"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_search"), "set_allow_search", "get_allow_search");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "system_menu_root", PROPERTY_HINT_ENUM, "Dock (macOS):_dock,Apple Menu(macOS):_apple,Window Menu(macOS):_window,Help Menu(macOS):_help"), "set_system_menu_root", "get_system_menu_root");
ADD_ARRAY_COUNT("Items", "item_count", "set_item_count", "get_item_count", "item_"); ADD_ARRAY_COUNT("Items", "item_count", "set_item_count", "get_item_count", "item_");

View File

@ -40,6 +40,8 @@
class PopupMenu : public Popup { class PopupMenu : public Popup {
GDCLASS(PopupMenu, Popup); GDCLASS(PopupMenu, Popup);
static HashMap<String, PopupMenu *> system_menus;
struct Item { struct Item {
Ref<Texture2D> icon; Ref<Texture2D> icon;
int icon_max_width = 0; int icon_max_width = 0;
@ -90,6 +92,7 @@ class PopupMenu : public Popup {
}; };
String global_menu_name; String global_menu_name;
String system_menu_name;
bool close_allowed = false; bool close_allowed = false;
bool activated_by_keyboard = false; bool activated_by_keyboard = false;
@ -218,6 +221,9 @@ public:
String bind_global_menu(); String bind_global_menu();
void unbind_global_menu(); void unbind_global_menu();
bool is_system_menu() const;
void set_system_menu_root(const String &p_special);
String get_system_menu_root() const;
void add_item(const String &p_label, int p_id = -1, Key p_accel = Key::NONE); void add_item(const String &p_label, int p_id = -1, Key p_accel = Key::NONE);
void add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id = -1, Key p_accel = Key::NONE); void add_icon_item(const Ref<Texture2D> &p_icon, const String &p_label, int p_id = -1, Key p_accel = Key::NONE);

View File

@ -267,6 +267,11 @@ void DisplayServer::global_menu_clear(const String &p_menu_root) {
WARN_PRINT("Global menus not supported by this display server."); WARN_PRINT("Global menus not supported by this display server.");
} }
Dictionary DisplayServer::global_menu_get_system_menu_roots() const {
WARN_PRINT("Global menus not supported by this display server.");
return Dictionary();
}
bool DisplayServer::tts_is_speaking() const { bool DisplayServer::tts_is_speaking() const {
WARN_PRINT("TTS is not supported by this display server."); WARN_PRINT("TTS is not supported by this display server.");
return false; return false;
@ -652,6 +657,8 @@ void DisplayServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("global_menu_remove_item", "menu_root", "idx"), &DisplayServer::global_menu_remove_item); ClassDB::bind_method(D_METHOD("global_menu_remove_item", "menu_root", "idx"), &DisplayServer::global_menu_remove_item);
ClassDB::bind_method(D_METHOD("global_menu_clear", "menu_root"), &DisplayServer::global_menu_clear); ClassDB::bind_method(D_METHOD("global_menu_clear", "menu_root"), &DisplayServer::global_menu_clear);
ClassDB::bind_method(D_METHOD("global_menu_get_system_menu_roots"), &DisplayServer::global_menu_get_system_menu_roots);
ClassDB::bind_method(D_METHOD("tts_is_speaking"), &DisplayServer::tts_is_speaking); ClassDB::bind_method(D_METHOD("tts_is_speaking"), &DisplayServer::tts_is_speaking);
ClassDB::bind_method(D_METHOD("tts_is_paused"), &DisplayServer::tts_is_paused); ClassDB::bind_method(D_METHOD("tts_is_paused"), &DisplayServer::tts_is_paused);
ClassDB::bind_method(D_METHOD("tts_get_voices"), &DisplayServer::tts_get_voices); ClassDB::bind_method(D_METHOD("tts_get_voices"), &DisplayServer::tts_get_voices);

View File

@ -185,6 +185,8 @@ public:
virtual void global_menu_remove_item(const String &p_menu_root, int p_idx); virtual void global_menu_remove_item(const String &p_menu_root, int p_idx);
virtual void global_menu_clear(const String &p_menu_root); virtual void global_menu_clear(const String &p_menu_root);
virtual Dictionary global_menu_get_system_menu_roots() const;
struct TTSUtterance { struct TTSUtterance {
String text; String text;
String voice; String voice;