280 lines
8.4 KiB
C++
280 lines
8.4 KiB
C++
#include "pch.h"
|
|
#include "platform_apple/apple_platform_services.h"
|
|
#include "platform_legacy/legacy_platform_state.h"
|
|
|
|
#include <memory>
|
|
|
|
#if defined(__APPLE__)
|
|
#include <Foundation/Foundation.h>
|
|
#include "objc_utils.h"
|
|
#if defined(__OBJC__) && defined(__IOS__)
|
|
#import "PanoPainter/AppDelegate.h"
|
|
#import "PanoPainter/GameViewController.h"
|
|
#elif defined(__OBJC__) && defined(__OSX__)
|
|
#import "PanoPainter-OSX/main.h"
|
|
#endif
|
|
#endif
|
|
|
|
namespace pp::platform::apple {
|
|
namespace {
|
|
|
|
#if defined(__IOS__) || defined(__OSX__)
|
|
struct RetainedLegacyAppleDocumentPlatformState final {
|
|
std::unique_ptr<AppleDocumentPlatformServices> services;
|
|
};
|
|
|
|
[[nodiscard]] NSMutableArray<NSString*>* apple_file_types_array(const std::vector<std::string>& file_types)
|
|
{
|
|
NSMutableArray<NSString*>* types = [NSMutableArray arrayWithCapacity:file_types.size()];
|
|
for (const auto& type : file_types)
|
|
{
|
|
[types addObject:[NSString stringWithCString:type.c_str() encoding:NSUTF8StringEncoding]];
|
|
}
|
|
return types;
|
|
}
|
|
|
|
[[nodiscard]] RetainedLegacyAppleDocumentPlatformState& retained_legacy_apple_document_platform_state()
|
|
{
|
|
static RetainedLegacyAppleDocumentPlatformState state;
|
|
return state;
|
|
}
|
|
|
|
#ifdef __IOS__
|
|
[[nodiscard]] AppleDocumentPickerBridge make_legacy_apple_document_picker_bridge()
|
|
{
|
|
const auto& apple_state = active_legacy_apple_state();
|
|
auto* const ios_view = apple_state.ios_view;
|
|
auto* const ios_app = apple_state.ios_app;
|
|
|
|
AppleDocumentPickerBridge bridge;
|
|
bridge.clipboard_text = [ios_view] {
|
|
return [ios_view clipboard_get_string];
|
|
};
|
|
bridge.set_clipboard_text = [ios_view](std::string_view text) {
|
|
const std::string value(text);
|
|
return [ios_view clipboard_set_string:value];
|
|
};
|
|
bridge.set_virtual_keyboard_visible = [ios_view](bool visible) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
if (visible)
|
|
[ios_view show_keyboard];
|
|
else
|
|
[ios_view hide_keyboard];
|
|
});
|
|
};
|
|
bridge.trigger_crash_test = [ios_view] {
|
|
[ios_view crash];
|
|
};
|
|
bridge.start_sonarpen = [ios_app] {
|
|
[ios_app sonarpen_start];
|
|
};
|
|
bridge.acquire_render_context = [ios_view] {
|
|
[ios_view async_lock];
|
|
};
|
|
bridge.release_render_context = [ios_view] {
|
|
[ios_view async_unlock];
|
|
};
|
|
bridge.present_render_context = [ios_view] {
|
|
[ios_view async_swap];
|
|
};
|
|
bridge.bind_main_render_target = [ios_view] {
|
|
[ios_view->glview bindDrawable];
|
|
};
|
|
bridge.display_file = [ios_view](std::string path) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[ios_view display_file:path];
|
|
});
|
|
};
|
|
bridge.share_file = [ios_view](std::string path) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[ios_view share_file:[NSString stringWithUTF8String:path.c_str()]];
|
|
});
|
|
};
|
|
bridge.pick_image = [ios_view](PickedPathCallback callback) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[ios_view pick_photo:callback];
|
|
});
|
|
};
|
|
bridge.pick_file = [ios_view](
|
|
std::vector<std::string> file_types,
|
|
PickedPathCallback callback) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[ios_view pick_file:apple_file_types_array(file_types) then:callback];
|
|
});
|
|
};
|
|
bridge.save_prepared_file = [ios_view](
|
|
std::string path,
|
|
std::string suggested_name,
|
|
PreparedFileCallback callback) {
|
|
(void)suggested_name;
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[ios_view pick_file_save:path];
|
|
});
|
|
callback(path, true);
|
|
};
|
|
return bridge;
|
|
}
|
|
#elif defined(__OSX__)
|
|
[[nodiscard]] AppleDocumentPickerBridge make_legacy_apple_document_picker_bridge()
|
|
{
|
|
const auto& apple_state = active_legacy_apple_state();
|
|
auto* const osx_view = apple_state.osx_view;
|
|
auto* const osx_app = apple_state.osx_app;
|
|
|
|
AppleDocumentPickerBridge bridge;
|
|
bridge.clipboard_text = [osx_view] {
|
|
return [osx_view clipboard_get_string];
|
|
};
|
|
bridge.set_clipboard_text = [osx_view](std::string_view text) {
|
|
const std::string value(text);
|
|
return [osx_view clipboard_set_string:value];
|
|
};
|
|
bridge.share_file = [osx_view](std::string path) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[osx_view share_file:[NSString stringWithUTF8String:path.c_str()]];
|
|
});
|
|
};
|
|
bridge.trigger_crash_test = [osx_view] {
|
|
[osx_view hockeyapp_crash];
|
|
};
|
|
bridge.request_app_close = [osx_view] {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[osx_view close];
|
|
});
|
|
};
|
|
bridge.acquire_render_context = [osx_view] {
|
|
[osx_view async_lock];
|
|
};
|
|
bridge.release_render_context = [osx_view] {
|
|
[osx_view async_unlock];
|
|
};
|
|
bridge.present_render_context = [osx_view] {
|
|
[osx_view async_swap];
|
|
};
|
|
bridge.set_cursor_visible = [osx_view](bool visible) {
|
|
[osx_view show_cursor:visible];
|
|
};
|
|
bridge.save_ui_state = [osx_app] {
|
|
[osx_app save_ui_state];
|
|
};
|
|
bridge.pick_file = [osx_view](
|
|
std::vector<std::string> file_types,
|
|
PickedPathCallback callback) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
const std::string path = [osx_view pick_file:apple_file_types_array(file_types)];
|
|
callback(path);
|
|
});
|
|
};
|
|
bridge.pick_save_file = [osx_view](
|
|
std::vector<std::string> file_types,
|
|
PickedPathCallback callback) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
const std::string path = [osx_view pick_file_save:apple_file_types_array(file_types)];
|
|
callback(path);
|
|
});
|
|
};
|
|
bridge.pick_directory = [osx_view](PickedPathCallback callback) {
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
const std::string path = [osx_view pick_dir];
|
|
callback(path);
|
|
});
|
|
};
|
|
bridge.format_working_directory_path = [](std::string_view path) {
|
|
char path_buffer[4096] = {};
|
|
if (realpath(std::string(path).c_str(), path_buffer))
|
|
return std::string(path_buffer);
|
|
return std::string(path);
|
|
};
|
|
return bridge;
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
}
|
|
|
|
#if defined(__IOS__) || defined(__OSX__)
|
|
[[nodiscard]] PlatformFamily legacy_apple_platform_family()
|
|
{
|
|
#ifdef __IOS__
|
|
return PlatformFamily::ios;
|
|
#else
|
|
return PlatformFamily::macos;
|
|
#endif
|
|
}
|
|
|
|
[[nodiscard]] RetainedLegacyAppleState& active_legacy_apple_state()
|
|
{
|
|
static RetainedLegacyAppleState state;
|
|
return state;
|
|
}
|
|
|
|
[[nodiscard]] AppleDocumentPlatformServices& active_legacy_apple_document_platform_services()
|
|
{
|
|
auto& retained = retained_legacy_apple_document_platform_state();
|
|
if (!retained.services)
|
|
{
|
|
retained.services = std::make_unique<AppleDocumentPlatformServices>(
|
|
legacy_apple_platform_family(),
|
|
make_legacy_apple_document_picker_bridge());
|
|
}
|
|
return *retained.services;
|
|
}
|
|
|
|
[[nodiscard]] PlatformStoragePaths prepare_legacy_apple_storage_paths()
|
|
{
|
|
const auto& apple_state = active_legacy_apple_state();
|
|
#ifdef __IOS__
|
|
[apple_state.ios_view init_dirs];
|
|
#elif defined(__OSX__)
|
|
[apple_state.osx_app init_dirs];
|
|
#endif
|
|
return apple_state.storage_paths;
|
|
}
|
|
|
|
void set_legacy_apple_storage_paths(pp::platform::PlatformStoragePaths paths)
|
|
{
|
|
active_legacy_apple_state().storage_paths = std::move(paths);
|
|
}
|
|
|
|
void set_legacy_apple_state(
|
|
#ifdef __IOS__
|
|
GameViewController* ios_view,
|
|
AppDelegate* ios_app
|
|
#elif defined(__OSX__)
|
|
View* osx_view,
|
|
AppOSX* osx_app
|
|
#endif
|
|
)
|
|
{
|
|
auto& retained = active_legacy_apple_state();
|
|
bool changed = false;
|
|
#ifdef __IOS__
|
|
if (ios_view)
|
|
{
|
|
changed = changed || retained.ios_view != ios_view;
|
|
retained.ios_view = ios_view;
|
|
}
|
|
if (ios_app)
|
|
{
|
|
changed = changed || retained.ios_app != ios_app;
|
|
retained.ios_app = ios_app;
|
|
}
|
|
#elif defined(__OSX__)
|
|
if (osx_view)
|
|
{
|
|
changed = changed || retained.osx_view != osx_view;
|
|
retained.osx_view = osx_view;
|
|
}
|
|
if (osx_app)
|
|
{
|
|
changed = changed || retained.osx_app != osx_app;
|
|
retained.osx_app = osx_app;
|
|
}
|
|
#endif
|
|
if (changed)
|
|
retained_legacy_apple_document_platform_state().services.reset();
|
|
}
|
|
#endif
|
|
|
|
}
|