#include "pch.h" #include "platform_legacy/legacy_platform_services.h" #include "app.h" #include "app_core/document_platform_io.h" #ifdef __ANDROID__ void displayKeyboard(bool pShow); void android_async_lock(); void android_async_swap(); void android_async_unlock(); void android_attach_jni(); void android_detach_jni(); void android_pick_file(std::function callback); void android_pick_file_save(std::function callback); std::string android_get_clipboard(); bool android_set_clipboard(const std::string& s); #elif __APPLE__ #elif __LINUX__ #include std::string linux_home_path(); int mkpath(const std::string& dir, mode_t mode = DEFFILEMODE); void linux_update_fps(int frames); #elif __WEB__ void webgl_pick_file(std::function callback); void webgl_pick_file_save( const std::string& path, const std::string& name, std::function callback); void webgl_sync(); #endif namespace { void invoke_picked_path_if_selected( const std::string& path, const std::function& callback) { if (pp::app::plan_picked_path(path) == pp::app::PickedPathAction::invoke_callback) callback(path); } // DEBT-0017: fallback for platforms that do not inject PlatformServices yet. class LegacyPlatformServices final : public pp::platform::PlatformServices { public: [[nodiscard]] pp::platform::PlatformStoragePaths prepare_storage_paths() override { #if defined(__IOS__) [App::I->ios_view init_dirs]; return { App::I->data_path, App::I->work_path, App::I->rec_path, App::I->tmp_path, }; #elif defined(__OSX__) [App::I->osx_app init_dirs]; return { App::I->data_path, App::I->work_path, App::I->rec_path, App::I->tmp_path, }; #elif __LINUX__ const std::string data_path = linux_home_path() + "/PanoPainter"; mkpath(data_path + "/brushes"); mkpath(data_path + "/brushes/thumbs"); mkpath(data_path + "/patterns"); mkpath(data_path + "/patterns/thumbs"); mkpath(data_path + "/settings"); mkpath(data_path + "/frames"); return { data_path, data_path, data_path + "/frames", {}, }; #elif __WEB__ const std::string data_path = "/PanoPainter"; mkdir(data_path.c_str(), 0777); mkdir((data_path + "/brushes").c_str(), 0777); mkdir((data_path + "/brushes/thumbs").c_str(), 0777); mkdir((data_path + "/patterns").c_str(), 0777); mkdir((data_path + "/patterns/thumbs").c_str(), 0777); mkdir((data_path + "/settings").c_str(), 0777); mkdir((data_path + "/frames").c_str(), 0777); return { data_path, data_path, data_path + "/frames", {}, }; #else return { App::I->data_path, App::I->work_path, App::I->rec_path, App::I->tmp_path, }; #endif } [[nodiscard]] std::string clipboard_text() override { #if __IOS__ return [App::I->ios_view clipboard_get_string]; #elif __OSX__ return [App::I->osx_view clipboard_get_string]; #elif __ANDROID__ return android_get_clipboard(); #else return {}; #endif } [[nodiscard]] bool set_clipboard_text(std::string_view text) override { const std::string value(text); #if __IOS__ return [App::I->ios_view clipboard_set_string:value]; #elif __OSX__ return [App::I->osx_view clipboard_set_string:value]; #elif __ANDROID__ return android_set_clipboard(value); #else return false; #endif } void set_cursor_visible(bool visible) override { #ifdef __OSX__ [App::I->osx_view show_cursor:visible]; #else (void)visible; #endif } void set_virtual_keyboard_visible(bool visible) override { #ifdef __IOS__ dispatch_async(dispatch_get_main_queue(), ^{ if (visible) [App::I->ios_view show_keyboard]; else [App::I->ios_view hide_keyboard]; }); #elif __ANDROID__ displayKeyboard(visible); #else (void)visible; #endif } void attach_ui_thread() override { #ifdef __ANDROID__ android_attach_jni(); #endif } void detach_ui_thread() override { #ifdef __ANDROID__ android_detach_jni(); #endif } void acquire_render_context() override { #if __OSX__ [App::I->osx_view async_lock]; #elif __IOS__ [App::I->ios_view async_lock]; #elif __ANDROID__ android_async_lock(); #elif __LINUX__ || __WEB__ glfwMakeContextCurrent(App::I->glfw_window); #endif } void release_render_context() override { #if __OSX__ [App::I->osx_view async_unlock]; #elif __IOS__ [App::I->ios_view async_unlock]; #elif __ANDROID__ android_async_unlock(); #endif } void present_render_context() override { #if __OSX__ [App::I->osx_view async_swap]; #elif __IOS__ [App::I->ios_view async_swap]; #elif __ANDROID__ android_async_swap(); #elif __LINUX__ || __WEB__ glfwSwapBuffers(App::I->glfw_window); #endif } void begin_render_capture_frame() override { } void end_render_capture_frame() override { } void update_platform_frame(float delta_time_seconds) override { (void)delta_time_seconds; } void report_rendered_frames(int frames) override { #ifdef __LINUX__ linux_update_fps(frames); #else (void)frames; #endif } void pick_image(pp::platform::PickedPathCallback callback) override { #ifdef __IOS__ dispatch_async(dispatch_get_main_queue(), ^{ [App::I->ios_view pick_photo:callback]; }); #elif __OSX__ dispatch_async(dispatch_get_main_queue(), ^{ NSArray* fileTypes = [NSArray arrayWithObjects:@"png", @"PNG", @"jpg", @"JPG", @"jpeg", nil]; std::string path = [App::I->osx_view pick_file:fileTypes]; invoke_picked_path_if_selected(path, callback); }); #elif __ANDROID__ android_pick_file(callback); #elif __LINUX__ if (auto p = tinyfd_openFileDialog("Open File", "", 0, nullptr, nullptr, false)) invoke_picked_path_if_selected(p, callback); #elif __WEB__ webgl_pick_file(callback); #else (void)callback; #endif } void pick_file(std::vector file_types, pp::platform::PickedPathCallback callback) override { #ifdef __IOS__ dispatch_async(dispatch_get_main_queue(), ^{ NSMutableArray* fileTypes = [NSMutableArray arrayWithCapacity:file_types.size()]; for (const auto& t : file_types) [fileTypes addObject:[NSString stringWithCString:t.c_str() encoding:NSUTF8StringEncoding]]; [App::I->ios_view pick_file:fileTypes then:callback]; }); #elif __OSX__ dispatch_async(dispatch_get_main_queue(), ^{ NSMutableArray* fileTypes = [NSMutableArray arrayWithCapacity:file_types.size()]; for (const auto& t : file_types) [fileTypes addObject:[NSString stringWithCString:t.c_str() encoding:NSUTF8StringEncoding]]; std::string path = [App::I->osx_view pick_file:fileTypes]; invoke_picked_path_if_selected(path, callback); }); #elif __ANDROID__ android_pick_file(callback); #elif __LINUX__ if (auto p = tinyfd_openFileDialog("Open File", "", 0, nullptr, nullptr, false)) invoke_picked_path_if_selected(p, callback); #elif __WEB__ webgl_pick_file(callback); #else (void)file_types; (void)callback; #endif } void pick_save_file(std::vector file_types, pp::platform::PickedPathCallback callback) override { #if __OSX__ dispatch_async(dispatch_get_main_queue(), ^{ NSMutableArray* fileTypes = [NSMutableArray arrayWithCapacity:file_types.size()]; for (const auto& t : file_types) [fileTypes addObject:[NSString stringWithCString:t.c_str() encoding:NSUTF8StringEncoding]]; std::string path = [App::I->osx_view pick_file_save:fileTypes]; invoke_picked_path_if_selected(path, callback); }); #elif __ANDROID__ android_pick_file_save(callback); #else (void)file_types; (void)callback; #endif } void pick_directory(pp::platform::PickedPathCallback callback) override { #ifdef __IOS__ (void)callback; #elif __OSX__ dispatch_async(dispatch_get_main_queue(), ^{ std::string path = [App::I->osx_view pick_dir]; invoke_picked_path_if_selected(path, callback); }); #elif __ANDROID__ (void)callback; #else (void)callback; #endif } void display_file(std::string_view path) override { const std::string value(path); #ifdef __IOS__ dispatch_async(dispatch_get_main_queue(), ^{ [App::I->ios_view display_file:value]; }); #elif __OSX__ [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithUTF8String:value.c_str()]]; #else (void)value; #endif } void share_file(std::string_view path) override { const std::string value(path); #ifdef __IOS__ dispatch_async(dispatch_get_main_queue(), ^{ [App::I->ios_view share_file:[NSString stringWithUTF8String:value.c_str()]]; }); #elif __OSX__ dispatch_async(dispatch_get_main_queue(), ^{ [App::I->osx_view share_file:[NSString stringWithUTF8String:value.c_str()]]; }); #else (void)value; #endif } void request_app_close() override { #ifdef __OSX__ dispatch_async(dispatch_get_main_queue(), ^{ [App::I->osx_view close]; }); #elif __LINUX__ glfwSetWindowShouldClose(App::I->glfw_window, GLFW_TRUE); #endif } void save_prepared_file( std::string_view path, std::string_view suggested_name, pp::platform::PreparedFileCallback callback) override { const std::string value(path); const std::string name(suggested_name); #ifdef __IOS__ (void)name; dispatch_async(dispatch_get_main_queue(), ^{ [App::I->ios_view pick_file_save:value]; }); callback(value, true); #elif __WEB__ webgl_pick_file_save(value, name, [callback = std::move(callback), value](bool success) { callback(value, success); }); #else (void)name; callback(value, false); #endif } }; } namespace pp::platform::legacy { PlatformServices& platform_services() { static LegacyPlatformServices services; return services; } }