[macOS] Add native "Edit" menu.

This commit is contained in:
bruvzg 2024-09-30 12:19:48 +03:00
parent e3213aaef5
commit 0fa669c097
No known key found for this signature in database
GPG Key ID: 7960FCF39844EC38
12 changed files with 308 additions and 12 deletions

View File

@ -401,6 +401,14 @@
[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="get_system_menu_no_default_items" qualifiers="const">
<return type="bool" />
<param index="0" name="menu_id" type="int" enum="NativeMenu.SystemMenus" />
<description>
Returns [code]true[/code] if system menu has no default items.
[b]Note:[/b] This method is implemented only on macOS.
</description>
</method>
<method name="has_feature" qualifiers="const"> <method name="has_feature" qualifiers="const">
<return type="bool" /> <return type="bool" />
<param index="0" name="feature" type="int" enum="NativeMenu.Feature" /> <param index="0" name="feature" type="int" enum="NativeMenu.Feature" />
@ -720,6 +728,25 @@
[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="set_system_menu_hidden">
<return type="void" />
<param index="0" name="menu_id" type="int" enum="NativeMenu.SystemMenus" />
<param index="1" name="hidden" type="bool" />
<description>
Hides/shows the system menu. Only system menus with no default items can be hidden. When it is hidden, an item does not appear in a menu and its action cannot be invoked.
[b]Note:[/b] This method is implemented only on macOS.
</description>
</method>
<method name="set_system_menu_name">
<return type="void" />
<param index="0" name="menu_id" type="int" enum="NativeMenu.SystemMenus" />
<param index="1" name="string" type="String" />
<description>
Sets system menu name. If set to empty string, default menu name is restored.
[b]Note:[/b] On macOS, only [constant FILE_MENU_ID] can be renamed.
[b]Note:[/b] This method is implemented only on macOS.
</description>
</method>
</methods> </methods>
<constants> <constants>
<constant name="FEATURE_GLOBAL_MENU" value="0" enum="Feature"> <constant name="FEATURE_GLOBAL_MENU" value="0" enum="Feature">
@ -755,5 +782,11 @@
<constant name="DOCK_MENU_ID" value="5" enum="SystemMenus"> <constant name="DOCK_MENU_ID" value="5" enum="SystemMenus">
Dock icon right-click menu ID (on macOS this menu include standard application control items and a list of open windows). Dock icon right-click menu ID (on macOS this menu include standard application control items and a list of open windows).
</constant> </constant>
<constant name="EDIT_MENU_ID" value="6" enum="SystemMenus">
"Edit" menu ID (on macOS this menu includes "Cut", "Copy", and "Paste" items).
</constant>
<constant name="FILE_MENU_ID" value="7" enum="SystemMenus">
"File" menu ID (on macOS this menu is empty and is hidden by default, this menu is shown before "Edit" menu).
</constant>
</constants> </constants>
</class> </class>

View File

@ -7168,6 +7168,9 @@ EditorNode::EditorNode() {
file_menu = memnew(PopupMenu); file_menu = memnew(PopupMenu);
file_menu->set_name(TTR("Scene")); file_menu->set_name(TTR("Scene"));
if (global_menu && NativeMenu::get_singleton()->has_system_menu(NativeMenu::FILE_MENU_ID)) {
file_menu->set_system_menu(NativeMenu::FILE_MENU_ID);
}
main_menu->add_child(file_menu); main_menu->add_child(file_menu);
main_menu->set_menu_tooltip(0, TTR("Operations with scene files.")); main_menu->set_menu_tooltip(0, TTR("Operations with scene files."));

View File

@ -217,6 +217,8 @@ private:
WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect); WindowID _create_window(WindowMode p_mode, VSyncMode p_vsync_mode, const Rect2i &p_rect);
void _update_window_style(WindowData p_wd); void _update_window_style(WindowData p_wd);
void _get_action_key(const StringName &p_name, String &r_keycode, unsigned int &r_keymask) const;
void _update_displays_arrangement(); void _update_displays_arrangement();
Point2i _get_native_screen_position(int p_screen) const; Point2i _get_native_screen_position(int p_screen) const;
static void _displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info); static void _displays_arrangement_changed(CGDirectDisplayID display_id, CGDisplayChangeSummaryFlags flags, void *user_info);

View File

@ -43,6 +43,7 @@
#include "tts_macos.h" #include "tts_macos.h"
#include "core/config/project_settings.h" #include "core/config/project_settings.h"
#include "core/input/input_map.h"
#include "core/io/marshalls.h" #include "core/io/marshalls.h"
#include "core/math/geometry_2d.h" #include "core/math/geometry_2d.h"
#include "core/os/keyboard.h" #include "core/os/keyboard.h"
@ -3471,6 +3472,34 @@ bool DisplayServerMacOS::mouse_process_popups(bool p_close) {
return closed; return closed;
} }
void DisplayServerMacOS::_get_action_key(const StringName &p_name, String &r_keycode, unsigned int &r_keymask) const {
r_keycode = String();
r_keymask = 0;
const List<Ref<InputEvent>> *events = InputMap::get_singleton()->action_get_events(p_name);
if (!events) {
return;
}
const List<Ref<InputEvent>>::Element *first_event = events->front();
if (!first_event) {
return;
}
const Ref<InputEventKey> event = first_event->get();
if (event.is_null()) {
return;
}
if (event->get_keycode() != Key::NONE) {
r_keycode = KeyMappingMacOS::keycode_get_native_string(event->get_keycode() & KeyModifierMask::CODE_MASK);
r_keymask = KeyMappingMacOS::keycode_get_native_mask(event->get_keycode_with_modifiers());
} else if (event->get_physical_keycode() != Key::NONE) {
r_keycode = KeyMappingMacOS::keycode_get_native_string(event->get_physical_keycode() & KeyModifierMask::CODE_MASK);
r_keymask = KeyMappingMacOS::keycode_get_native_mask(event->get_physical_keycode_with_modifiers());
} else if (event->get_key_label() != Key::NONE) {
r_keycode = KeyMappingMacOS::keycode_get_native_string(event->get_key_label() & KeyModifierMask::CODE_MASK);
r_keymask = KeyMappingMacOS::keycode_get_native_mask(event->get_key_label_with_modifiers());
}
}
DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) { DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Context p_context, Error &r_error) {
KeyMappingMacOS::initialize(); KeyMappingMacOS::initialize();
@ -3558,6 +3587,35 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname]; title = [NSString stringWithFormat:NSLocalizedString(@"Quit %@", nil), nsappname];
[application_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; [application_menu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
NSMenu *file_menu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"File", nil)];
menu_item = [file_menu addItemWithTitle:@"_start_" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
menu_item.tag = MENU_TAG_START;
menu_item = [file_menu addItemWithTitle:@"_end_" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
menu_item.tag = MENU_TAG_END;
NSMenu *edit_menu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Edit", nil)];
String keycode;
unsigned int keymask = 0;
_get_action_key("ui_cut", keycode, keymask);
menu_item = [edit_menu addItemWithTitle:NSLocalizedString(@"Cut", nil) action:@selector(cut:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
[menu_item setKeyEquivalentModifierMask:keymask];
_get_action_key("ui_copy", keycode, keymask);
menu_item = [edit_menu addItemWithTitle:NSLocalizedString(@"Copy", nil) action:@selector(copy:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
[menu_item setKeyEquivalentModifierMask:keymask];
_get_action_key("ui_paste", keycode, keymask);
menu_item = [edit_menu addItemWithTitle:NSLocalizedString(@"Paste", nil) action:@selector(paste:) keyEquivalent:[NSString stringWithUTF8String:keycode.utf8().get_data()]];
[menu_item setKeyEquivalentModifierMask:keymask];
[edit_menu addItem:[NSMenuItem separatorItem]];
menu_item = [edit_menu addItemWithTitle:@"_start_" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
menu_item.tag = MENU_TAG_START;
menu_item = [edit_menu addItemWithTitle:@"_end_" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
menu_item.tag = MENU_TAG_END;
NSMenu *window_menu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Window", nil)]; NSMenu *window_menu = [[NSMenu alloc] initWithTitle:NSLocalizedString(@"Window", nil)];
[window_menu addItemWithTitle:NSLocalizedString(@"Minimize", nil) action:@selector(performMiniaturize:) keyEquivalent:@"m"]; [window_menu addItemWithTitle:NSLocalizedString(@"Minimize", nil) action:@selector(performMiniaturize:) keyEquivalent:@"m"];
[window_menu addItemWithTitle:NSLocalizedString(@"Zoom", nil) action:@selector(performZoom:) keyEquivalent:@""]; [window_menu addItemWithTitle:NSLocalizedString(@"Zoom", nil) action:@selector(performZoom:) keyEquivalent:@""];
@ -3587,6 +3645,13 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""]; menu_item = [main_menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
[main_menu setSubmenu:application_menu forItem:menu_item]; [main_menu setSubmenu:application_menu forItem:menu_item];
NSMenuItem *file_menu_item = [main_menu addItemWithTitle:NSLocalizedString(@"File", nil) action:nil keyEquivalent:@""];
file_menu_item.hidden = YES;
[main_menu setSubmenu:file_menu forItem:file_menu_item];
menu_item = [main_menu addItemWithTitle:NSLocalizedString(@"Edit", nil) action:nil keyEquivalent:@""];
[main_menu setSubmenu:edit_menu forItem:menu_item];
menu_item = [main_menu addItemWithTitle:NSLocalizedString(@"Window", nil) action:nil keyEquivalent:@""]; menu_item = [main_menu addItemWithTitle:NSLocalizedString(@"Window", nil) action:nil keyEquivalent:@""];
[main_menu setSubmenu:window_menu forItem:menu_item]; [main_menu setSubmenu:window_menu forItem:menu_item];
@ -3595,7 +3660,7 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
[main_menu setAutoenablesItems:NO]; [main_menu setAutoenablesItems:NO];
native_menu->_register_system_menus(main_menu, application_menu, window_menu, help_menu, dock_menu); native_menu->_register_system_menus(main_menu, application_menu, window_menu, help_menu, dock_menu, edit_menu, file_menu, file_menu_item);
//!!!!!!!!!!!!!!!!!!!!!!!!!! //!!!!!!!!!!!!!!!!!!!!!!!!!!
//TODO - do Vulkan and OpenGL support checks, driver selection and fallback //TODO - do Vulkan and OpenGL support checks, driver selection and fallback

View File

@ -76,6 +76,7 @@
- (void)setWindowID:(DisplayServer::WindowID)wid; - (void)setWindowID:(DisplayServer::WindowID)wid;
- (void)updateLayerDelegate; - (void)updateLayerDelegate;
- (void)cancelComposition; - (void)cancelComposition;
- (void)processUIEvent:(const StringName &)name;
@end @end

View File

@ -33,6 +33,7 @@
#include "display_server_macos.h" #include "display_server_macos.h"
#include "key_mapping_macos.h" #include "key_mapping_macos.h"
#include "core/input/input_map.h"
#include "main/main.h" #include "main/main.h"
@implementation GodotContentLayerDelegate @implementation GodotContentLayerDelegate
@ -337,6 +338,65 @@
return NO; return NO;
} }
// MARK: Edit menu actions
- (void)processUIEvent:(const StringName &)name {
DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
if (!ds || !ds->has_window(window_id)) {
return;
}
const List<Ref<InputEvent>> *events = InputMap::get_singleton()->action_get_events(name);
if (!events) {
return;
}
const List<Ref<InputEvent>>::Element *first_event = events->front();
if (!first_event) {
return;
}
const Ref<InputEventKey> event = first_event->get();
if (event.is_null()) {
return;
}
DisplayServerMacOS::KeyEvent ke;
ke.window_id = window_id;
ke.macos_state = 0;
if (event->is_ctrl_pressed()) {
ke.macos_state |= NSEventModifierFlagControl;
}
if (event->is_shift_pressed()) {
ke.macos_state |= NSEventModifierFlagShift;
}
if (event->is_alt_pressed()) {
ke.macos_state |= NSEventModifierFlagOption;
}
if (event->is_meta_pressed()) {
ke.macos_state |= NSEventModifierFlagCommand;
}
ke.pressed = true;
ke.echo = false;
ke.raw = false;
ke.keycode = event->get_keycode();
ke.physical_keycode = event->get_physical_keycode();
ke.key_label = event->get_key_label();
ke.unicode = event->get_unicode();
ds->push_to_key_event_buffer(ke);
}
- (void)copy:(id)sender {
[self processUIEvent:"ui_copy"];
}
- (void)cut:(id)sender {
[self processUIEvent:"ui_cut"];
}
- (void)paste:(id)sender {
[self processUIEvent:"ui_paste"];
}
// MARK: Focus // MARK: Focus
- (BOOL)canBecomeKeyView { - (BOOL)canBecomeKeyView {

View File

@ -102,9 +102,13 @@
} else { } else {
// Otherwise redirect event to the engine. // Otherwise redirect event to the engine.
if (DisplayServer::get_singleton()) { if (DisplayServer::get_singleton()) {
if ([[NSApplication sharedApplication] keyWindow].sheet) {
[[[[NSApplication sharedApplication] keyWindow] sheetParent] sendEvent:event];
} else {
[[[NSApplication sharedApplication] keyWindow] sendEvent:event]; [[[NSApplication sharedApplication] keyWindow] sendEvent:event];
} }
} }
}
// Suppress default menu action. // Suppress default menu action.
*target = self; *target = self;

View File

@ -58,12 +58,18 @@ class NativeMenuMacOS : public NativeMenu {
NSMenu *window_menu_ns = nullptr; NSMenu *window_menu_ns = nullptr;
NSMenu *help_menu_ns = nullptr; NSMenu *help_menu_ns = nullptr;
NSMenu *dock_menu_ns = nullptr; NSMenu *dock_menu_ns = nullptr;
NSMenu *edit_menu_ns = nullptr;
NSMenu *file_menu_ns = nullptr;
NSMenuItem *file_menu_item = nullptr;
RID main_menu; RID main_menu;
RID application_menu; RID application_menu;
RID window_menu; RID window_menu;
RID help_menu; RID help_menu;
RID dock_menu; RID dock_menu;
RID edit_menu;
RID file_menu;
int _get_system_menu_start(const NSMenu *p_menu) const; int _get_system_menu_start(const NSMenu *p_menu) const;
int _get_system_menu_count(const NSMenu *p_menu) const; int _get_system_menu_count(const NSMenu *p_menu) const;
@ -71,7 +77,7 @@ class NativeMenuMacOS : public NativeMenu {
NSMenuItem *_menu_add_item(NSMenu *p_menu, const String &p_label, Key p_accel, int p_index, int *r_out); NSMenuItem *_menu_add_item(NSMenu *p_menu, const String &p_label, Key p_accel, int p_index, int *r_out);
public: public:
void _register_system_menus(NSMenu *p_main_menu, NSMenu *p_application_menu, NSMenu *p_window_menu, NSMenu *p_help_menu, NSMenu *p_dock_menu); void _register_system_menus(NSMenu *p_main_menu, NSMenu *p_application_menu, NSMenu *p_window_menu, NSMenu *p_help_menu, NSMenu *p_dock_menu, NSMenu *p_edit_menu, NSMenu *p_file_menu, NSMenuItem *p_file_menu_item);
NSMenu *_get_dock_menu(); NSMenu *_get_dock_menu();
void _menu_need_update(NSMenu *p_menu); void _menu_need_update(NSMenu *p_menu);
@ -84,6 +90,10 @@ public:
virtual bool has_system_menu(SystemMenus p_menu_id) const override; virtual bool has_system_menu(SystemMenus p_menu_id) const override;
virtual RID get_system_menu(SystemMenus p_menu_id) const override; virtual RID get_system_menu(SystemMenus p_menu_id) const override;
virtual bool get_system_menu_no_default_items(SystemMenus p_menu_id) const override;
virtual void set_system_menu_name(SystemMenus p_menu_id, const String &p_string) override;
virtual void set_system_menu_hidden(SystemMenus p_menu_id, bool p_hidden) override;
virtual RID create_menu() override; virtual RID create_menu() override;
virtual bool has_menu(const RID &p_rid) const override; virtual bool has_menu(const RID &p_rid) const override;
virtual void free_menu(const RID &p_rid) override; virtual void free_menu(const RID &p_rid) override;

View File

@ -36,7 +36,7 @@
#include "scene/resources/image_texture.h" #include "scene/resources/image_texture.h"
void NativeMenuMacOS::_register_system_menus(NSMenu *p_main_menu, NSMenu *p_application_menu, NSMenu *p_window_menu, NSMenu *p_help_menu, NSMenu *p_dock_menu) { void NativeMenuMacOS::_register_system_menus(NSMenu *p_main_menu, NSMenu *p_application_menu, NSMenu *p_window_menu, NSMenu *p_help_menu, NSMenu *p_dock_menu, NSMenu *p_edit_menu, NSMenu *p_file_menu, NSMenuItem *p_file_menu_item) {
{ {
MenuData *md = memnew(MenuData); MenuData *md = memnew(MenuData);
md->menu = p_main_menu; md->menu = p_main_menu;
@ -45,6 +45,24 @@ void NativeMenuMacOS::_register_system_menus(NSMenu *p_main_menu, NSMenu *p_appl
main_menu_ns = p_main_menu; main_menu_ns = p_main_menu;
menu_lookup[md->menu] = main_menu; menu_lookup[md->menu] = main_menu;
} }
{
MenuData *md = memnew(MenuData);
md->menu = p_file_menu;
md->is_system = true;
file_menu = menus.make_rid(md);
file_menu_ns = p_file_menu;
menu_lookup[md->menu] = file_menu;
file_menu_item = p_file_menu_item;
}
{
MenuData *md = memnew(MenuData);
md->menu = p_edit_menu;
md->is_system = true;
edit_menu = menus.make_rid(md);
edit_menu_ns = p_edit_menu;
menu_lookup[md->menu] = edit_menu;
}
{ {
MenuData *md = memnew(MenuData); MenuData *md = memnew(MenuData);
md->menu = p_application_menu; md->menu = p_application_menu;
@ -160,10 +178,10 @@ bool NativeMenuMacOS::_is_menu_opened(NSMenu *p_menu) const {
} }
int NativeMenuMacOS::_get_system_menu_start(const NSMenu *p_menu) const { int NativeMenuMacOS::_get_system_menu_start(const NSMenu *p_menu) const {
if (p_menu == [NSApp mainMenu]) { // Skip Apple menu. if (p_menu == [NSApp mainMenu]) { // Skip Apple, File and Edit menu.
return 1; return 3;
} }
if (p_menu == application_menu_ns || p_menu == window_menu_ns || p_menu == help_menu_ns) { if (p_menu == application_menu_ns || p_menu == window_menu_ns || p_menu == help_menu_ns || p_menu == edit_menu_ns || p_menu == file_menu_ns) {
int count = [p_menu numberOfItems]; int count = [p_menu numberOfItems];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
NSMenuItem *menu_item = [p_menu itemAtIndex:i]; NSMenuItem *menu_item = [p_menu itemAtIndex:i];
@ -176,10 +194,10 @@ int NativeMenuMacOS::_get_system_menu_start(const NSMenu *p_menu) const {
} }
int NativeMenuMacOS::_get_system_menu_count(const NSMenu *p_menu) const { int NativeMenuMacOS::_get_system_menu_count(const NSMenu *p_menu) const {
if (p_menu == [NSApp mainMenu]) { // Skip Apple, Window and Help menu. if (p_menu == [NSApp mainMenu]) { // Skip Apple, File, Edit, Window and Help menu.
return [p_menu numberOfItems] - 3; return [p_menu numberOfItems] - 5;
} }
if (p_menu == application_menu_ns || p_menu == window_menu_ns || p_menu == help_menu_ns) { if (p_menu == application_menu_ns || p_menu == window_menu_ns || p_menu == help_menu_ns || p_menu == edit_menu_ns || p_menu == file_menu_ns) {
int start = 0; int start = 0;
int count = [p_menu numberOfItems]; int count = [p_menu numberOfItems];
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
@ -215,6 +233,8 @@ bool NativeMenuMacOS::has_system_menu(SystemMenus p_menu_id) const {
case WINDOW_MENU_ID: case WINDOW_MENU_ID:
case HELP_MENU_ID: case HELP_MENU_ID:
case DOCK_MENU_ID: case DOCK_MENU_ID:
case EDIT_MENU_ID:
case FILE_MENU_ID:
return true; return true;
default: default:
return false; return false;
@ -233,11 +253,37 @@ RID NativeMenuMacOS::get_system_menu(SystemMenus p_menu_id) const {
return help_menu; return help_menu;
case DOCK_MENU_ID: case DOCK_MENU_ID:
return dock_menu; return dock_menu;
case EDIT_MENU_ID:
return edit_menu;
case FILE_MENU_ID:
return file_menu;
default: default:
return RID(); return RID();
} }
} }
bool NativeMenuMacOS::get_system_menu_no_default_items(SystemMenus p_menu_id) const {
return p_menu_id == FILE_MENU_ID;
}
void NativeMenuMacOS::set_system_menu_name(SystemMenus p_menu_id, const String &p_string) {
if (p_menu_id == FILE_MENU_ID) {
if (p_string.is_empty()) {
[file_menu_item setTitle:NSLocalizedString(@"File", nil)];
[file_menu_ns setTitle:NSLocalizedString(@"File", nil)];
} else {
[file_menu_item setTitle:[NSString stringWithUTF8String:p_string.utf8().get_data()]];
[file_menu_ns setTitle:[NSString stringWithUTF8String:p_string.utf8().get_data()]];
}
}
}
void NativeMenuMacOS::set_system_menu_hidden(SystemMenus p_menu_id, bool p_hidden) {
if (p_menu_id == FILE_MENU_ID) {
file_menu_item.hidden = p_hidden;
}
}
RID NativeMenuMacOS::create_menu() { RID NativeMenuMacOS::create_menu() {
MenuData *md = memnew(MenuData); MenuData *md = memnew(MenuData);
md->menu = [[NSMenu alloc] initWithTitle:@""]; md->menu = [[NSMenu alloc] initWithTitle:@""];
@ -1291,7 +1337,7 @@ void NativeMenuMacOS::clear(const RID &p_rid) {
ERR_FAIL_NULL(md); ERR_FAIL_NULL(md);
ERR_FAIL_COND_MSG(_is_menu_opened(md->menu), "Can't remove open menu!"); ERR_FAIL_COND_MSG(_is_menu_opened(md->menu), "Can't remove open menu!");
if (p_rid == application_menu || p_rid == window_menu || p_rid == help_menu) { if (p_rid == application_menu || p_rid == window_menu || p_rid == help_menu || p_rid == edit_menu || p_rid == file_menu) {
int start = _get_system_menu_start(md->menu); int start = _get_system_menu_start(md->menu);
int count = _get_system_menu_count(md->menu); int count = _get_system_menu_count(md->menu);
for (int i = start + count - 1; i >= start; i--) { for (int i = start + count - 1; i >= start; i--) {
@ -1302,12 +1348,24 @@ void NativeMenuMacOS::clear(const RID &p_rid) {
} }
if (p_rid == main_menu) { if (p_rid == main_menu) {
// Restore Apple, Window and Help menu. // Restore Apple, File, Edit, Window and Help menu.
MenuData *md_app = menus.get_or_null(application_menu); MenuData *md_app = menus.get_or_null(application_menu);
if (md_app) { if (md_app) {
NSMenuItem *menu_item = [md->menu addItemWithTitle:@"" action:nil keyEquivalent:@""]; NSMenuItem *menu_item = [md->menu addItemWithTitle:@"" action:nil keyEquivalent:@""];
[md->menu setSubmenu:md_app->menu forItem:menu_item]; [md->menu setSubmenu:md_app->menu forItem:menu_item];
} }
MenuData *md_file = menus.get_or_null(file_menu);
if (md_file) {
NSMenuItem *menu_item = [md->menu addItemWithTitle:@"File" action:nil keyEquivalent:@""];
menu_item.hidden = YES;
[md->menu setSubmenu:md_file->menu forItem:menu_item];
file_menu_item = menu_item;
}
MenuData *md_edit = menus.get_or_null(edit_menu);
if (md_edit) {
NSMenuItem *menu_item = [md->menu addItemWithTitle:@"Edit" action:nil keyEquivalent:@""];
[md->menu setSubmenu:md_edit->menu forItem:menu_item];
}
MenuData *md_win = menus.get_or_null(window_menu); MenuData *md_win = menus.get_or_null(window_menu);
if (md_win) { if (md_win) {
NSMenuItem *menu_item = [md->menu addItemWithTitle:@"Window" action:nil keyEquivalent:@""]; NSMenuItem *menu_item = [md->menu addItemWithTitle:@"Window" action:nil keyEquivalent:@""];
@ -1346,6 +1404,28 @@ NativeMenuMacOS::~NativeMenuMacOS() {
memdelete(md); memdelete(md);
} }
} }
if (file_menu.is_valid()) {
MenuData *md = menus.get_or_null(file_menu);
if (md) {
clear(file_menu);
menus.free(file_menu);
menu_lookup.erase(md->menu);
md->menu = nullptr;
file_menu_ns = nullptr;
memdelete(md);
}
}
if (edit_menu.is_valid()) {
MenuData *md = menus.get_or_null(edit_menu);
if (md) {
clear(edit_menu);
menus.free(edit_menu);
menu_lookup.erase(md->menu);
md->menu = nullptr;
edit_menu_ns = nullptr;
memdelete(md);
}
}
if (window_menu.is_valid()) { if (window_menu.is_valid()) {
MenuData *md = menus.get_or_null(window_menu); MenuData *md = menus.get_or_null(window_menu);
if (md) { if (md) {

View File

@ -99,6 +99,10 @@ RID PopupMenu::bind_global_menu() {
} else { } else {
system_menus[system_menu_id] = this; system_menus[system_menu_id] = this;
system_menu = nmenu->get_system_menu(system_menu_id); system_menu = nmenu->get_system_menu(system_menu_id);
nmenu->set_system_menu_name(system_menu_id, get_name());
if (nmenu->get_system_menu_no_default_items(system_menu_id)) {
nmenu->set_system_menu_hidden(system_menu_id, false);
}
global_menu = system_menu; global_menu = system_menu;
} }
} else { } else {
@ -154,6 +158,12 @@ void PopupMenu::unbind_global_menu() {
if (global_menu == system_menu && system_menus[system_menu_id] == this) { if (global_menu == system_menu && system_menus[system_menu_id] == this) {
system_menus.erase(system_menu_id); system_menus.erase(system_menu_id);
NativeMenu *nmenu = NativeMenu::get_singleton();
nmenu->set_system_menu_name(system_menu_id, String());
if (nmenu->get_system_menu_no_default_items(system_menu_id)) {
nmenu->set_system_menu_hidden(system_menu_id, true);
}
} }
for (int i = 0; i < items.size(); i++) { for (int i = 0; i < items.size(); i++) {

View File

@ -41,6 +41,10 @@ void NativeMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_system_menu", "menu_id"), &NativeMenu::get_system_menu); ClassDB::bind_method(D_METHOD("get_system_menu", "menu_id"), &NativeMenu::get_system_menu);
ClassDB::bind_method(D_METHOD("get_system_menu_name", "menu_id"), &NativeMenu::get_system_menu_name); ClassDB::bind_method(D_METHOD("get_system_menu_name", "menu_id"), &NativeMenu::get_system_menu_name);
ClassDB::bind_method(D_METHOD("get_system_menu_no_default_items", "menu_id"), &NativeMenu::get_system_menu_no_default_items);
ClassDB::bind_method(D_METHOD("set_system_menu_name", "menu_id", "string"), &NativeMenu::set_system_menu_name);
ClassDB::bind_method(D_METHOD("set_system_menu_hidden", "menu_id", "hidden"), &NativeMenu::set_system_menu_hidden);
ClassDB::bind_method(D_METHOD("create_menu"), &NativeMenu::create_menu); ClassDB::bind_method(D_METHOD("create_menu"), &NativeMenu::create_menu);
ClassDB::bind_method(D_METHOD("has_menu", "rid"), &NativeMenu::has_menu); ClassDB::bind_method(D_METHOD("has_menu", "rid"), &NativeMenu::has_menu);
ClassDB::bind_method(D_METHOD("free_menu", "rid"), &NativeMenu::free_menu); ClassDB::bind_method(D_METHOD("free_menu", "rid"), &NativeMenu::free_menu);
@ -125,6 +129,8 @@ void NativeMenu::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_MENU_ID); BIND_ENUM_CONSTANT(WINDOW_MENU_ID);
BIND_ENUM_CONSTANT(HELP_MENU_ID); BIND_ENUM_CONSTANT(HELP_MENU_ID);
BIND_ENUM_CONSTANT(DOCK_MENU_ID); BIND_ENUM_CONSTANT(DOCK_MENU_ID);
BIND_ENUM_CONSTANT(EDIT_MENU_ID);
BIND_ENUM_CONSTANT(FILE_MENU_ID);
} }
bool NativeMenu::has_feature(Feature p_feature) const { bool NativeMenu::has_feature(Feature p_feature) const {
@ -152,11 +158,27 @@ String NativeMenu::get_system_menu_name(SystemMenus p_menu_id) const {
return "Help menu"; return "Help menu";
case DOCK_MENU_ID: case DOCK_MENU_ID:
return "Dock menu"; return "Dock menu";
case EDIT_MENU_ID:
return "Edit menu";
case FILE_MENU_ID:
return "File menu";
default: default:
return "Invalid"; return "Invalid";
} }
} }
bool NativeMenu::get_system_menu_no_default_items(SystemMenus p_menu_id) const {
return false;
}
void NativeMenu::set_system_menu_name(SystemMenus p_menu_id, const String &p_string) {
WARN_PRINT("Global menus are not supported on this platform.");
}
void NativeMenu::set_system_menu_hidden(SystemMenus p_menu_id, bool p_hidden) {
WARN_PRINT("Global menus are not supported on this platform.");
}
RID NativeMenu::create_menu() { RID NativeMenu::create_menu() {
WARN_PRINT("Global menus are not supported on this platform."); WARN_PRINT("Global menus are not supported on this platform.");
return RID(); return RID();

View File

@ -66,6 +66,8 @@ public:
WINDOW_MENU_ID, WINDOW_MENU_ID,
HELP_MENU_ID, HELP_MENU_ID,
DOCK_MENU_ID, DOCK_MENU_ID,
EDIT_MENU_ID,
FILE_MENU_ID,
}; };
virtual bool has_feature(Feature p_feature) const; virtual bool has_feature(Feature p_feature) const;
@ -74,6 +76,10 @@ public:
virtual RID get_system_menu(SystemMenus p_menu_id) const; virtual RID get_system_menu(SystemMenus p_menu_id) const;
virtual String get_system_menu_name(SystemMenus p_menu_id) const; virtual String get_system_menu_name(SystemMenus p_menu_id) const;
virtual bool get_system_menu_no_default_items(SystemMenus p_menu_id) const;
virtual void set_system_menu_name(SystemMenus p_menu_id, const String &p_string);
virtual void set_system_menu_hidden(SystemMenus p_menu_id, bool p_hidden);
virtual RID create_menu(); virtual RID create_menu();
virtual bool has_menu(const RID &p_rid) const; virtual bool has_menu(const RID &p_rid) const;
virtual void free_menu(const RID &p_rid); virtual void free_menu(const RID &p_rid);