summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbruvzg <7645683+bruvzg@users.noreply.github.com>2019-02-06 15:57:06 +0200
committerbruvzg <7645683+bruvzg@users.noreply.github.com>2019-08-26 16:45:49 +0300
commitdb6d4352ea528e925c69ee94f6fb9bc0942719ec (patch)
tree864bb7a3b90ea000ec0b1881f670f4596133aadd
parent4b53fdb25d545b0a2fc73f6a46775ced586994b7 (diff)
[macOS] Add methods to modify global and dock menus. Add ability to open multiple editor/project manager instances, recent/favourite project list to project manager dock menu and opened scene list to editor dock menu.
-rw-r--r--core/bind/core_bind.cpp30
-rw-r--r--core/bind/core_bind.h5
-rw-r--r--core/os/main_loop.cpp8
-rw-r--r--core/os/main_loop.h1
-rw-r--r--core/os/os.h5
-rw-r--r--doc/classes/MainLoop.xml10
-rw-r--r--doc/classes/OS.xml44
-rw-r--r--doc/classes/SceneTree.xml9
-rw-r--r--editor/editor_node.cpp26
-rw-r--r--editor/editor_node.h4
-rw-r--r--editor/project_manager.cpp35
-rw-r--r--editor/project_manager.h2
-rw-r--r--platform/osx/os_osx.h25
-rw-r--r--platform/osx/os_osx.mm94
-rw-r--r--scene/main/scene_tree.cpp7
-rw-r--r--scene/main/scene_tree.h1
16 files changed, 305 insertions, 1 deletions
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 8e0d156438..b5e84d49a0 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -185,10 +185,31 @@ _ResourceSaver::_ResourceSaver() {
/////////////////OS
+void _OS::global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta) {
+
+ OS::get_singleton()->global_menu_add_item(p_menu, p_label, p_signal, p_meta);
+}
+
+void _OS::global_menu_add_separator(const String &p_menu) {
+
+ OS::get_singleton()->global_menu_add_separator(p_menu);
+}
+
+void _OS::global_menu_remove_item(const String &p_menu, int p_idx) {
+
+ OS::get_singleton()->global_menu_remove_item(p_menu, p_idx);
+}
+
+void _OS::global_menu_clear(const String &p_menu) {
+
+ OS::get_singleton()->global_menu_clear(p_menu);
+}
+
Point2 _OS::get_mouse_position() const {
return OS::get_singleton()->get_mouse_position();
}
+
void _OS::set_window_title(const String &p_title) {
OS::get_singleton()->set_window_title(p_title);
@@ -202,6 +223,7 @@ int _OS::get_mouse_button_state() const {
String _OS::get_unique_id() const {
return OS::get_singleton()->get_unique_id();
}
+
bool _OS::has_touchscreen_ui_hint() const {
return OS::get_singleton()->has_touchscreen_ui_hint();
@@ -211,6 +233,7 @@ void _OS::set_clipboard(const String &p_text) {
OS::get_singleton()->set_clipboard(p_text);
}
+
String _OS::get_clipboard() const {
return OS::get_singleton()->get_clipboard();
@@ -257,12 +280,14 @@ void _OS::set_video_mode(const Size2 &p_size, bool p_fullscreen, bool p_resizeab
vm.resizable = p_resizeable;
OS::get_singleton()->set_video_mode(vm, p_screen);
}
+
Size2 _OS::get_video_mode(int p_screen) const {
OS::VideoMode vm;
vm = OS::get_singleton()->get_video_mode(p_screen);
return Size2(vm.width, vm.height);
}
+
bool _OS::is_video_mode_fullscreen(int p_screen) const {
OS::VideoMode vm;
@@ -1125,6 +1150,11 @@ void _OS::_bind_methods() {
//ClassDB::bind_method(D_METHOD("is_video_mode_resizable","screen"),&_OS::is_video_mode_resizable,DEFVAL(0));
//ClassDB::bind_method(D_METHOD("get_fullscreen_mode_list","screen"),&_OS::get_fullscreen_mode_list,DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("global_menu_add_item", "menu", "label", "id", "meta"), &_OS::global_menu_add_item);
+ ClassDB::bind_method(D_METHOD("global_menu_add_separator", "menu"), &_OS::global_menu_add_separator);
+ ClassDB::bind_method(D_METHOD("global_menu_remove_item", "menu", "idx"), &_OS::global_menu_remove_item);
+ ClassDB::bind_method(D_METHOD("global_menu_clear", "menu"), &_OS::global_menu_clear);
+
ClassDB::bind_method(D_METHOD("get_video_driver_count"), &_OS::get_video_driver_count);
ClassDB::bind_method(D_METHOD("get_video_driver_name", "driver"), &_OS::get_video_driver_name);
ClassDB::bind_method(D_METHOD("get_current_video_driver"), &_OS::get_current_video_driver);
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index f0f86e003f..76ba2dc0a5 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -143,6 +143,11 @@ public:
MONTH_DECEMBER
};
+ void global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta);
+ void global_menu_add_separator(const String &p_menu);
+ void global_menu_remove_item(const String &p_menu, int p_idx);
+ void global_menu_clear(const String &p_menu);
+
Point2 get_mouse_position() const;
void set_window_title(const String &p_title);
int get_mouse_button_state() const;
diff --git a/core/os/main_loop.cpp b/core/os/main_loop.cpp
index 9946ced2f3..eca3b2a7f4 100644
--- a/core/os/main_loop.cpp
+++ b/core/os/main_loop.cpp
@@ -49,6 +49,8 @@ void MainLoop::_bind_methods() {
BIND_VMETHOD(MethodInfo("_drop_files", PropertyInfo(Variant::POOL_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "from_screen")));
BIND_VMETHOD(MethodInfo("_finalize"));
+ BIND_VMETHOD(MethodInfo("_global_menu_action", PropertyInfo(Variant::NIL, "id"), PropertyInfo(Variant::NIL, "meta")));
+
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_ENTER);
BIND_CONSTANT(NOTIFICATION_WM_MOUSE_EXIT);
BIND_CONSTANT(NOTIFICATION_WM_FOCUS_IN);
@@ -115,6 +117,12 @@ void MainLoop::drop_files(const Vector<String> &p_files, int p_from_screen) {
get_script_instance()->call("_drop_files", p_files, p_from_screen);
}
+void MainLoop::global_menu_action(const Variant &p_id, const Variant &p_meta) {
+
+ if (get_script_instance())
+ get_script_instance()->call("_global_menu_action", p_id, p_meta);
+}
+
void MainLoop::finish() {
if (get_script_instance()) {
diff --git a/core/os/main_loop.h b/core/os/main_loop.h
index 6ddaf5bee7..54e61fd2fa 100644
--- a/core/os/main_loop.h
+++ b/core/os/main_loop.h
@@ -71,6 +71,7 @@ public:
virtual void finish();
virtual void drop_files(const Vector<String> &p_files, int p_from_screen = 0);
+ virtual void global_menu_action(const Variant &p_id, const Variant &p_meta);
void set_init_script(const Ref<Script> &p_init_script);
diff --git a/core/os/os.h b/core/os/os.h
index e627773d88..9b46b43081 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -143,6 +143,11 @@ public:
static OS *get_singleton();
+ virtual void global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta){};
+ virtual void global_menu_add_separator(const String &p_menu){};
+ virtual void global_menu_remove_item(const String &p_menu, int p_idx){};
+ virtual void global_menu_clear(const String &p_menu){};
+
void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, Logger::ErrorType p_type = Logger::ERR_ERROR);
void print(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
void printerr(const char *p_format, ...) _PRINTF_FORMAT_ATTRIBUTE_2_3;
diff --git a/doc/classes/MainLoop.xml b/doc/classes/MainLoop.xml
index fedf77bfd2..181a99590a 100644
--- a/doc/classes/MainLoop.xml
+++ b/doc/classes/MainLoop.xml
@@ -61,6 +61,16 @@
Called before the program exits.
</description>
</method>
+ <method name="_global_menu_action" qualifiers="virtual">
+ <return type="void">
+ </return>
+ <argument index="0" name="id" type="Variant">
+ </argument>
+ <argument index="1" name="meta" type="Variant">
+ </argument>
+ <description>
+ </description>
+ </method>
<method name="_idle" qualifiers="virtual">
<return type="bool">
</return>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index c770e78c7c..938777a36b 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -497,6 +497,50 @@
Returns unobscured area of the window where interactive controls should be rendered.
</description>
</method>
+ <method name="global_menu_add_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu" type="String">
+ </argument>
+ <argument index="1" name="label" type="String">
+ </argument>
+ <argument index="2" name="id" type="Variant">
+ </argument>
+ <argument index="3" name="meta" type="Variant">
+ </argument>
+ <description>
+ Add a new item with text "label" to global menu. Use "_dock" menu to add item to the macOS dock icon menu.
+ </description>
+ </method>
+ <method name="global_menu_add_separator">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu" type="String">
+ </argument>
+ <description>
+ Add a separator between items. Separators also occupy an index.
+ </description>
+ </method>
+ <method name="global_menu_clear">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu" type="String">
+ </argument>
+ <description>
+ Clear the global menu, in effect removing all items.
+ </description>
+ </method>
+ <method name="global_menu_remove_item">
+ <return type="void">
+ </return>
+ <argument index="0" name="menu" type="String">
+ </argument>
+ <argument index="1" name="idx" type="int">
+ </argument>
+ <description>
+ Removes the item at index "idx" from the global menu. Note that the indexes of items after the removed item are going to be shifted by one.
+ </description>
+ </method>
<method name="has_environment" qualifiers="const">
<return type="bool">
</return>
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index 1302c1e6bf..ed43f83f05 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -324,6 +324,15 @@
Emitted when files are dragged from the OS file manager and dropped in the game window. The arguments are a list of file paths and the identifier of the screen where the drag originated.
</description>
</signal>
+ <signal name="global_menu_action">
+ <argument index="0" name="id" type="Nil">
+ </argument>
+ <argument index="1" name="meta" type="Nil">
+ </argument>
+ <description>
+ Emitted whenever global menu item is clicked.
+ </description>
+ </signal>
<signal name="idle_frame">
<description>
Emitted immediately before [method Node._process] is called on every node in the [SceneTree].
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 3e97dbd96c..635f6d4fc7 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -135,6 +135,8 @@ void EditorNode::_update_scene_tabs() {
bool show_rb = EditorSettings::get_singleton()->get("interface/scene_tabs/show_script_button");
+ OS::get_singleton()->global_menu_clear("_dock");
+
scene_tabs->clear_tabs();
Ref<Texture> script_icon = gui_base->get_icon("Script", "EditorIcons");
for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
@@ -149,11 +151,16 @@ void EditorNode::_update_scene_tabs() {
bool unsaved = (i == current) ? saved_version != editor_data.get_undo_redo().get_version() : editor_data.get_scene_version(i) != 0;
scene_tabs->add_tab(editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), icon);
+ OS::get_singleton()->global_menu_add_item("_dock", editor_data.get_scene_title(i) + (unsaved ? "(*)" : ""), GLOBAL_SCENE, i);
+
if (show_rb && editor_data.get_scene_root_script(i).is_valid()) {
scene_tabs->set_tab_right_button(i, script_icon);
}
}
+ OS::get_singleton()->global_menu_add_separator("_dock");
+ OS::get_singleton()->global_menu_add_item("_dock", TTR("New Window"), GLOBAL_NEW_WINDOW, Variant());
+
scene_tabs->set_current_tab(editor_data.get_edited_scene());
if (scene_tabs->get_offset_buttons_visible()) {
@@ -290,6 +297,7 @@ void EditorNode::_notification(int p_what) {
get_tree()->get_root()->set_as_audio_listener_2d(false);
get_tree()->set_auto_accept_quit(false);
get_tree()->connect("files_dropped", this, "_dropped_files");
+ get_tree()->connect("global_menu_action", this, "_global_menu_action");
/* DO NOT LOAD SCENES HERE, WAIT FOR FILE SCANNING AND REIMPORT TO COMPLETE */
} break;
@@ -4941,6 +4949,23 @@ void EditorNode::remove_tool_menu_item(const String &p_name) {
}
}
+void EditorNode::_global_menu_action(const Variant &p_id, const Variant &p_meta) {
+
+ int id = (int)p_id;
+ if (id == GLOBAL_NEW_WINDOW) {
+ if (OS::get_singleton()->get_main_loop()) {
+ List<String> args;
+ String exec = OS::get_singleton()->get_executable_path();
+
+ OS::ProcessID pid = 0;
+ OS::get_singleton()->execute(exec, args, false, &pid);
+ }
+ } else if (id == GLOBAL_SCENE) {
+ int idx = (int)p_meta;
+ scene_tabs->set_current_tab(idx);
+ }
+}
+
void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) {
String to_path = ProjectSettings::get_singleton()->globalize_path(get_filesystem_dock()->get_selected_path());
@@ -5322,6 +5347,7 @@ void EditorNode::_bind_methods() {
ClassDB::bind_method("_clear_undo_history", &EditorNode::_clear_undo_history);
ClassDB::bind_method("_dropped_files", &EditorNode::_dropped_files);
+ ClassDB::bind_method(D_METHOD("_global_menu_action"), &EditorNode::_global_menu_action, DEFVAL(Variant()));
ClassDB::bind_method("_toggle_distraction_free_mode", &EditorNode::_toggle_distraction_free_mode);
ClassDB::bind_method("edit_item_resource", &EditorNode::edit_item_resource);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index a8443549ed..61bbb7b86d 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -207,6 +207,9 @@ private:
SET_VIDEO_DRIVER_SAVE_AND_RESTART,
+ GLOBAL_NEW_WINDOW,
+ GLOBAL_SCENE,
+
IMPORT_PLUGIN_BASE = 100,
TOOL_MENU_BASE = 1000
@@ -504,6 +507,7 @@ private:
void _add_to_recent_scenes(const String &p_scene);
void _update_recent_scenes();
void _open_recent_scene(int p_idx);
+ void _global_menu_action(const Variant &p_id, const Variant &p_meta);
void _dropped_files(const Vector<String> &p_files, int p_screen);
void _add_dropped_files_recursive(const Vector<String> &p_files, String to_path);
String _recent_scene;
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 5709bdc3fa..fbaa90c3d7 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -946,6 +946,11 @@ public:
static const char *SIGNAL_SELECTION_CHANGED;
static const char *SIGNAL_PROJECT_ASK_OPEN;
+ enum MenuOptions {
+ GLOBAL_NEW_WINDOW,
+ GLOBAL_OPEN_PROJECT
+ };
+
// Can often be passed by copy
struct Item {
String project_key;
@@ -1181,6 +1186,7 @@ void ProjectList::load_projects() {
_projects.clear();
_last_clicked = "";
_selected_project_keys.clear();
+ OS::get_singleton()->global_menu_clear("_dock");
// Load data
// TODO Would be nice to change how projects and favourites are stored... it complicates things a bit.
@@ -1218,6 +1224,9 @@ void ProjectList::load_projects() {
create_project_item_control(i);
}
+ OS::get_singleton()->global_menu_add_separator("_dock");
+ OS::get_singleton()->global_menu_add_item("_dock", TTR("New Window"), GLOBAL_NEW_WINDOW, Variant());
+
sort_projects();
set_v_scroll(0);
@@ -1305,6 +1314,7 @@ void ProjectList::create_project_item_control(int p_index) {
fpath->set_clip_text(true);
_scroll_children->add_child(hb);
+ OS::get_singleton()->global_menu_add_item("_dock", item.project_name + " ( " + item.path + " )", GLOBAL_OPEN_PROJECT, Variant(item.path.plus_file("project.godot")));
item.control = hb;
}
@@ -1894,6 +1904,29 @@ void ProjectManager::_confirm_update_settings() {
_open_selected_projects();
}
+void ProjectManager::_global_menu_action(const Variant &p_id, const Variant &p_meta) {
+
+ int id = (int)p_id;
+ if (id == ProjectList::GLOBAL_NEW_WINDOW) {
+ List<String> args;
+ String exec = OS::get_singleton()->get_executable_path();
+
+ OS::ProcessID pid = 0;
+ OS::get_singleton()->execute(exec, args, false, &pid);
+ } else if (id == ProjectList::GLOBAL_OPEN_PROJECT) {
+ String conf = (String)p_meta;
+
+ if (conf != String()) {
+ List<String> args;
+ args.push_back(conf);
+ String exec = OS::get_singleton()->get_executable_path();
+
+ OS::ProcessID pid = 0;
+ OS::get_singleton()->execute(exec, args, false, &pid);
+ }
+ }
+}
+
void ProjectManager::_open_selected_projects() {
const Set<String> &selected_list = _project_list->get_selected_project_keys();
@@ -2236,6 +2269,7 @@ void ProjectManager::_bind_methods() {
ClassDB::bind_method("_open_selected_projects_ask", &ProjectManager::_open_selected_projects_ask);
ClassDB::bind_method("_open_selected_projects", &ProjectManager::_open_selected_projects);
+ ClassDB::bind_method(D_METHOD("_global_menu_action"), &ProjectManager::_global_menu_action, DEFVAL(Variant()));
ClassDB::bind_method("_run_project", &ProjectManager::_run_project);
ClassDB::bind_method("_run_project_confirm", &ProjectManager::_run_project_confirm);
ClassDB::bind_method("_scan_projects", &ProjectManager::_scan_projects);
@@ -2561,6 +2595,7 @@ ProjectManager::ProjectManager() {
}
SceneTree::get_singleton()->connect("files_dropped", this, "_files_dropped");
+ SceneTree::get_singleton()->connect("global_menu_action", this, "_global_menu_action");
run_error_diag = memnew(AcceptDialog);
gui_base->add_child(run_error_diag);
diff --git a/editor/project_manager.h b/editor/project_manager.h
index 2a5fd02892..cf0b8b8801 100644
--- a/editor/project_manager.h
+++ b/editor/project_manager.h
@@ -43,6 +43,7 @@ class ProjectList;
class ProjectListFilter;
class ProjectManager : public Control {
+
GDCLASS(ProjectManager, Control);
Button *erase_btn;
@@ -96,6 +97,7 @@ class ProjectManager : public Control {
void _restart_confirm();
void _exit_dialog();
void _scan_begin(const String &p_base);
+ void _global_menu_action(const Variant &p_id, const Variant &p_meta);
void _confirm_update_settings();
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 9cb2915701..f1f37e24d2 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -157,6 +157,26 @@ public:
int video_driver_index;
virtual int get_current_video_driver() const;
+ struct GlobalMenuItem {
+ String label;
+ Variant signal;
+ Variant meta;
+
+ GlobalMenuItem() {
+ //NOP
+ }
+
+ GlobalMenuItem(const String &p_label, const Variant &p_signal, const Variant &p_meta) {
+ label = p_label;
+ signal = p_signal;
+ meta = p_meta;
+ }
+ };
+
+ Map<String, Vector<GlobalMenuItem> > global_menus;
+
+ void _update_global_menu();
+
protected:
virtual void initialize_core();
virtual Error initialize(const VideoMode &p_desired, int p_video_driver, int p_audio_driver);
@@ -168,6 +188,11 @@ protected:
public:
static OS_OSX *singleton;
+ void global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta);
+ void global_menu_add_separator(const String &p_menu);
+ void global_menu_remove_item(const String &p_menu, int p_idx);
+ void global_menu_clear(const String &p_menu);
+
void wm_minimized(bool p_minimized);
virtual String get_name() const;
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index ab77897b08..f48d4a307d 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -204,11 +204,53 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
}
}
+- (void)globalMenuCallback:(id)sender {
+
+ if (![sender representedObject])
+ return;
+
+ OS_OSX::GlobalMenuItem *item = (OS_OSX::GlobalMenuItem *)[[sender representedObject] pointerValue];
+
+ if (!item)
+ return;
+
+ OS_OSX::singleton->main_loop->global_menu_action(item->signal, item->meta);
+}
+
+- (NSMenu *)applicationDockMenu:(NSApplication *)sender {
+
+ NSMenu *menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+
+ Vector<OS_OSX::GlobalMenuItem> &E = OS_OSX::singleton->global_menus["_dock"];
+ for (int i = 0; i < E.size(); i++) {
+ if (E[i].label == String()) {
+ [menu addItem:[NSMenuItem separatorItem]];
+ } else {
+ NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:E[i].label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""];
+ [menu_item setRepresentedObject:[NSValue valueWithPointer:&(E[i])]];
+ }
+ }
+
+ return menu;
+}
+
- (BOOL)application:(NSApplication *)sender openFile:(NSString *)filename {
- // Note: called before main loop init!
+ // Note: may be called called before main loop init!
char *utfs = strdup([filename UTF8String]);
OS_OSX::singleton->open_with_filename.parse_utf8(utfs);
free(utfs);
+
+#ifdef TOOLS_ENABLED
+ // Open new instance
+ if (OS_OSX::singleton->get_main_loop()) {
+ List<String> args;
+ args.push_back(OS_OSX::singleton->open_with_filename);
+ String exec = OS::get_singleton()->get_executable_path();
+
+ OS::ProcessID pid = 0;
+ OS::get_singleton()->execute(exec, args, false, &pid);
+ }
+#endif
return YES;
}
@@ -1266,6 +1308,56 @@ inline void sendPanEvent(double dx, double dy, int modifierFlags) {
@end
+void OS_OSX::_update_global_menu() {
+
+ NSMenu *main_menu = [NSApp mainMenu];
+
+ for (int i = 1; i < [main_menu numberOfItems]; i++) {
+ [main_menu removeItemAtIndex:i];
+ }
+ for (Map<String, Vector<GlobalMenuItem> >::Element *E = global_menus.front(); E; E = E->next()) {
+ if (E->key() != "_dock") {
+ NSMenu *menu = [[[NSMenu alloc] initWithTitle:[NSString stringWithUTF8String:E->key().utf8().get_data()]] autorelease];
+ for (int i = 0; i < E->get().size(); i++) {
+ if (E->get()[i].label == String()) {
+ [menu addItem:[NSMenuItem separatorItem]];
+ } else {
+ NSMenuItem *menu_item = [menu addItemWithTitle:[NSString stringWithUTF8String:E->get()[i].label.utf8().get_data()] action:@selector(globalMenuCallback:) keyEquivalent:@""];
+ [menu_item setRepresentedObject:[NSValue valueWithPointer:&(E->get()[i])]];
+ }
+ }
+ NSMenuItem *menu_item = [main_menu addItemWithTitle:[NSString stringWithUTF8String:E->key().utf8().get_data()] action:nil keyEquivalent:@""];
+ [main_menu setSubmenu:menu forItem:menu_item];
+ }
+ }
+}
+
+void OS_OSX::global_menu_add_item(const String &p_menu, const String &p_label, const Variant &p_signal, const Variant &p_meta) {
+
+ global_menus[p_menu].push_back(GlobalMenuItem(p_label, p_signal, p_meta));
+ _update_global_menu();
+}
+
+void OS_OSX::global_menu_add_separator(const String &p_menu) {
+
+ global_menus[p_menu].push_back(GlobalMenuItem());
+ _update_global_menu();
+}
+
+void OS_OSX::global_menu_remove_item(const String &p_menu, int p_idx) {
+
+ ERR_FAIL_INDEX(p_idx, global_menus[p_menu].size());
+
+ global_menus[p_menu].remove(p_idx);
+ _update_global_menu();
+}
+
+void OS_OSX::global_menu_clear(const String &p_menu) {
+
+ global_menus[p_menu].clear();
+ _update_global_menu();
+}
+
Point2 OS_OSX::get_ime_selection() const {
return im_selection;
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 98d63650d3..617a703855 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1673,6 +1673,12 @@ void SceneTree::drop_files(const Vector<String> &p_files, int p_from_screen) {
MainLoop::drop_files(p_files, p_from_screen);
}
+void SceneTree::global_menu_action(const Variant &p_id, const Variant &p_meta) {
+
+ emit_signal("global_menu_action", p_id, p_meta);
+ MainLoop::global_menu_action(p_id, p_meta);
+}
+
Ref<SceneTreeTimer> SceneTree::create_timer(float p_delay_sec, bool p_process_pause) {
Ref<SceneTreeTimer> stt;
@@ -1894,6 +1900,7 @@ void SceneTree::_bind_methods() {
ADD_SIGNAL(MethodInfo("physics_frame"));
ADD_SIGNAL(MethodInfo("files_dropped", PropertyInfo(Variant::POOL_STRING_ARRAY, "files"), PropertyInfo(Variant::INT, "screen")));
+ ADD_SIGNAL(MethodInfo("global_menu_action", PropertyInfo(Variant::NIL, "id"), PropertyInfo(Variant::NIL, "meta")));
ADD_SIGNAL(MethodInfo("network_peer_connected", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("network_peer_disconnected", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("connected_to_server"));
diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h
index afb653e242..42a87545a6 100644
--- a/scene/main/scene_tree.h
+++ b/scene/main/scene_tree.h
@@ -407,6 +407,7 @@ public:
static SceneTree *get_singleton() { return singleton; }
void drop_files(const Vector<String> &p_files, int p_from_screen = 0);
+ void global_menu_action(const Variant &p_id, const Variant &p_meta);
//network API