diff options
Diffstat (limited to 'platform/osx')
-rw-r--r-- | platform/osx/dir_access_osx.h | 3 | ||||
-rw-r--r-- | platform/osx/export/export.cpp | 81 | ||||
-rw-r--r-- | platform/osx/logo.png | bin | 1752 -> 1751 bytes | |||
-rw-r--r-- | platform/osx/os_osx.h | 28 | ||||
-rw-r--r-- | platform/osx/os_osx.mm | 125 |
5 files changed, 189 insertions, 48 deletions
diff --git a/platform/osx/dir_access_osx.h b/platform/osx/dir_access_osx.h index e1aa038c61..c5951a570e 100644 --- a/platform/osx/dir_access_osx.h +++ b/platform/osx/dir_access_osx.h @@ -41,9 +41,6 @@ #include "core/os/dir_access.h" #include "drivers/unix/dir_access_unix.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class DirAccessOSX : public DirAccessUnix { protected: virtual String fix_unicode_name(const char *p_name) const; diff --git a/platform/osx/export/export.cpp b/platform/osx/export/export.cpp index 8cabc45250..9226aea369 100644 --- a/platform/osx/export/export.cpp +++ b/platform/osx/export/export.cpp @@ -29,9 +29,11 @@ /*************************************************************************/ #include "export.h" + #include "core/io/marshalls.h" #include "core/io/resource_saver.h" #include "core/io/zip_io.h" +#include "core/os/dir_access.h" #include "core/os/file_access.h" #include "core/os/os.h" #include "core/project_settings.h" @@ -130,8 +132,12 @@ void EditorExportPlatformOSX::get_export_options(List<ExportOption> *r_options) r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), false)); #ifdef OSX_ENABLED - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity"), "")); - r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_PLACEHOLDER_TEXT, "Type: Name (ID)"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/hardened_runtime"), true)); + r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/entitlements", PROPERTY_HINT_GLOBAL_FILE, "*.plist"), "")); + r_options->push_back(ExportOption(PropertyInfo(Variant::POOL_STRING_ARRAY, "codesign/custom_options"), PoolStringArray())); #endif r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "texture_format/s3tc"), true)); @@ -238,19 +244,23 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ { "is32", "s8mk", false, 16 } //16x16 24-bit RLE + 8-bit uncompressed mask }; - for (unsigned int i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { + for (uint64_t i = 0; i < (sizeof(icon_infos) / sizeof(icon_infos[0])); ++i) { Ref<Image> copy = p_icon; // does this make sense? doesn't this just increase the reference count instead of making a copy? Do we even need a copy? copy->convert(Image::FORMAT_RGBA8); copy->resize(icon_infos[i].size, icon_infos[i].size); if (icon_infos[i].is_png) { - //encode png icon + // Encode PNG icon. it->create_from_image(copy); String path = EditorSettings::get_singleton()->get_cache_dir().plus_file("icon.png"); ResourceSaver::save(path, it); FileAccess *f = FileAccess::open(path, FileAccess::READ); - ERR_FAIL_COND(!f); + if (!f) { + // Clean up generated file. + DirAccess::remove_file_or_error(path); + ERR_FAIL(); + } int ofs = data.size(); uint32_t len = f->get_len(); @@ -261,6 +271,10 @@ void EditorExportPlatformOSX::_make_icon(const Ref<Image> &p_icon, Vector<uint8_ len = BSWAP32(len); copymem(&data.write[ofs], icon_infos[i].name, 4); encode_uint32(len, &data.write[ofs + 4]); + + // Clean up generated file. + DirAccess::remove_file_or_error(path); + } else { PoolVector<uint8_t> src_data = copy->get_data(); @@ -350,25 +364,48 @@ void EditorExportPlatformOSX::_fix_plist(const Ref<EditorExportPreset> &p_preset Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) { List<String> args; + if (p_preset->get("codesign/timestamp")) { + args.push_back("--timestamp"); + } + if (p_preset->get("codesign/hardened_runtime")) { + args.push_back("--options"); + args.push_back("runtime"); + } + if (p_preset->get("codesign/entitlements") != "") { /* this should point to our entitlements.plist file that sandboxes our application, I don't know if this should also be placed in our app bundle */ - args.push_back("-entitlements"); + args.push_back("--entitlements"); args.push_back(p_preset->get("codesign/entitlements")); } + + PoolStringArray user_args = p_preset->get("codesign/custom_options"); + for (int i = 0; i < user_args.size(); i++) { + String user_arg = user_args[i].strip_edges(); + if (!user_arg.empty()) { + args.push_back(user_arg); + } + } + args.push_back("-s"); args.push_back(p_preset->get("codesign/identity")); + args.push_back("-v"); /* provide some more feedback */ + args.push_back(p_path); String str; Error err = OS::get_singleton()->execute("codesign", args, true, NULL, &str, NULL, true); ERR_FAIL_COND_V(err != OK, err); - print_line("codesign: " + str); + print_line("codesign (" + p_path + "): " + str); if (str.find("no identity found") != -1) { EditorNode::add_io_error("codesign: no identity found"); return FAILED; } + if ((str.find("unrecognized blob type") != -1) || (str.find("cannot read entitlement data") != -1)) { + EditorNode::add_io_error("codesign: invalid entitlements file"); + return FAILED; + } return OK; } @@ -376,7 +413,9 @@ Error EditorExportPlatformOSX::_code_sign(const Ref<EditorExportPreset> &p_prese Error EditorExportPlatformOSX::_create_dmg(const String &p_dmg_path, const String &p_pkg_name, const String &p_app_path_name) { List<String> args; - OS::get_singleton()->move_to_trash(p_dmg_path); + if (FileAccess::exists(p_dmg_path)) { + OS::get_singleton()->move_to_trash(p_dmg_path); + } args.push_back("create"); args.push_back(p_dmg_path); @@ -561,7 +600,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p } } } - //bleh? } if (data.size() > 0) { @@ -638,20 +676,20 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p err = save_pack(p_preset, pack_path, &shared_objects); // see if we can code sign our new package - String identity = p_preset->get("codesign/identity"); + bool sign_enabled = p_preset->get("codesign/enable"); if (err == OK) { DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < shared_objects.size(); i++) { err = da->copy(shared_objects[i].path, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file()); - if (err == OK && identity != "") { + if (err == OK && sign_enabled) { err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Frameworks/" + shared_objects[i].path.get_file()); } } memdelete(da); } - if (err == OK && identity != "") { + if (err == OK && sign_enabled) { if (ep.step("Code signing bundle", 2)) { return ERR_SKIP; } @@ -664,19 +702,6 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p ///@TODO we should check the contents of /Contents/Frameworks for frameworks to sign } - if (err == OK && identity != "") { - // we should probably loop through all resources and sign them? - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Resources/icon.icns"); - } - - if (err == OK && identity != "") { - err = _code_sign(p_preset, pack_path); - } - - if (err == OK && identity != "") { - err = _code_sign(p_preset, tmp_app_path_name + "/Contents/Info.plist"); - } - // and finally create a DMG if (err == OK) { if (ep.step("Making DMG", 3)) { @@ -687,7 +712,8 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p // Clean up temporary .app dir OS::get_singleton()->move_to_trash(tmp_app_path_name); - } else { + + } else { // pck String pack_path = EditorSettings::get_singleton()->get_cache_dir().plus_file(pkg_name + ".pck"); @@ -747,6 +773,9 @@ Error EditorExportPlatformOSX::export_project(const Ref<EditorExportPreset> &p_p zipCloseFileInZip(dst_pkg_zip); } } + + // Clean up generated file. + DirAccess::remove_file_or_error(pack_path); } } diff --git a/platform/osx/logo.png b/platform/osx/logo.png Binary files differindex 62086fc415..834bbf3ba6 100644 --- a/platform/osx/logo.png +++ b/platform/osx/logo.png diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index a83d5084ed..f1f37e24d2 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -51,9 +51,6 @@ #include <CoreVideo/CoreVideo.h> #undef CursorShape -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class OS_OSX : public OS_Unix { public: @@ -160,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); @@ -171,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 992aff54f1..51ae264cf7 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; } @@ -297,6 +339,8 @@ static CVReturn DisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt CGFloat oldBackingScaleFactor = [[[notification userInfo] objectForKey:@"NSBackingPropertyOldScaleFactorKey"] doubleValue]; if (OS_OSX::singleton->is_hidpi_allowed()) { [OS_OSX::singleton->window_view setWantsBestResolutionOpenGLSurface:YES]; + } else { + [OS_OSX::singleton->window_view setWantsBestResolutionOpenGLSurface:NO]; } if (newBackingScaleFactor != oldBackingScaleFactor) { @@ -1266,6 +1310,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; @@ -1400,6 +1494,8 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a [window_view setWantsBestResolutionOpenGLSurface:YES]; //if (current_videomode.resizable) [window_object setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary]; + } else { + [window_view setWantsBestResolutionOpenGLSurface:NO]; } //[window_object setTitle:[NSString stringWithUTF8String:"GodotEnginies"]]; @@ -1719,10 +1815,7 @@ Error OS_OSX::open_dynamic_library(const String p_path, void *&p_library_handle, } p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); - if (!p_library_handle) { - ERR_EXPLAIN("Can't open dynamic library: " + p_path + ". Error: " + dlerror()); - ERR_FAIL_V(ERR_CANT_OPEN); - } + ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ", error: " + dlerror() + "."); return OK; } @@ -1884,11 +1977,16 @@ void OS_OSX::set_custom_mouse_cursor(const RES &p_cursor, CursorShape p_shape, c [nsimage release]; } else { // Reset to default system cursor - cursors[p_shape] = NULL; + if (cursors[p_shape] != NULL) { + [cursors[p_shape] release]; + cursors[p_shape] = NULL; + } CursorShape c = cursor_shape; cursor_shape = CURSOR_MAX; set_cursor_shape(c); + + cursors_cache.erase(p_shape); } } @@ -1962,15 +2060,10 @@ void OS_OSX::set_native_icon(const String &p_filename) { memdelete(f); NSData *icon_data = [[[NSData alloc] initWithBytes:&data.write[0] length:len] autorelease]; - if (!icon_data) { - ERR_EXPLAIN("Error reading icon data"); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!icon_data, "Error reading icon data."); + NSImage *icon = [[[NSImage alloc] initWithData:icon_data] autorelease]; - if (!icon) { - ERR_EXPLAIN("Error loading icon"); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!icon, "Error loading icon."); [NSApp setApplicationIconImage:icon]; } @@ -2411,7 +2504,7 @@ Size2 OS_OSX::get_min_window_size() const { void OS_OSX::set_min_window_size(const Size2 p_size) { if ((p_size != Size2()) && (max_size != Size2()) && ((p_size.x > max_size.x) || (p_size.y > max_size.y))) { - WARN_PRINT("Minimum window size can't be larger than maximum window size!"); + ERR_PRINT("Minimum window size can't be larger than maximum window size!"); return; } min_size = p_size; @@ -2427,7 +2520,7 @@ void OS_OSX::set_min_window_size(const Size2 p_size) { void OS_OSX::set_max_window_size(const Size2 p_size) { if ((p_size != Size2()) && ((p_size.x < min_size.x) || (p_size.y < min_size.y))) { - WARN_PRINT("Maximum window size can't be smaller than minimum window size!"); + ERR_PRINT("Maximum window size can't be smaller than minimum window size!"); return; } max_size = p_size; |