From 5c1075127b0b40628edcc6dc14f2caea3d71b9c6 Mon Sep 17 00:00:00 2001 From: Stuart Carnie Date: Sun, 4 Nov 2018 09:29:40 -0700 Subject: [PATCH 01/10] chore(metal): Separate legacy GL and Metal source * Forks of Cocoa / Cocoa Touch to *_metal.* version * Reverted original GL Cocoa / Cocoa Touch versions * GL and Metal projects still build --- config.features.h | 2 +- configuration.c | 6 +- gfx/common/metal_common.m | 2 +- gfx/drivers_context/cocoa_gl_ctx_metal.m | 917 ++++++++++++++++++ griffin/griffin.c | 2 +- griffin/griffin_objc.m | 13 +- input/drivers_hid/btstack_hid.c | 2 +- input/input_driver.c | 2 +- pkg/apple/BaseConfig.xcconfig | 3 +- pkg/apple/Metal.xcconfig | 2 +- .../RetroArch_Metal.xcodeproj/project.pbxproj | 142 +-- ui/drivers/cocoa/cocoa_common.h | 57 +- ui/drivers/cocoa/cocoa_common.m | 65 +- ui/drivers/cocoa/cocoa_common_metal.h | 162 ++++ ui/drivers/cocoa/cocoa_common_metal.m | 694 +++++++++++++ ui/drivers/cocoa/ui_cocoa_application.m | 13 +- ui/drivers/cocoa/ui_cocoa_application_metal.m | 73 ++ .../cocoa/ui_cocoa_browser_window_metal.m | 67 ++ ui/drivers/cocoa/ui_cocoa_msg_window.m | 174 ++-- ui/drivers/cocoa/ui_cocoa_msg_window_metal.m | 154 +++ ui/drivers/cocoa/ui_cocoa_window.m | 13 +- ui/drivers/cocoa/ui_cocoa_window_metal.m | 102 ++ ui/drivers/ui_cocoa.h | 2 +- ui/drivers/ui_cocoa.m | 337 ++----- ui/drivers/ui_cocoa_metal.h | 44 + ui/drivers/ui_cocoa_metal.m | 786 +++++++++++++++ ui/drivers/ui_cocoatouch.m | 36 +- ui/drivers/ui_cocoatouch_metal.m | 719 ++++++++++++++ 28 files changed, 3946 insertions(+), 645 deletions(-) create mode 100644 gfx/drivers_context/cocoa_gl_ctx_metal.m create mode 100644 ui/drivers/cocoa/cocoa_common_metal.h create mode 100644 ui/drivers/cocoa/cocoa_common_metal.m create mode 100644 ui/drivers/cocoa/ui_cocoa_application_metal.m create mode 100644 ui/drivers/cocoa/ui_cocoa_browser_window_metal.m create mode 100644 ui/drivers/cocoa/ui_cocoa_msg_window_metal.m create mode 100644 ui/drivers/cocoa/ui_cocoa_window_metal.m create mode 100644 ui/drivers/ui_cocoa_metal.h create mode 100644 ui/drivers/ui_cocoa_metal.m create mode 100644 ui/drivers/ui_cocoatouch_metal.m diff --git a/config.features.h b/config.features.h index 93062366f4..f3e0d85b50 100644 --- a/config.features.h +++ b/config.features.h @@ -308,7 +308,7 @@ static const bool _python_supp = true; static const bool _python_supp = false; #endif -#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) +#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) static const bool _cocoa_supp = true; #else static const bool _cocoa_supp = false; diff --git a/configuration.c b/configuration.c index a9b64bc8cc..0329a77778 100644 --- a/configuration.c +++ b/configuration.c @@ -451,7 +451,7 @@ static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_UDEV; static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_LINUXRAW; #elif defined(HAVE_WAYLAND) static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_WAYLAND; -#elif defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) +#elif defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_COCOA; #elif defined(__QNX__) static enum input_driver_enum INPUT_DEFAULT_DRIVER = INPUT_QNX; @@ -511,7 +511,7 @@ static enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_V4L2; static enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_RWEBCAM; #elif defined(ANDROID) static enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_ANDROID; -#elif defined(HAVE_AVFOUNDATION) && (defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH)) +#elif defined(HAVE_AVFOUNDATION) && (defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL)) static enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_AVFOUNDATION; #else static enum camera_driver_enum CAMERA_DEFAULT_DRIVER = CAMERA_NULL; @@ -525,7 +525,7 @@ static enum wifi_driver_enum WIFI_DEFAULT_DRIVER = WIFI_NULL; #if defined(ANDROID) static enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_ANDROID; -#elif defined(HAVE_CORELOCATION) && (defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH)) +#elif defined(HAVE_CORELOCATION) && (defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL)) static enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_CORELOCATION; #else static enum location_driver_enum LOCATION_DEFAULT_DRIVER = LOCATION_NULL; diff --git a/gfx/common/metal_common.m b/gfx/common/metal_common.m index 3358883392..2c2129d911 100644 --- a/gfx/common/metal_common.m +++ b/gfx/common/metal_common.m @@ -7,7 +7,7 @@ #import #import "metal_common.h" -#import "../../ui/drivers/cocoa/cocoa_common.h" +#import "../../ui/drivers/cocoa/cocoa_common_metal.h" #import #import #import diff --git a/gfx/drivers_context/cocoa_gl_ctx_metal.m b/gfx/drivers_context/cocoa_gl_ctx_metal.m new file mode 100644 index 0000000000..d554ab8385 --- /dev/null +++ b/gfx/drivers_context/cocoa_gl_ctx_metal.m @@ -0,0 +1,917 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2018 - Stuart Carnie + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#if TARGET_OS_IPHONE +#include +#else +#include +#endif +#if defined(HAVE_COCOA_METAL) +#include +#include +#include +#include +#elif defined(HAVE_COCOATOUCH) +#include +#ifdef HAVE_AVFOUNDATION +#import +#endif +#endif + +#include +#include + +#import "../../ui/drivers/cocoa/cocoa_common_metal.h" +#include "../video_driver.h" +#include "../../configuration.h" +#include "../../verbosity.h" +#ifdef HAVE_VULKAN +#include "../common/vulkan_common.h" +#endif + +#if defined(HAVE_COCOATOUCH) +#define GLContextClass EAGLContext +#define GLFrameworkID CFSTR("com.apple.opengles") +#define RAScreen UIScreen + +#ifndef UIUserInterfaceIdiomTV +#define UIUserInterfaceIdiomTV 2 +#endif + +#ifndef UIUserInterfaceIdiomCarPlay +#define UIUserInterfaceIdiomCarPlay 3 +#endif + +@interface EAGLContext (OSXCompat) @end +@implementation EAGLContext (OSXCompat) ++ (void)clearCurrentContext { [EAGLContext setCurrentContext:nil]; } +- (void)makeCurrentContext { [EAGLContext setCurrentContext:self]; } +@end + +#else + +@interface NSScreen (IOSCompat) @end +@implementation NSScreen (IOSCompat) +- (CGRect)bounds +{ + CGRect cgrect = NSRectToCGRect(self.frame); + return CGRectMake(0, 0, CGRectGetWidth(cgrect), CGRectGetHeight(cgrect)); +} +- (float) scale { return 1.0f; } +@end + +#define GLContextClass NSOpenGLContext +#define GLFrameworkID CFSTR("com.apple.opengl") +#define RAScreen NSScreen +#endif + +static enum gfx_ctx_api cocoagl_api = GFX_CTX_NONE; + +typedef struct cocoa_ctx_data +{ + bool core_hw_context_enable; +#ifdef HAVE_VULKAN + gfx_ctx_vulkan_data_t vk; + int swap_interval; +#endif + unsigned width; + unsigned height; +} cocoa_ctx_data_t; + +#if defined(HAVE_COCOATOUCH) + +static GLKView *g_view; +UIView *g_pause_indicator_view; +#endif + +static GLContextClass* g_hw_ctx; +static GLContextClass* g_context; + +static int g_fast_forward_skips; +static bool g_is_syncing = true; +static bool g_use_hw_ctx = false; + +#if defined(HAVE_COCOA_METAL) +#include "../../ui/drivers/ui_cocoa_metal.h" +static NSOpenGLPixelFormat* g_format; + +void *glcontext_get_ptr(void) +{ + return (BRIDGE void *)g_context; +} +#endif + +static unsigned g_minor = 0; +static unsigned g_major = 0; + +/* forward declaration */ +void *nsview_get_ptr(void); + +#if defined(HAVE_COCOATOUCH) +static void glkitview_init_xibs(void) +{ + /* iOS Pause menu and lifecycle. */ + UINib *xib = (UINib*)[UINib nibWithNibName:BOXSTRING("PauseIndicatorView") bundle:nil]; + g_pause_indicator_view = [[xib instantiateWithOwner:[RetroArch_iOS get] options:nil] lastObject]; +} +#endif + +void *glkitview_init(void) +{ +#if defined(HAVE_COCOATOUCH) + glkitview_init_xibs(); + + g_view = [GLKView new]; + g_view.multipleTouchEnabled = YES; + g_view.enableSetNeedsDisplay = NO; + [g_view addSubview:g_pause_indicator_view]; + + return (BRIDGE void *)((GLKView*)g_view); +#else + return nsview_get_ptr(); +#endif +} + +#if defined(HAVE_COCOATOUCH) +void cocoagl_bind_game_view_fbo(void) +{ +#ifdef HAVE_AVFOUNDATION + /* Implicitly initializes your audio session */ + AVAudioSession *audio_session = [AVAudioSession sharedInstance]; + [audio_session setCategory:AVAudioSessionCategoryAmbient error:nil]; + [audio_session setActive:YES error:nil]; +#endif + if (g_context) + [g_view bindDrawable]; +} +#endif + +static float get_from_selector(Class obj_class, id obj_id, SEL selector, CGFloat *ret) +{ + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: + [obj_class instanceMethodSignatureForSelector:selector]]; + [invocation setSelector:selector]; + [invocation setTarget:obj_id]; + [invocation invoke]; + [invocation getReturnValue:ret]; + RELEASE(invocation); + return *ret; +} + +void *get_chosen_screen(void) +{ + settings_t *settings = config_get_ptr(); + NSArray *screens = [RAScreen screens]; + if (!screens || !settings) + return NULL; + + if (settings->uints.video_monitor_index >= screens.count) + { + RARCH_WARN("video_monitor_index is greater than the number of connected monitors; using main screen instead."); + return (BRIDGE void*)screens; + } + + return ((BRIDGE void*)[screens objectAtIndex:settings->uints.video_monitor_index]); +} + + +float get_backing_scale_factor(void) +{ + static float + backing_scale_def = 0.0f; + RAScreen *screen = NULL; + + (void)screen; + + if (backing_scale_def != 0.0f) + return backing_scale_def; + + backing_scale_def = 1.0f; +#ifdef HAVE_COCOA_METAL + screen = (BRIDGE RAScreen*)get_chosen_screen(); + + if (screen) + { + SEL selector = NSSelectorFromString(BOXSTRING("backingScaleFactor")); + if ([screen respondsToSelector:selector]) + { + CGFloat ret; + NSView *g_view = apple_platform.renderView; + //CocoaView *g_view = (CocoaView*)nsview_get_ptr(); + backing_scale_def = (float)get_from_selector + ([[g_view window] class], [g_view window], selector, &ret); + } + } +#endif + + return backing_scale_def; +} + +void cocoagl_gfx_ctx_update(void) +{ + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: +#if defined(HAVE_COCOA_METAL) +#if MAC_OS_X_VERSION_10_7 + CGLUpdateContext(g_hw_ctx.CGLContextObj); + CGLUpdateContext(g_context.CGLContextObj); +#else + [g_hw_ctx update]; + [g_context update]; +#endif +#endif + break; + default: + break; + } +} + +static void cocoagl_gfx_ctx_destroy(void *data) +{ + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; + + if (!cocoa_ctx) + return; + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + [GLContextClass clearCurrentContext]; + +#if defined(HAVE_COCOA_METAL) + [g_context clearDrawable]; + RELEASE(g_context); + RELEASE(g_format); + if (g_hw_ctx) + { + [g_hw_ctx clearDrawable]; + } + RELEASE(g_hw_ctx); +#endif + [GLContextClass clearCurrentContext]; + g_context = nil; + break; + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + vulkan_context_destroy(&cocoa_ctx->vk, cocoa_ctx->vk.vk_surface != VK_NULL_HANDLE); + if (cocoa_ctx->vk.context.queue_lock) { + slock_free(cocoa_ctx->vk.context.queue_lock); + } + memset(&cocoa_ctx->vk, 0, sizeof(cocoa_ctx->vk)); + +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + + free(cocoa_ctx); +} + +static void *cocoagl_gfx_ctx_init(video_frame_info_t *video_info, void *video_driver) +{ + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*) + calloc(1, sizeof(cocoa_ctx_data_t)); + + if (!cocoa_ctx) + return NULL; + + switch (cocoagl_api) + { +#if defined(HAVE_COCOATOUCH) + case GFX_CTX_OPENGL_ES_API: + // setViewType is not (yet?) defined for iOS + // [apple_platform setViewType:APPLE_VIEW_TYPE_OPENGL_ES]; + break; +#elif defined(HAVE_COCOA_METAL) + case GFX_CTX_OPENGL_API: + [apple_platform setViewType:APPLE_VIEW_TYPE_OPENGL]; + break; +#endif + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + [apple_platform setViewType:APPLE_VIEW_TYPE_VULKAN]; + if (!vulkan_context_init(&cocoa_ctx->vk, VULKAN_WSI_MVK_MACOS)) + { + goto error; + } +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + + return cocoa_ctx; + +error: + free(cocoa_ctx); + return NULL; +} + +static enum gfx_ctx_api cocoagl_gfx_ctx_get_api(void *data) +{ + return cocoagl_api; +} + +static bool cocoagl_gfx_ctx_bind_api(void *data, enum gfx_ctx_api api, unsigned major, unsigned minor) +{ + (void)data; + switch (api) + { +#if defined(HAVE_COCOATOUCH) + case GFX_CTX_OPENGL_ES_API: + break; +#elif defined(HAVE_COCOA_METAL) + case GFX_CTX_OPENGL_API: + break; +#ifdef HAVE_VULKAN + case GFX_CTX_VULKAN_API: + break; +#endif +#endif + case GFX_CTX_NONE: + default: + return false; + } + + cocoagl_api = api; + g_minor = minor; + g_major = major; + + return true; +} + +static void cocoagl_gfx_ctx_swap_interval(void *data, int interval) +{ +#ifdef HAVE_VULKAN + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; +#endif + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + { +#if defined(HAVE_COCOATOUCH) // < No way to disable Vsync on iOS? + // Just skip presents so fast forward still works. + g_is_syncing = interval ? true : false; + g_fast_forward_skips = interval ? 0 : 3; +#elif defined(HAVE_COCOA_METAL) + GLint value = interval ? 1 : 0; + [g_context setValues:&value forParameter:NSOpenGLCPSwapInterval]; +#endif + break; + } + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + if (cocoa_ctx->swap_interval != interval) + { + cocoa_ctx->swap_interval = interval; + if (cocoa_ctx->vk.swapchain) + { + cocoa_ctx->vk.need_new_swapchain = true; + } + } +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + +} + +static void cocoagl_gfx_ctx_show_mouse(void *data, bool state) +{ + (void)data; + +#ifdef HAVE_COCOA_METAL + if (state) + [NSCursor unhide]; + else + [NSCursor hide]; +#endif +} + +static bool cocoagl_gfx_ctx_set_video_mode(void *data, + video_frame_info_t *video_info, + unsigned width, unsigned height, bool fullscreen) +{ + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; + cocoa_ctx->width = width; + cocoa_ctx->height = height; + +#if defined(HAVE_COCOA_METAL) + //CocoaView *g_view = (BRIDGE CocoaView *)nsview_get_ptr(); + NSView *g_view = apple_platform.renderView; +#endif + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + { +#if defined(HAVE_COCOA_METAL) + if ([g_view respondsToSelector: @selector(setWantsBestResolutionOpenGLSurface:)]) + [g_view setWantsBestResolutionOpenGLSurface:YES]; + + NSOpenGLPixelFormatAttribute attributes [] = { + NSOpenGLPFAColorSize, + 24, + NSOpenGLPFADoubleBuffer, + NSOpenGLPFAAllowOfflineRenderers, + NSOpenGLPFADepthSize, + (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer + 0, /* profile */ + 0, /* profile enum */ + (NSOpenGLPixelFormatAttribute)0 + }; + +#if MAC_OS_X_VERSION_10_7 + if (g_major == 3 && (g_minor >= 1 && g_minor <= 3)) + { + attributes[6] = NSOpenGLPFAOpenGLProfile; + attributes[7] = NSOpenGLProfileVersion3_2Core; + } +#endif + +#if MAC_OS_X_VERSION_10_10 + if (g_major == 4 && g_minor == 1) + { + attributes[6] = NSOpenGLPFAOpenGLProfile; + attributes[7] = NSOpenGLProfileVersion4_1Core; + } +#endif + + g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 + if (g_format == nil) + { + /* NSOpenGLFPAAllowOfflineRenderers is + not supported on this OS version. */ + attributes[3] = (NSOpenGLPixelFormatAttribute)0; + g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; + } +#endif + + if (g_use_hw_ctx) + g_hw_ctx = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:nil]; + g_context = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:(g_use_hw_ctx) ? g_hw_ctx : nil]; + [g_context setView:g_view]; +#else + if (g_use_hw_ctx) + g_hw_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + g_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; + g_view.context = g_context; +#endif + + [g_context makeCurrentContext]; + break; + } + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + RARCH_LOG("[macOS]: Native window size: %u x %u.\n", cocoa_ctx->width, cocoa_ctx->height); + if (!vulkan_surface_create(&cocoa_ctx->vk, + VULKAN_WSI_MVK_MACOS, NULL, + (BRIDGE void *)g_view, cocoa_ctx->width, cocoa_ctx->height, + cocoa_ctx->swap_interval)) + { + RARCH_ERR("[macOS]: Failed to create surface.\n"); + return false; + } +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + +#if defined(HAVE_COCOA_METAL) + static bool has_went_fullscreen = false; + /* TODO: Screen mode support. */ + + if (fullscreen) + { + if (!has_went_fullscreen) + { + [g_view enterFullScreenMode:(BRIDGE NSScreen *)get_chosen_screen() withOptions:nil]; + cocoagl_gfx_ctx_show_mouse(data, false); + } + } + else + { + if (has_went_fullscreen) + { + [g_view exitFullScreenModeWithOptions:nil]; + [[g_view window] makeFirstResponder:g_view]; + cocoagl_gfx_ctx_show_mouse(data, true); + } + + [[g_view window] setContentSize:NSMakeSize(width, height)]; + } + + has_went_fullscreen = fullscreen; +#endif + + /* TODO: Maybe iOS users should be able to show/hide the status bar here? */ + + return true; +} + +float cocoagl_gfx_ctx_get_native_scale(void) +{ + static CGFloat ret = 0.0f; + SEL selector = NSSelectorFromString(BOXSTRING("nativeScale")); + RAScreen *screen = (BRIDGE RAScreen*)get_chosen_screen(); + + if (ret != 0.0f) + return ret; + if (!screen) + return 0.0f; + + if ([screen respondsToSelector:selector]) + return (float)get_from_selector([screen class], screen, selector, &ret); + + ret = 1.0f; + selector = NSSelectorFromString(BOXSTRING("scale")); + if ([screen respondsToSelector:selector]) + ret = screen.scale; + return ret; +} + +static void cocoagl_gfx_ctx_get_video_size(void *data, unsigned* width, unsigned* height) +{ + float screenscale = cocoagl_gfx_ctx_get_native_scale(); +#if defined(HAVE_COCOA_METAL) + CGRect size; + GLsizei backingPixelWidth, backingPixelHeight; + NSView *g_view = apple_platform.renderView; + //CocoaView *g_view = (CocoaView*)nsview_get_ptr(); + CGRect cgrect = NSRectToCGRect([g_view frame]); +#if MAC_OS_X_VERSION_10_7 + SEL selector = NSSelectorFromString(BOXSTRING("convertRectToBacking:")); + if ([g_view respondsToSelector:selector]) + cgrect = NSRectToCGRect([g_view convertRectToBacking:[g_view bounds]]); +#endif + backingPixelWidth = CGRectGetWidth(cgrect); + backingPixelHeight = CGRectGetHeight(cgrect); + size = CGRectMake(0, 0, backingPixelWidth, backingPixelHeight); +#else + CGRect size = g_view.bounds; +#endif + *width = CGRectGetWidth(size) * screenscale; + *height = CGRectGetHeight(size) * screenscale; +} + +#if defined(HAVE_COCOA_METAL) +static void cocoagl_gfx_ctx_update_title(void *data, void *data2) +{ + ui_window_cocoa_t view; + const ui_window_t *window = ui_companion_driver_get_window_ptr(); + + //view.data = (CocoaView*)nsview_get_ptr(); + view.data = (BRIDGE void *)apple_platform.renderView; + + if (window) + { + char title[128]; + + title[0] = '\0'; + + video_driver_get_window_title(title, sizeof(title)); + + if (title[0]) + window->set_title(&view, title); + } +} +#endif + +static bool cocoagl_gfx_ctx_get_metrics(void *data, enum display_metric_types type, + float *value) +{ + RAScreen *screen = (BRIDGE RAScreen*)get_chosen_screen(); +#if defined(HAVE_COCOA_METAL) + NSDictionary *description = [screen deviceDescription]; + NSSize display_pixel_size = [[description objectForKey:NSDeviceSize] sizeValue]; + CGSize display_physical_size = CGDisplayScreenSize( + [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); + + float display_width = display_pixel_size.width; + float display_height = display_pixel_size.height; + float physical_width = display_physical_size.width; + float physical_height = display_physical_size.height; + float scale = get_backing_scale_factor(); + float dpi = (display_width/ physical_width) * 25.4f * scale; +#elif defined(HAVE_COCOATOUCH) + float scale = cocoagl_gfx_ctx_get_native_scale(); + CGRect screen_rect = [screen bounds]; + float display_height = screen_rect.size.height; + float physical_width = screen_rect.size.width * scale; + float physical_height = screen_rect.size.height * scale; + float dpi = 160 * scale; + unsigned idiom_type = UI_USER_INTERFACE_IDIOM(); + + switch (idiom_type) + { + case -1: /* UIUserInterfaceIdiomUnspecified */ + /* TODO */ + break; + case UIUserInterfaceIdiomPad: + dpi = 132 * scale; + break; + case UIUserInterfaceIdiomPhone: + dpi = 163 * scale; + break; + case UIUserInterfaceIdiomTV: + case UIUserInterfaceIdiomCarPlay: + /* TODO */ + break; + } +#endif + + (void)display_height; + + switch (type) + { + case DISPLAY_METRIC_MM_WIDTH: + *value = physical_width; + break; + case DISPLAY_METRIC_MM_HEIGHT: + *value = physical_height; + break; + case DISPLAY_METRIC_DPI: + *value = dpi; + break; + case DISPLAY_METRIC_NONE: + default: + *value = 0; + return false; + } + + return true; +} + +static bool cocoagl_gfx_ctx_has_focus(void *data) +{ + (void)data; +#if defined(HAVE_COCOATOUCH) + return ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive); +#else + return [NSApp isActive]; +#endif +} + +static bool cocoagl_gfx_ctx_suppress_screensaver(void *data, bool enable) +{ + (void)data; + (void)enable; + + return false; +} + +#if !defined(HAVE_COCOATOUCH) +static bool cocoagl_gfx_ctx_has_windowed(void *data) +{ + return true; +} +#endif + +#ifdef HAVE_VULKAN +static void *cocoagl_gfx_ctx_get_context_data(void *data) +{ + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; + return &cocoa_ctx->vk.context; +} +#endif + + +static void cocoagl_gfx_ctx_swap_buffers(void *data, void *data2) +{ +#ifdef HAVE_VULKAN + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; +#endif + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + if (!(--g_fast_forward_skips < 0)) + return; + +#if defined(HAVE_COCOA_METAL) + [g_context flushBuffer]; + [g_hw_ctx flushBuffer]; +#elif defined(HAVE_COCOATOUCH) + if (g_view) + [g_view display]; +#endif + + g_fast_forward_skips = g_is_syncing ? 0 : 3; + break; + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + vulkan_present(&cocoa_ctx->vk, cocoa_ctx->vk.context.current_swapchain_index); + vulkan_acquire_next_image(&cocoa_ctx->vk); +#endif + break; + case GFX_CTX_NONE: + default: + break; + } +} + +static gfx_ctx_proc_t cocoagl_gfx_ctx_get_proc_address(const char *symbol_name) +{ + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + return (gfx_ctx_proc_t)CFBundleGetFunctionPointerForName(CFBundleGetBundleWithIdentifier(GLFrameworkID), + (BRIDGE CFStringRef)BOXSTRING(symbol_name) + ); + case GFX_CTX_NONE: + default: + break; + } + + return NULL; +} + +static bool cocoagl_gfx_ctx_set_resize(void *data, unsigned width, unsigned height) +{ +#ifdef HAVE_VULKAN + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; +#endif + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + break; + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + cocoa_ctx->width = width; + cocoa_ctx->height = height; + + if (vulkan_create_swapchain(&cocoa_ctx->vk, + width, height, cocoa_ctx->swap_interval)) + { + cocoa_ctx->vk.context.invalid_swapchain = true; + if (cocoa_ctx->vk.created_new_swapchain) + vulkan_acquire_next_image(&cocoa_ctx->vk); + } + else + { + RARCH_ERR("[macOS/Vulkan]: Failed to update swapchain.\n"); + return false; + } + + cocoa_ctx->vk.need_new_swapchain = false; +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + + return true; +} + + +static void cocoagl_gfx_ctx_check_window(void *data, bool *quit, + bool *resize, unsigned *width, unsigned *height, bool is_shutdown) +{ + unsigned new_width, new_height; +#ifdef HAVE_VULKAN + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; +#endif + + *quit = false; + + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + break; + case GFX_CTX_VULKAN_API: +#ifdef HAVE_VULKAN + *resize = cocoa_ctx->vk.need_new_swapchain; +#endif + break; + case GFX_CTX_NONE: + default: + break; + } + + cocoagl_gfx_ctx_get_video_size(data, &new_width, &new_height); + if (new_width != *width || new_height != *height) + { + *width = new_width; + *height = new_height; + *resize = true; + } +} + +static void cocoagl_gfx_ctx_input_driver(void *data, + const char *name, + const input_driver_t **input, void **input_data) +{ + *input = NULL; + *input_data = NULL; +} + +static void cocoagl_gfx_ctx_bind_hw_render(void *data, bool enable) +{ + (void)data; + switch (cocoagl_api) + { + case GFX_CTX_OPENGL_API: + case GFX_CTX_OPENGL_ES_API: + g_use_hw_ctx = enable; + + if (enable) + [g_hw_ctx makeCurrentContext]; + else + [g_context makeCurrentContext]; + break; + case GFX_CTX_NONE: + default: + break; + } +} + +static uint32_t cocoagl_gfx_ctx_get_flags(void *data) +{ + uint32_t flags = 0; + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; + + BIT32_SET(flags, GFX_CTX_FLAGS_NONE); + + if (cocoa_ctx->core_hw_context_enable) + BIT32_SET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT); + + return flags; +} + +static void cocoagl_gfx_ctx_set_flags(void *data, uint32_t flags) +{ + (void)flags; + cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; + + if (BIT32_GET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT)) + cocoa_ctx->core_hw_context_enable = true; +} + +const gfx_ctx_driver_t gfx_ctx_cocoagl = { + .init = cocoagl_gfx_ctx_init, + .destroy = cocoagl_gfx_ctx_destroy, + .get_api = cocoagl_gfx_ctx_get_api, + .bind_api = cocoagl_gfx_ctx_bind_api, + .swap_interval = cocoagl_gfx_ctx_swap_interval, + .set_video_mode = cocoagl_gfx_ctx_set_video_mode, + .get_video_size = cocoagl_gfx_ctx_get_video_size, + .get_metrics = cocoagl_gfx_ctx_get_metrics, +#if defined(HAVE_COCOA_METAL) + .update_window_title = cocoagl_gfx_ctx_update_title, +#endif + .check_window = cocoagl_gfx_ctx_check_window, + .set_resize = cocoagl_gfx_ctx_set_resize, + .has_focus = cocoagl_gfx_ctx_has_focus, + .suppress_screensaver = cocoagl_gfx_ctx_suppress_screensaver, +#if !defined(HAVE_COCOATOUCH) + .has_windowed = cocoagl_gfx_ctx_has_windowed, +#endif + .swap_buffers = cocoagl_gfx_ctx_swap_buffers, + .input_driver = cocoagl_gfx_ctx_input_driver, + .get_proc_address = cocoagl_gfx_ctx_get_proc_address, + .ident = "macOS", + .get_flags = cocoagl_gfx_ctx_get_flags, + .set_flags = cocoagl_gfx_ctx_set_flags, + .bind_hw_render = cocoagl_gfx_ctx_bind_hw_render, +#if defined(HAVE_VULKAN) + .get_context_data = cocoagl_gfx_ctx_get_context_data, +#else + .get_context_data = NULL, +#endif +}; diff --git a/griffin/griffin.c b/griffin/griffin.c index e063951f5c..f84450d833 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -567,7 +567,7 @@ INPUT #elif defined(SN_TARGET_PSP2) || defined(PSP) || defined(VITA) #include "../input/drivers/psp_input.c" #include "../input/drivers_joypad/psp_joypad.c" -#elif defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) +#elif defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) #include "../input/drivers/cocoa_input.c" #elif defined(_3DS) #include "../input/drivers/ctr_input.c" diff --git a/griffin/griffin_objc.m b/griffin/griffin_objc.m index 1393d61bf1..f11512e7a4 100644 --- a/griffin/griffin_objc.m +++ b/griffin/griffin_objc.m @@ -27,9 +27,14 @@ #include "../frontend/drivers/platform_darwin.m" #endif +#if defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) #if defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA) -#include "../gfx/drivers_context/macos_ctx.m" +#include "../gfx/drivers_context/cocoa_gl_ctx.m" #include "../ui/drivers/cocoa/cocoa_common.m" +#else +#include "../gfx/drivers_context/cocoa_gl_ctx_metal.m" +#include "../ui/drivers/cocoa/cocoa_common_metal.m" +#endif #if defined(HAVE_COCOATOUCH) @@ -45,6 +50,12 @@ #include "../ui/drivers/cocoa/ui_cocoa_window.m" #include "../ui/drivers/cocoa/ui_cocoa_msg_window.m" #include "../ui/drivers/cocoa/ui_cocoa_application.m" +#elif defined(HAVE_COCOA_METAL) +#include "../ui/drivers/ui_cocoa_metal.m" +#include "../ui/drivers/cocoa/ui_cocoa_browser_window_metal.m" +#include "../ui/drivers/cocoa/ui_cocoa_window_metal.m" +#include "../ui/drivers/cocoa/ui_cocoa_msg_window_metal.m" +#include "../ui/drivers/cocoa/ui_cocoa_application_metal.m" #endif #endif diff --git a/input/drivers_hid/btstack_hid.c b/input/drivers_hid/btstack_hid.c index fb701e7505..cf7e1cf6c9 100644 --- a/input/drivers_hid/btstack_hid.c +++ b/input/drivers_hid/btstack_hid.c @@ -1284,7 +1284,7 @@ static bool btstack_try_load(void) } #endif -#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) +#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) run_loop_init_ptr(RUN_LOOP_COCOA); #else run_loop_init_ptr(RUN_LOOP_POSIX); diff --git a/input/input_driver.c b/input/input_driver.c index f49fd829fe..4a6a6fb8b5 100644 --- a/input/input_driver.c +++ b/input/input_driver.c @@ -122,7 +122,7 @@ static const input_driver_t *input_drivers[] = { #if defined(__linux__) && !defined(ANDROID) &input_linuxraw, #endif -#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) +#if defined(HAVE_COCOA) || defined(HAVE_COCOATOUCH) || defined(HAVE_COCOA_METAL) &input_cocoa, #endif #ifdef __QNX__ diff --git a/pkg/apple/BaseConfig.xcconfig b/pkg/apple/BaseConfig.xcconfig index 0ff10b6737..70ab0271c1 100644 --- a/pkg/apple/BaseConfig.xcconfig +++ b/pkg/apple/BaseConfig.xcconfig @@ -4,8 +4,7 @@ // // Created by Stuart Carnie on 5/10/18. // - -OTHER_CFLAGS = $(inherited) -DHAVE_RUNAHEAD -DHAVE_GRIFFIN -DHAVE_FLAC -DHAVE_DR_FLAC -DHAVE_DR_MP3 -DHAVE_LROUND -DFLAC__HAS_OGG=0 -DHAVE_CHD -DHAVE_STB_VORBIS -DHAVE_MINIUPNPC -DHAVE_BUILTINMINIUPNPC -DHAVE_UPDATE_ASSETS -DHAVE_LANGEXTRA -DHAVE_CHEEVOS -DHAVE_IMAGEVIEWER -DHAVE_IOHIDMANAGER -DHAVE_CORETEXT -DHAVE_RGUI -DHAVE_MENU -DOSX -DHAVE_OPENGL -DHAVE_CC_RESAMPLER -DHAVE_GLSL -DINLINE=inline -D__LIBRETRO__ -DHAVE_COREAUDIO -DHAVE_DYNAMIC -DHAVE_OVERLAY -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_COCOA -DHAVE_NETWORKGAMEPAD -DHAVE_NETWORKING -DRARCH_INTERNAL -DHAVE_THREADS -DHAVE_DYLIB -DHAVE_7ZIP -DHAVE_MATERIALUI -DHAVE_HID -DHAVE_XMB -DHAVE_SEGA -DHAVE_SHADERPIPELINE -DHAVE_MMAP -DHAVE_LIBRETRODB -DHAVE_GETOPT_LONG -DHAVE_METAL -DHAVE_SLANG -DHAVE_GLSLANG -DHAVE_SPIRV_CROSS -DWANT_GLSLANG -DENABLE_HLSL -DGLSLANG_OSINCLUDE_UNIX -DMETAL_DEBUG +OTHER_CFLAGS = $(inherited) -DHAVE_RUNAHEAD -DHAVE_GRIFFIN -DHAVE_FLAC -DHAVE_DR_FLAC -DHAVE_DR_MP3 -DHAVE_LROUND -DFLAC__HAS_OGG=0 -DHAVE_CHD -DHAVE_STB_VORBIS -DHAVE_MINIUPNPC -DHAVE_BUILTINMINIUPNPC -DHAVE_UPDATE_ASSETS -DHAVE_LANGEXTRA -DRC_DISABLE_LUA -DHAVE_CHEEVOS -DHAVE_IMAGEVIEWER -DHAVE_IOHIDMANAGER -DHAVE_CORETEXT -DHAVE_RGUI -DHAVE_MENU -DOSX -DHAVE_CC_RESAMPLER -DHAVE_GLSL -DINLINE=inline -D__LIBRETRO__ -DHAVE_COREAUDIO -DHAVE_DYNAMIC -DHAVE_OVERLAY -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_RJPEG -DHAVE_RBMP -DHAVE_RTGA -DHAVE_NETWORKGAMEPAD -DHAVE_NETWORKING -DHAVE_NETPLAYDISCOVERY -DRARCH_INTERNAL -DHAVE_THREADS -DHAVE_DYLIB -DHAVE_7ZIP -DHAVE_MATERIALUI -DHAVE_HID -DHAVE_XMB -DHAVE_SEGA -DHAVE_SHADERPIPELINE -DHAVE_MMAP -DHAVE_LIBRETRODB -DHAVE_GETOPT_LONG -DHAVE_METAL -DHAVE_SLANG -DHAVE_GLSLANG -DHAVE_SPIRV_CROSS -DWANT_GLSLANG -DENABLE_HLSL -DGLSLANG_OSINCLUDE_UNIX -DMETAL_DEBUG -DHAVE_OPENGL SRCBASE = $(SRCROOT)/../.. DEPS_DIR = $(SRCBASE)/deps diff --git a/pkg/apple/Metal.xcconfig b/pkg/apple/Metal.xcconfig index 27d22dd265..1168500099 100644 --- a/pkg/apple/Metal.xcconfig +++ b/pkg/apple/Metal.xcconfig @@ -5,5 +5,5 @@ // Created by Stuart Carnie on 5/10/18. // -OTHER_CFLAGS = $(inherited) -DHAVE_MAIN +OTHER_CFLAGS = $(inherited) -DHAVE_MAIN -DHAVE_COCOA_METAL diff --git a/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj index 471b781c50..5475e66f4d 100644 --- a/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj @@ -548,10 +548,20 @@ 84DD5EB71A89F1C7007336C1 /* retroarch.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = retroarch.icns; path = ../../media/retroarch.icns; sourceTree = ""; }; 8D1107320486CEB800E47090 /* RetroArch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = RetroArch.app; sourceTree = BUILT_PRODUCTS_DIR; }; A902040DE66D42F9EE47BFE3 /* MenuDisplay.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuDisplay.h; sourceTree = ""; }; + A90205DCA5102DF8D80D3F68 /* ui_cocoa_metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ui_cocoa_metal.h; sourceTree = ""; }; A90205FD4D5979BD8B7E4DD6 /* Info_Metal.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.info; name = Info_Metal.plist; path = OSX/Info_Metal.plist; sourceTree = ""; }; A902065A41AEBECE594908C7 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = OSX/en.lproj/MainMenu_Metal.xib; sourceTree = ""; }; A902070F2C43F222FD56A95A /* MenuDisplay.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuDisplay.m; sourceTree = ""; }; A90207489289602F593626D5 /* QTConfig.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = QTConfig.xcconfig; sourceTree = ""; }; + A90208A05A895029CEC32C14 /* ui_cocoa_msg_window_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ui_cocoa_msg_window_metal.m; sourceTree = ""; }; + A9020AF14B9A73364C6CDDA5 /* cocoa_common_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = cocoa_common_metal.m; sourceTree = ""; }; + A9020BD6594399DDAB0E2563 /* ui_cocoatouch_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ui_cocoatouch_metal.m; sourceTree = ""; }; + A9020C55D864F0E0C6E7DFF9 /* ui_cocoa_window_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ui_cocoa_window_metal.m; sourceTree = ""; }; + A9020E880B5DBFD909921A8F /* cocoa_common_metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cocoa_common_metal.h; sourceTree = ""; }; + A9020EE4BE2C6A15024A32E0 /* ui_cocoa_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ui_cocoa_metal.m; sourceTree = ""; }; + A9020F2EEF870903107B0EA7 /* ui_cocoa_application_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ui_cocoa_application_metal.m; sourceTree = ""; }; + A9020F48BA562B13D4789292 /* ui_cocoa_browser_window_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ui_cocoa_browser_window_metal.m; sourceTree = ""; }; + A9020FA64527ED74C836B41D /* cocoa_gl_ctx_metal.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = cocoa_gl_ctx_metal.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -932,6 +942,9 @@ 05366511213F8BE5007E7EA0 /* qt */, 05A8C5CE20DB72F000FF7857 /* ui_cocoa.h */, 05A8C5BA20DB72F000FF7857 /* ui_cocoa.m */, + A90205DCA5102DF8D80D3F68 /* ui_cocoa_metal.h */, + A9020EE4BE2C6A15024A32E0 /* ui_cocoa_metal.m */, + A9020BD6594399DDAB0E2563 /* ui_cocoatouch_metal.m */, 05A8C5CF20DB72F000FF7857 /* ui_cocoatouch.m */, 05A8C5B920DB72F000FF7857 /* ui_null.c */, 05A8C5D020DB72F000FF7857 /* ui_qt.cpp */, @@ -946,12 +959,18 @@ 05A8C5BB20DB72F000FF7857 /* cocoa */ = { isa = PBXGroup; children = ( + A9020E880B5DBFD909921A8F /* cocoa_common_metal.h */, + A9020AF14B9A73364C6CDDA5 /* cocoa_common_metal.m */, 05A8C5C220DB72F000FF7857 /* cocoa_common.h */, 05A8C5BD20DB72F000FF7857 /* cocoa_common.m */, 05A8C5BE20DB72F000FF7857 /* cocoatouch_menu.m */, + A9020F2EEF870903107B0EA7 /* ui_cocoa_application_metal.m */, 05A8C5C120DB72F000FF7857 /* ui_cocoa_application.m */, + A9020F48BA562B13D4789292 /* ui_cocoa_browser_window_metal.m */, 05A8C5BF20DB72F000FF7857 /* ui_cocoa_browser_window.m */, + A90208A05A895029CEC32C14 /* ui_cocoa_msg_window_metal.m */, 05A8C5BC20DB72F000FF7857 /* ui_cocoa_msg_window.m */, + A9020C55D864F0E0C6E7DFF9 /* ui_cocoa_window_metal.m */, 05A8C5C020DB72F000FF7857 /* ui_cocoa_window.m */, ); path = cocoa; @@ -996,6 +1015,7 @@ children = ( 05A8C5E720DB72F000FF7857 /* cocoa_gl_ctx.m */, 05A8C5DD20DB72F000FF7857 /* macos_ctx.m */, + A9020FA64527ED74C836B41D /* cocoa_gl_ctx_metal.m */, ); path = drivers_context; sourceTree = ""; @@ -1790,67 +1810,6 @@ ); MACOSX_DEPLOYMENT_TARGET = 10.13; ONLY_ACTIVE_ARCH = YES; - OTHER_CFLAGS = ( - "$(inherited)", - "-DHAVE_RUNAHEAD", - "-DHAVE_GRIFFIN", - "-DHAVE_FLAC", - "-DHAVE_DR_FLAC", - "-DHAVE_DR_MP3", - "-DHAVE_LROUND", - "-DFLAC__HAS_OGG=0", - "-DHAVE_CHD", - "-DHAVE_STB_VORBIS", - "-DHAVE_MINIUPNPC", - "-DHAVE_BUILTINMINIUPNPC", - "-DHAVE_UPDATE_ASSETS", - "-DHAVE_LANGEXTRA", - "-DRC_DISABLE_LUA", - "-DHAVE_CHEEVOS", - "-DHAVE_IMAGEVIEWER", - "-DHAVE_IOHIDMANAGER", - "-DHAVE_CORETEXT", - "-DHAVE_RGUI", - "-DHAVE_MENU", - "-DOSX", - "-DHAVE_OPENGL", - "-DHAVE_CC_RESAMPLER", - "-DHAVE_GLSL", - "-DINLINE=inline", - "-D__LIBRETRO__", - "-DHAVE_COREAUDIO", - "-DHAVE_DYNAMIC", - "-DHAVE_OVERLAY", - "-DHAVE_ZLIB", - "-DHAVE_RPNG", - "-DHAVE_RJPEG", - "-DHAVE_RBMP", - "-DHAVE_RTGA", - "-DHAVE_COCOA", - "-DHAVE_NETWORKGAMEPAD", - "-DHAVE_NETWORKING", - "-DHAVE_NETPLAYDISCOVERY", - "-DRARCH_INTERNAL", - "-DHAVE_THREADS", - "-DHAVE_DYLIB", - "-DHAVE_7ZIP", - "-DHAVE_MATERIALUI", - "-DHAVE_HID", - "-DHAVE_XMB", - "-DHAVE_SEGA", - "-DHAVE_SHADERPIPELINE", - "-DHAVE_MMAP", - "-DHAVE_LIBRETRODB", - "-DHAVE_GETOPT_LONG", - "-DHAVE_METAL", - "-DHAVE_SLANG", - "-DHAVE_GLSLANG", - "-DHAVE_SPIRV_CROSS", - "-DWANT_GLSLANG", - "-DENABLE_HLSL", - "-DGLSLANG_OSINCLUDE_UNIX", - "-DMETAL_DEBUG", - ); PREBINDING = NO; SDKROOT = macosx; }; @@ -1905,67 +1864,6 @@ "$(DEPS_DIR)/glslang/glslang/glslang/OSDependent/Unix", ); MACOSX_DEPLOYMENT_TARGET = 10.13; - OTHER_CFLAGS = ( - "$(inherited)", - "-DHAVE_RUNAHEAD", - "-DHAVE_GRIFFIN", - "-DHAVE_FLAC", - "-DHAVE_DR_FLAC", - "-DHAVE_DR_MP3", - "-DHAVE_LROUND", - "-DFLAC__HAS_OGG=0", - "-DHAVE_CHD", - "-DHAVE_STB_VORBIS", - "-DHAVE_MINIUPNPC", - "-DHAVE_BUILTINMINIUPNPC", - "-DHAVE_UPDATE_ASSETS", - "-DHAVE_LANGEXTRA", - "-DRC_DISABLE_LUA", - "-DHAVE_CHEEVOS", - "-DHAVE_IMAGEVIEWER", - "-DHAVE_IOHIDMANAGER", - "-DHAVE_CORETEXT", - "-DHAVE_RGUI", - "-DHAVE_MENU", - "-DOSX", - "-DHAVE_OPENGL", - "-DHAVE_CC_RESAMPLER", - "-DHAVE_GLSL", - "-DINLINE=inline", - "-D__LIBRETRO__", - "-DHAVE_COREAUDIO", - "-DHAVE_DYNAMIC", - "-DHAVE_OVERLAY", - "-DHAVE_ZLIB", - "-DHAVE_RPNG", - "-DHAVE_RJPEG", - "-DHAVE_RBMP", - "-DHAVE_RTGA", - "-DHAVE_COCOA", - "-DHAVE_NETWORKGAMEPAD", - "-DHAVE_NETWORKING", - "-DHAVE_NETPLAYDISCOVERY", - "-DRARCH_INTERNAL", - "-DHAVE_THREADS", - "-DHAVE_DYLIB", - "-DHAVE_7ZIP", - "-DHAVE_MATERIALUI", - "-DHAVE_HID", - "-DHAVE_XMB", - "-DHAVE_SEGA", - "-DHAVE_SHADERPIPELINE", - "-DHAVE_MMAP", - "-DHAVE_LIBRETRODB", - "-DHAVE_GETOPT_LONG", - "-DHAVE_METAL", - "-DHAVE_SLANG", - "-DHAVE_GLSLANG", - "-DHAVE_SPIRV_CROSS", - "-DWANT_GLSLANG", - "-DENABLE_HLSL", - "-DGLSLANG_OSINCLUDE_UNIX", - "-DMETAL_DEBUG", - ); PREBINDING = NO; SDKROOT = macosx; }; diff --git a/ui/drivers/cocoa/cocoa_common.h b/ui/drivers/cocoa/cocoa_common.h index a291b769b3..be2aee7595 100644 --- a/ui/drivers/cocoa/cocoa_common.h +++ b/ui/drivers/cocoa/cocoa_common.h @@ -14,8 +14,8 @@ * If not, see . */ -#ifndef __COCOA_COMMON_H -#define __COCOA_COMMON_H +#ifndef __COCOA_COMMON_METAL_H +#define __COCOA_COMMON_METAL_H #include @@ -28,46 +28,6 @@ #include #endif -typedef enum apple_view_type { - APPLE_VIEW_TYPE_NONE, - APPLE_VIEW_TYPE_OPENGL_ES, - APPLE_VIEW_TYPE_OPENGL, - APPLE_VIEW_TYPE_VULKAN, - APPLE_VIEW_TYPE_METAL, -} apple_view_type_t; - -#ifdef HAVE_METAL -#import - -@interface MetalView : MTKView -@end - -#endif - -@protocol ApplePlatform - -/*! @brief renderView returns the current render view based on the viewType */ -@property (readonly) id renderView; - -/*! @brief isActive returns true if the application has focus */ -@property (readonly) bool hasFocus; - -@property (readwrite) apple_view_type_t viewType; - -/*! @brief setVideoMode adjusts the video display to the specified mode */ -- (void)setVideoMode:(gfx_ctx_mode_t)mode; - -/*! @brief setCursorVisible specifies whether the cursor is visible */ -- (void)setCursorVisible:(bool)v; - -/*! @brief controls whether the screen saver should be disabled and - * the displays should not sleep. - */ -- (bool)setDisableDisplaySleep:(bool)disable; -@end - -extern id apple_platform; - #if defined(HAVE_COCOATOUCH) #include @@ -106,7 +66,7 @@ AVCaptureAudioDataOutputSampleBufferDelegate> @end @interface RetroArch_iOS : UINavigationController +UINavigationControllerDelegate> @property (nonatomic) UIWindow* window; @property (nonatomic) NSString* documentsDirectory; @@ -148,15 +108,4 @@ void get_ios_version(int *major, int *minor); #define BOXUINT(x) [NSNumber numberWithUnsignedInt:x] #define BOXFLOAT(x) [NSNumber numberWithDouble:x] -#if __has_feature(objc_arc) -#define RELEASE(x) x = nil -#define BRIDGE __bridge -#define UNSAFE_UNRETAINED __unsafe_unretained -#else -#define RELEASE(x) [x release]; \ - x = nil -#define BRIDGE -#define UNSAFE_UNRETAINED -#endif - #endif diff --git a/ui/drivers/cocoa/cocoa_common.m b/ui/drivers/cocoa/cocoa_common.m index 09163291c8..b356ffed58 100644 --- a/ui/drivers/cocoa/cocoa_common.m +++ b/ui/drivers/cocoa/cocoa_common.m @@ -43,32 +43,12 @@ #include "../../../location/location_driver.h" #include "../../../camera/camera_driver.h" -#ifdef HAVE_METAL -@implementation MetalView - -- (void)keyDown:(NSEvent*)theEvent -{ -} - -/* Stop the annoying sound when pressing a key. */ -- (BOOL)acceptsFirstResponder -{ - return YES; -} - -- (BOOL)isFlipped -{ - return YES; -} -@end -#endif - static CocoaView* g_instance; #if defined(HAVE_COCOA) void *nsview_get_ptr(void) { - return (BRIDGE void *)g_instance; + return g_instance; } #endif @@ -85,7 +65,6 @@ void *glkitview_init(void); cocoa_input_data_t *apple = (cocoa_input_data_t*)input_driver_get_data(); (void)apple; } - #endif + (CocoaView*)get @@ -102,6 +81,9 @@ void *glkitview_init(void); #if defined(HAVE_COCOA) [self setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + ui_window_cocoa_t cocoa_view; + cocoa_view.data = (CocoaView*)self; + [self registerForDraggedTypes:[NSArray arrayWithObjects:NSColorPboardType, NSFilenamesPboardType, nil]]; #elif defined(HAVE_COCOATOUCH) self.view = (__bridge GLKView*)glkitview_init(); @@ -113,13 +95,10 @@ void *glkitview_init(void); } #if defined(HAVE_COCOA) -- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow *)window { - return YES; -} - - (void)setFrame:(NSRect)frameRect { [super setFrame:frameRect]; + cocoagl_gfx_ctx_update(); } @@ -191,7 +170,7 @@ void *glkitview_init(void); { float width = 0.0f, height = 0.0f, tenpctw, tenpcth; RAScreen *screen = (__bridge RAScreen*)get_chosen_screen(); - UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; + UIInterfaceOrientation orientation = self.interfaceOrientation; CGRect screenSize = [screen bounds]; SEL selector = NSSelectorFromString(BOXSTRING("coordinateSpace")); @@ -212,40 +191,8 @@ void *glkitview_init(void); g_pause_indicator_view.frame = CGRectMake(tenpctw * 4.0f, 0.0f, tenpctw * 2.0f, tenpcth); [g_pause_indicator_view viewWithTag:1].frame = CGRectMake(0, 0, tenpctw * 2.0f, tenpcth); - - [self adjustViewFrameForSafeArea]; } --(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { - [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; - if (@available(iOS 11, *)) { - [coordinator animateAlongsideTransition:^(id _Nonnull context) { - [self adjustViewFrameForSafeArea]; - } completion:^(id _Nonnull context) { - }]; - } -} - --(void)adjustViewFrameForSafeArea { - // This is for adjusting the view frame to account for the notch in iPhone X phones - if (@available(iOS 11, *)) { - RAScreen *screen = (__bridge RAScreen*)get_chosen_screen(); - CGRect screenSize = [screen bounds]; - UIEdgeInsets inset = [[UIApplication sharedApplication] delegate].window.safeAreaInsets; - UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; - CGRect newFrame = screenSize; - if ( orientation == UIInterfaceOrientationPortrait ) { - newFrame = CGRectMake(screenSize.origin.x, screenSize.origin.y + inset.top, screenSize.size.width, screenSize.size.height - inset.top); - } else if ( orientation == UIInterfaceOrientationLandscapeLeft ) { - newFrame = CGRectMake(screenSize.origin.x, screenSize.origin.y, screenSize.size.width - inset.right, screenSize.size.height); - } else if ( orientation == UIInterfaceOrientationLandscapeRight ) { - newFrame = CGRectMake(screenSize.origin.x + inset.left, screenSize.origin.y, screenSize.size.width - inset.left, screenSize.size.height); - } - self.view.frame = newFrame; - } -} - - #define ALMOST_INVISIBLE (.021f) - (void)hidePauseButton diff --git a/ui/drivers/cocoa/cocoa_common_metal.h b/ui/drivers/cocoa/cocoa_common_metal.h new file mode 100644 index 0000000000..377e3a2732 --- /dev/null +++ b/ui/drivers/cocoa/cocoa_common_metal.h @@ -0,0 +1,162 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2013-2014 - Jason Fetters + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef __COCOA_COMMON_H +#define __COCOA_COMMON_H + +#include + +#ifdef HAVE_MENU +#include "../../menu/menu_setting.h" +#include "../../menu/menu_driver.h" +#endif + +#ifdef HAVE_CORELOCATION +#include +#endif + +typedef enum apple_view_type { + APPLE_VIEW_TYPE_NONE, + APPLE_VIEW_TYPE_OPENGL_ES, + APPLE_VIEW_TYPE_OPENGL, + APPLE_VIEW_TYPE_VULKAN, + APPLE_VIEW_TYPE_METAL, +} apple_view_type_t; + +#ifdef HAVE_METAL +#import + +@interface MetalView : MTKView +@end + +#endif + +@protocol ApplePlatform + +/*! @brief renderView returns the current render view based on the viewType */ +@property (readonly) id renderView; + +/*! @brief isActive returns true if the application has focus */ +@property (readonly) bool hasFocus; + +@property (readwrite) apple_view_type_t viewType; + +/*! @brief setVideoMode adjusts the video display to the specified mode */ +- (void)setVideoMode:(gfx_ctx_mode_t)mode; + +/*! @brief setCursorVisible specifies whether the cursor is visible */ +- (void)setCursorVisible:(bool)v; + +/*! @brief controls whether the screen saver should be disabled and + * the displays should not sleep. + */ +- (bool)setDisableDisplaySleep:(bool)disable; +@end + +extern id apple_platform; + +#if defined(HAVE_COCOATOUCH) +#include + +#ifdef HAVE_AVFOUNDATION +#import +#endif + + +/*********************************************/ +/* RAMenuBase */ +/* A menu class that displays RAMenuItemBase */ +/* objects. */ +/*********************************************/ +@interface RAMenuBase : UITableViewController +@property (nonatomic) NSMutableArray* sections; +@property (nonatomic) BOOL hidesHeaders; +@property (nonatomic) RAMenuBase* last_menu; +@property (nonatomic) UILabel *osdmessage; + +- (id)initWithStyle:(UITableViewStyle)style; +- (id)itemForIndexPath:(NSIndexPath*)indexPath; + +@end + +typedef struct +{ + char orientations[32]; + unsigned orientation_flags; + char bluetooth_mode[64]; +} apple_frontend_settings_t; +extern apple_frontend_settings_t apple_frontend_settings; + +@interface CocoaView : UIViewController ++ (CocoaView*)get; +@end + +@interface RetroArch_iOS : UINavigationController + +@property (nonatomic) UIWindow* window; +@property (nonatomic) NSString* documentsDirectory; +@property (nonatomic) RAMenuBase* mainmenu; +@property (nonatomic) int menu_count; + ++ (RetroArch_iOS*)get; + +- (void)showGameView; +- (void)toggleUI; +- (void)supportOtherAudioSessions; + +- (void)refreshSystemConfig; +- (void)mainMenuPushPop: (bool)pushp; +- (void)mainMenuRefresh; +@end + +void get_ios_version(int *major, int *minor); + +#elif defined(HAVE_COCOA_METAL) +#include + +@interface CocoaView : NSView +#ifdef HAVE_CORELOCATION + +#endif + ++ (CocoaView*)get; +#if !defined(HAVE_COCOA_METAL) +- (void)display; +#endif + +@end + +#endif + +#define BOXSTRING(x) [NSString stringWithUTF8String:x] +#define BOXINT(x) [NSNumber numberWithInt:x] +#define BOXUINT(x) [NSNumber numberWithUnsignedInt:x] +#define BOXFLOAT(x) [NSNumber numberWithDouble:x] + +#if __has_feature(objc_arc) +#define RELEASE(x) x = nil +#define BRIDGE __bridge +#define UNSAFE_UNRETAINED __unsafe_unretained +#else +#define RELEASE(x) [x release]; \ + x = nil +#define BRIDGE +#define UNSAFE_UNRETAINED +#endif + +#endif diff --git a/ui/drivers/cocoa/cocoa_common_metal.m b/ui/drivers/cocoa/cocoa_common_metal.m new file mode 100644 index 0000000000..928a06cc6c --- /dev/null +++ b/ui/drivers/cocoa/cocoa_common_metal.m @@ -0,0 +1,694 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2013-2014 - Jason Fetters + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#import +#include +#include "cocoa_common_metal.h" +#ifdef HAVE_COCOA_METAL +#include "../ui_cocoa_metal.h" +#endif + +#include + +#include "../../../verbosity.h" + +/* Define compatibility symbols and categories. */ + +#ifdef HAVE_AVFOUNDATION +#include +#include +#include +#include +#include +#ifdef HAVE_OPENGLES +#include +#else +#include +#endif +#endif + +#include "../../../location/location_driver.h" +#include "../../../camera/camera_driver.h" + +#ifdef HAVE_METAL +@implementation MetalView + +- (void)keyDown:(NSEvent*)theEvent +{ +} + +/* Stop the annoying sound when pressing a key. */ +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (BOOL)isFlipped +{ + return YES; +} +@end +#endif + +static CocoaView* g_instance; + +#if defined(HAVE_COCOA_METAL) +void *nsview_get_ptr(void) +{ + return (BRIDGE void *)g_instance; +} +#endif + +/* forward declarations */ +void cocoagl_gfx_ctx_update(void); +void *glkitview_init(void); + +@implementation CocoaView + +#if defined(HAVE_COCOA_METAL) +#include "../../../input/drivers/cocoa_input.h" + +- (void)scrollWheel:(NSEvent *)theEvent { + cocoa_input_data_t *apple = (cocoa_input_data_t*)input_driver_get_data(); + (void)apple; +} + +#endif + ++ (CocoaView*)get +{ + if (!g_instance) + g_instance = [CocoaView new]; + + return g_instance; +} + +- (id)init +{ + self = [super init]; + +#if defined(HAVE_COCOA_METAL) + [self setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; + [self registerForDraggedTypes:[NSArray arrayWithObjects:NSColorPboardType, NSFilenamesPboardType, nil]]; +#elif defined(HAVE_COCOATOUCH) + self.view = (__bridge GLKView*)glkitview_init(); + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showPauseIndicator) name:UIApplicationWillEnterForegroundNotification object:nil]; +#endif + + return self; +} + +#if defined(HAVE_COCOA_METAL) +- (BOOL)layer:(CALayer *)layer shouldInheritContentsScale:(CGFloat)newScale fromWindow:(NSWindow *)window { + return YES; +} + +- (void)setFrame:(NSRect)frameRect +{ + [super setFrame:frameRect]; + cocoagl_gfx_ctx_update(); +} + +/* Stop the annoying sound when pressing a key. */ +- (BOOL)acceptsFirstResponder +{ + return YES; +} + +- (BOOL)isFlipped +{ + return YES; +} + +- (void)keyDown:(NSEvent*)theEvent +{ +} + +- (NSDragOperation)draggingEntered:(id )sender +{ + NSDragOperation sourceDragMask = [sender draggingSourceOperationMask]; + NSPasteboard *pboard = [sender draggingPasteboard]; + + if ( [[pboard types] containsObject:NSFilenamesPboardType] ) + { + if (sourceDragMask & NSDragOperationCopy) + return NSDragOperationCopy; + } + + return NSDragOperationNone; +} + +- (BOOL)performDragOperation:(id)sender +{ + NSPasteboard *pboard = [sender draggingPasteboard]; + + if ( [[pboard types] containsObject:NSURLPboardType]) + { + NSURL *fileURL = [NSURL URLFromPasteboard:pboard]; + NSString *s = [fileURL path]; + if (s != nil) + { + RARCH_LOG("Drop name is: %s\n", [s UTF8String]); + } + } + return YES; +} + +- (void)draggingExited:(id )sender +{ + [self setNeedsDisplay: YES]; +} + +#elif defined(HAVE_COCOATOUCH) +- (void)viewDidAppear:(BOOL)animated +{ + /* Pause Menus. */ + [self showPauseIndicator]; +} + +- (void)showPauseIndicator +{ + g_pause_indicator_view.alpha = 1.0f; + [NSObject cancelPreviousPerformRequestsWithTarget:g_instance]; + [g_instance performSelector:@selector(hidePauseButton) withObject:g_instance afterDelay:3.0f]; +} + +- (void)viewWillLayoutSubviews +{ + float width = 0.0f, height = 0.0f, tenpctw, tenpcth; + RAScreen *screen = (__bridge RAScreen*)get_chosen_screen(); + UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; + CGRect screenSize = [screen bounds]; + SEL selector = NSSelectorFromString(BOXSTRING("coordinateSpace")); + + if ([screen respondsToSelector:selector]) + { + screenSize = [[screen coordinateSpace] bounds]; + width = CGRectGetWidth(screenSize); + height = CGRectGetHeight(screenSize); + } + else + { + width = ((int)orientation < 3) ? CGRectGetWidth(screenSize) : CGRectGetHeight(screenSize); + height = ((int)orientation < 3) ? CGRectGetHeight(screenSize) : CGRectGetWidth(screenSize); + } + + tenpctw = width / 10.0f; + tenpcth = height / 10.0f; + + g_pause_indicator_view.frame = CGRectMake(tenpctw * 4.0f, 0.0f, tenpctw * 2.0f, tenpcth); + [g_pause_indicator_view viewWithTag:1].frame = CGRectMake(0, 0, tenpctw * 2.0f, tenpcth); + + [self adjustViewFrameForSafeArea]; +} + +-(void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { + [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]; + if (@available(iOS 11, *)) { + [coordinator animateAlongsideTransition:^(id _Nonnull context) { + [self adjustViewFrameForSafeArea]; + } completion:^(id _Nonnull context) { + }]; + } +} + +-(void)adjustViewFrameForSafeArea { + // This is for adjusting the view frame to account for the notch in iPhone X phones + if (@available(iOS 11, *)) { + RAScreen *screen = (__bridge RAScreen*)get_chosen_screen(); + CGRect screenSize = [screen bounds]; + UIEdgeInsets inset = [[UIApplication sharedApplication] delegate].window.safeAreaInsets; + UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; + CGRect newFrame = screenSize; + if ( orientation == UIInterfaceOrientationPortrait ) { + newFrame = CGRectMake(screenSize.origin.x, screenSize.origin.y + inset.top, screenSize.size.width, screenSize.size.height - inset.top); + } else if ( orientation == UIInterfaceOrientationLandscapeLeft ) { + newFrame = CGRectMake(screenSize.origin.x, screenSize.origin.y, screenSize.size.width - inset.right, screenSize.size.height); + } else if ( orientation == UIInterfaceOrientationLandscapeRight ) { + newFrame = CGRectMake(screenSize.origin.x + inset.left, screenSize.origin.y, screenSize.size.width - inset.left, screenSize.size.height); + } + self.view.frame = newFrame; + } +} + + +#define ALMOST_INVISIBLE (.021f) + +- (void)hidePauseButton +{ + [UIView animateWithDuration:0.2 + animations:^{ g_pause_indicator_view.alpha = ALMOST_INVISIBLE; } + completion:^(BOOL finished) { } + ]; +} + +/* NOTE: This version runs on iOS6+. */ +- (NSUInteger)supportedInterfaceOrientations +{ + return (NSUInteger)apple_frontend_settings.orientation_flags; +} + +/* NOTE: This version runs on iOS2-iOS5, but not iOS6+. */ +- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation +{ + switch (interfaceOrientation) + { + case UIInterfaceOrientationPortrait: + return (apple_frontend_settings.orientation_flags & UIInterfaceOrientationMaskPortrait); + case UIInterfaceOrientationPortraitUpsideDown: + return (apple_frontend_settings.orientation_flags & UIInterfaceOrientationMaskPortraitUpsideDown); + case UIInterfaceOrientationLandscapeLeft: + return (apple_frontend_settings.orientation_flags & UIInterfaceOrientationMaskLandscapeLeft); + case UIInterfaceOrientationLandscapeRight: + return (apple_frontend_settings.orientation_flags & UIInterfaceOrientationMaskLandscapeRight); + + default: + return (apple_frontend_settings.orientation_flags & UIInterfaceOrientationMaskAll); + } + + return YES; +} +#endif + +#ifdef HAVE_AVFOUNDATION +#include "../../gfx/common/gl_common.h" + +#ifndef GL_BGRA +#define GL_BGRA 0x80E1 +#endif + +#ifdef HAVE_OPENGLES +#define RCVOpenGLTextureCacheCreateTextureFromImage CVOpenGLESTextureCacheCreateTextureFromImage +#define RCVOpenGLTextureGetName CVOpenGLESTextureGetName +#define RCVOpenGLTextureCacheFlush CVOpenGLESTextureCacheFlush +#define RCVOpenGLTextureCacheCreate CVOpenGLESTextureCacheCreate +#define RCVOpenGLTextureRef CVOpenGLESTextureRef +#define RCVOpenGLTextureCacheRef CVOpenGLESTextureCacheRef +#if COREVIDEO_USE_EAGLCONTEXT_CLASS_IN_API +#define RCVOpenGLGetCurrentContext() (CVEAGLContext)(g_context) +#else +#define RCVOpenGLGetCurrentContext() (__bridge void *)(g_context) +#endif +#else +#define RCVOpenGLTextureCacheCreateTextureFromImage CVOpenGLTextureCacheCreateTextureFromImage +#define RCVOpenGLTextureGetName CVOpenGLTextureGetName +#define RCVOpenGLTextureCacheFlush CVOpenGLTextureCacheFlush +#define RCVOpenGLTextureCacheCreate CVOpenGLTextureCacheCreate +#define RCVOpenGLTextureRef CVOpenGLTextureRef +#define RCVOpenGLTextureCacheRef CVOpenGLTextureCacheRef +#define RCVOpenGLGetCurrentContext() CGLGetCurrentContext(), CGLGetPixelFormat(CGLGetCurrentContext()) +#endif + +static AVCaptureSession *_session; +static NSString *_sessionPreset; +RCVOpenGLTextureCacheRef textureCache; +GLuint outputTexture; +static bool newFrame = false; + +static void event_process_camera_frame(void *pbuf_ptr) +{ + CVReturn ret; + RCVOpenGLTextureRef renderTexture; + CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)pbuf_ptr; + size_t width = CVPixelBufferGetWidth(pixelBuffer); + size_t height = CVPixelBufferGetHeight(pixelBuffer); + + CVPixelBufferLockBaseAddress(pixelBuffer, 0); + + (void)width; + (void)height; + + /*TODO - rewrite all this. + * + * create a texture from our render target. + * textureCache will be what you previously + * made with RCVOpenGLTextureCacheCreate. + */ +#ifdef HAVE_OPENGLES + ret = RCVOpenGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault, + textureCache, pixelBuffer, NULL, GL_TEXTURE_2D, + GL_RGBA, (GLsizei)width, (GLsizei)height, + GL_BGRA, GL_UNSIGNED_BYTE, 0, &renderTexture); +#else + ret = RCVOpenGLTextureCacheCreateTextureFromImage(kCFAllocatorDefault, + textureCache, pixelBuffer, 0, &renderTexture); +#endif + + if (!renderTexture || ret) + { + RARCH_ERR("[apple_camera]: RCVOpenGLTextureCacheCreateTextureFromImage failed.\n"); + return; + } + + outputTexture = RCVOpenGLTextureGetName(renderTexture); + + gl_bind_texture(outputTexture, GL_CLAMP_TO_EDGE, GL_LINEAR, GL_LINEAR); + + CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); + [[NSNotificationCenter defaultCenter] postNotificationName:@"NewCameraTextureReady" object:nil]; + newFrame = true; + + glBindTexture(GL_TEXTURE_2D, 0); + + RCVOpenGLTextureCacheFlush(textureCache, 0); + + CFRelease(renderTexture); + CFRelease(pixelBuffer); + + pixelBuffer = 0; +} + +- (void)captureOutput:(AVCaptureOutput *)captureOutput +didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer + fromConnection:(AVCaptureConnection *)connection +{ + /* TODO: Don't post if event queue is full */ + CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CVPixelBufferRetain(CMSampleBufferGetImageBuffer(sampleBuffer)); + event_process_camera_frame(pixelBuffer); +} + +/* TODO - add void param to onCameraInit so we can pass g_context. */ +- (void) onCameraInit +{ + NSError *error; + AVCaptureVideoDataOutput * dataOutput; + AVCaptureDeviceInput *input; + AVCaptureDevice *videoDevice; + + CVReturn ret = RCVOpenGLTextureCacheCreate(kCFAllocatorDefault, NULL, + RCVOpenGLGetCurrentContext(), NULL, &textureCache); + (void)ret; + + /* Setup Capture Session. */ + _session = [[AVCaptureSession alloc] init]; + [_session beginConfiguration]; + + /* TODO: dehardcode this based on device capabilities */ + _sessionPreset = AVCaptureSessionPreset640x480; + + /* Set preset session size. */ + [_session setSessionPreset:_sessionPreset]; + + /* Creata a video device and input from that Device. Add the input to the capture session. */ + videoDevice = (AVCaptureDevice*)[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if (videoDevice == nil) + retro_assert(0); + + /* Add the device to the session. */ + input = (AVCaptureDeviceInput*)[AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error]; + + if (error) + { + RARCH_ERR("video device input %s\n", error.localizedDescription.UTF8String); + retro_assert(0); + } + + [_session addInput:input]; + + /* Create the output for the capture session. */ + dataOutput = (AVCaptureVideoDataOutput*)[[AVCaptureVideoDataOutput alloc] init]; + [dataOutput setAlwaysDiscardsLateVideoFrames:NO]; /* Probably want to set this to NO when recording. */ + + [dataOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA] forKey:(id)kCVPixelBufferPixelFormatTypeKey]]; + + /* Set dispatch to be on the main thread so OpenGL can do things with the data. */ + [dataOutput setSampleBufferDelegate:self queue:dispatch_get_main_queue()]; + + [_session addOutput:dataOutput]; + [_session commitConfiguration]; +} + +- (void) onCameraStart +{ + [_session startRunning]; +} + +- (void) onCameraStop +{ + [_session stopRunning]; +} + +- (void) onCameraFree +{ + RCVOpenGLTextureCacheFlush(textureCache, 0); + CFRelease(textureCache); +} +#endif + +#ifdef HAVE_CORELOCATION +#include + +static CLLocationManager *locationManager; +static bool locationChanged; +static CLLocationDegrees currentLatitude; +static CLLocationDegrees currentLongitude; +static CLLocationAccuracy currentHorizontalAccuracy; +static CLLocationAccuracy currentVerticalAccuracy; + +- (bool)onLocationHasChanged +{ + bool hasChanged = locationChanged; + + if (hasChanged) + locationChanged = false; + + return hasChanged; +} + +- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation +{ + locationChanged = true; + currentLatitude = newLocation.coordinate.latitude; + currentLongitude = newLocation.coordinate.longitude; + currentHorizontalAccuracy = newLocation.horizontalAccuracy; + currentVerticalAccuracy = newLocation.verticalAccuracy; + RARCH_LOG("didUpdateToLocation - latitude %f, longitude %f\n", (float)currentLatitude, (float)currentLongitude); +} + +- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations +{ + CLLocation *location = (CLLocation*)[locations objectAtIndex:([locations count] - 1)]; + + locationChanged = true; + currentLatitude = [location coordinate].latitude; + currentLongitude = [location coordinate].longitude; + currentHorizontalAccuracy = location.horizontalAccuracy; + currentVerticalAccuracy = location.verticalAccuracy; + RARCH_LOG("didUpdateLocations - latitude %f, longitude %f\n", (float)currentLatitude, (float)currentLongitude); +} + +- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error +{ + RARCH_LOG("didFailWithError - %s\n", [[error localizedDescription] UTF8String]); +} + +- (void)locationManagerDidPauseLocationUpdates:(CLLocationManager *)manager +{ + RARCH_LOG("didPauseLocationUpdates\n"); +} + +- (void)locationManagerDidResumeLocationUpdates:(CLLocationManager *)manager +{ + RARCH_LOG("didResumeLocationUpdates\n"); +} + +- (void)onLocationInit +{ + /* Create the location manager + * if this object does not already have one. + */ + + if (locationManager == nil) + locationManager = [[CLLocationManager alloc] init]; + locationManager.delegate = self; + locationManager.desiredAccuracy = kCLLocationAccuracyBest; + locationManager.distanceFilter = kCLDistanceFilterNone; + [locationManager startUpdatingLocation]; +} +#endif + +@end + +#ifdef HAVE_AVFOUNDATION +typedef struct apple_camera +{ + void *empty; +} applecamera_t; + +static void *apple_camera_init(const char *device, uint64_t caps, unsigned width, unsigned height) +{ + applecamera_t *applecamera; + + if ((caps & (UINT64_C(1) << RETRO_CAMERA_BUFFER_OPENGL_TEXTURE)) == 0) + { + RARCH_ERR("applecamera returns OpenGL texture.\n"); + return NULL; + } + + applecamera = (applecamera_t*)calloc(1, sizeof(applecamera_t)); + if (!applecamera) + return NULL; + + [[CocoaView get] onCameraInit]; + + return applecamera; +} + +static void apple_camera_free(void *data) +{ + applecamera_t *applecamera = (applecamera_t*)data; + + [[CocoaView get] onCameraFree]; + + if (applecamera) + free(applecamera); + applecamera = NULL; +} + +static bool apple_camera_start(void *data) +{ + (void)data; + + [[CocoaView get] onCameraStart]; + + return true; +} + +static void apple_camera_stop(void *data) +{ + [[CocoaView get] onCameraStop]; +} + +static bool apple_camera_poll(void *data, retro_camera_frame_raw_framebuffer_t frame_raw_cb, + retro_camera_frame_opengl_texture_t frame_gl_cb) +{ + + (void)data; + (void)frame_raw_cb; + + if (frame_gl_cb && newFrame) + { + /* FIXME: Identity for now. + * Use proper texture matrix as returned by iOS Camera (if at all?). */ + static const float affine[] = { + 1.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 1.0f + }; + + frame_gl_cb(outputTexture, GL_TEXTURE_2D, affine); + newFrame = false; + } + + return true; +} + +camera_driver_t camera_avfoundation = { + apple_camera_init, + apple_camera_free, + apple_camera_start, + apple_camera_stop, + apple_camera_poll, + "avfoundation", +}; +#endif + +#ifdef HAVE_CORELOCATION +typedef struct apple_location +{ + void *empty; +} applelocation_t; + +static void *apple_location_init(void) +{ + applelocation_t *applelocation = (applelocation_t*)calloc(1, sizeof(applelocation_t)); + if (!applelocation) + return NULL; + + [[CocoaView get] onLocationInit]; + + return applelocation; +} + +static void apple_location_set_interval(void *data, unsigned interval_update_ms, unsigned interval_distance) +{ + (void)data; + + locationManager.distanceFilter = interval_distance ? interval_distance : kCLDistanceFilterNone; +} + +static void apple_location_free(void *data) +{ + applelocation_t *applelocation = (applelocation_t*)data; + + /* TODO - free location manager? */ + + if (applelocation) + free(applelocation); + applelocation = NULL; +} + +static bool apple_location_start(void *data) +{ + (void)data; + + [locationManager startUpdatingLocation]; + return true; +} + +static void apple_location_stop(void *data) +{ + (void)data; + + [locationManager stopUpdatingLocation]; +} + +static bool apple_location_get_position(void *data, double *lat, double *lon, double *horiz_accuracy, + double *vert_accuracy) +{ + (void)data; + + bool ret = [[CocoaView get] onLocationHasChanged]; + + if (!ret) + goto fail; + + *lat = currentLatitude; + *lon = currentLongitude; + *horiz_accuracy = currentHorizontalAccuracy; + *vert_accuracy = currentVerticalAccuracy; + return true; + +fail: + *lat = 0.0; + *lon = 0.0; + *horiz_accuracy = 0.0; + *vert_accuracy = 0.0; + return false; +} + +location_driver_t location_corelocation = { + apple_location_init, + apple_location_free, + apple_location_start, + apple_location_stop, + apple_location_get_position, + apple_location_set_interval, + "corelocation", +}; +#endif + diff --git a/ui/drivers/cocoa/ui_cocoa_application.m b/ui/drivers/cocoa/ui_cocoa_application.m index afb6740d43..14975b3c10 100644 --- a/ui/drivers/cocoa/ui_cocoa_application.m +++ b/ui/drivers/cocoa/ui_cocoa_application.m @@ -23,10 +23,6 @@ #include "cocoa_common.h" #include "../../ui_companion_driver.h" -#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 -#define NSEventMaskAny NSAnyEventMask -#endif - static void* ui_application_cocoa_initialize(void) { return NULL; @@ -34,7 +30,7 @@ static void* ui_application_cocoa_initialize(void) static bool ui_application_cocoa_pending_events(void) { - NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; + NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; if (!event) return false; return true; @@ -44,17 +40,12 @@ static void ui_application_cocoa_process_events(void) { while (1) { - NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; + NSEvent *event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; if (!event) break; -#if __has_feature(objc_arc) - [NSApp sendEvent: event]; - -#else [event retain]; [NSApp sendEvent: event]; [event release]; -#endif } } diff --git a/ui/drivers/cocoa/ui_cocoa_application_metal.m b/ui/drivers/cocoa/ui_cocoa_application_metal.m new file mode 100644 index 0000000000..b5cc8f46ea --- /dev/null +++ b/ui/drivers/cocoa/ui_cocoa_application_metal.m @@ -0,0 +1,73 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include "cocoa_common_metal.h" +#include "../../ui_companion_driver.h" + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 +#define NSEventMaskAny NSAnyEventMask +#endif + +static void* ui_application_cocoa_initialize(void) +{ + return NULL; +} + +static bool ui_application_cocoa_pending_events(void) +{ + NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; + if (!event) + return false; + return true; +} + +static void ui_application_cocoa_process_events(void) +{ + while (1) + { + NSEvent *event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES]; + if (!event) + break; +#if __has_feature(objc_arc) + [NSApp sendEvent: event]; + +#else + [event retain]; + [NSApp sendEvent: event]; + [event release]; +#endif + } +} + +static void ui_application_cocoa_run(void *args) +{ + (void)args; +} + +ui_application_t ui_application_cocoa = { + ui_application_cocoa_initialize, + ui_application_cocoa_pending_events, + ui_application_cocoa_process_events, + ui_application_cocoa_run, + NULL, + "cocoa" +}; diff --git a/ui/drivers/cocoa/ui_cocoa_browser_window_metal.m b/ui/drivers/cocoa/ui_cocoa_browser_window_metal.m new file mode 100644 index 0000000000..27b1474409 --- /dev/null +++ b/ui/drivers/cocoa/ui_cocoa_browser_window_metal.m @@ -0,0 +1,67 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include +#include + +#include + +#include "cocoa_common_metal.h" + +#include "../../ui_companion_driver.h" + +static bool ui_browser_window_cocoa_open(ui_browser_window_state_t *state) +{ + NSOpenPanel* panel = (NSOpenPanel*)[NSOpenPanel openPanel]; + NSArray *filetypes = NULL; + + if (!string_is_empty(state->filters)) + filetypes = [[NSArray alloc] initWithObjects:BOXSTRING(state->filters), BOXSTRING(state->filters_title), nil]; + [panel setAllowedFileTypes:filetypes]; +#if defined(MAC_OS_X_VERSION_10_6) + [panel setMessage:BOXSTRING(state->title)]; + if ([panel runModalForDirectory:BOXSTRING(state->startdir) file:nil] != 1) + return false; +#else + [panel setTitle:NSLocalizedString(BOXSTRING(state->title), BOXSTRING("open panel"))]; + [panel setDirectory:BOXSTRING(state->startdir)]; + [panel setCanChooseDirectories:NO]; + [panel setCanChooseFiles:YES]; + [panel setAllowsMultipleSelection:NO]; + [panel setTreatsFilePackagesAsDirectories:NO]; + NSInteger result = [panel runModal]; + if (result != 1) + return false; +#endif + NSURL *url = (NSURL*)panel.URL; + const char *res_path = [url.path UTF8String]; + state->result = strdup(res_path); + + return true; +} + +static bool ui_browser_window_cocoa_save(ui_browser_window_state_t *state) +{ + return false; +} + +ui_browser_window_t ui_browser_window_cocoa = { + ui_browser_window_cocoa_open, + ui_browser_window_cocoa_save, + "cocoa" +}; diff --git a/ui/drivers/cocoa/ui_cocoa_msg_window.m b/ui/drivers/cocoa/ui_cocoa_msg_window.m index 71c83393c6..d5e4ec9713 100644 --- a/ui/drivers/cocoa/ui_cocoa_msg_window.m +++ b/ui/drivers/cocoa/ui_cocoa_msg_window.m @@ -25,104 +25,88 @@ #include "../../ui_companion_driver.h" -#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 -#define NSAlertStyleCritical NSCriticalAlertStyle -#define NSAlertStyleWarning NSWarningAlertStyle -#define NSAlertStyleInformational NSInformationalAlertStyle -#endif +extern id apple_platform; static enum ui_msg_window_response ui_msg_window_cocoa_dialog(ui_msg_window_state *state, enum ui_msg_window_type type) { - NSInteger response; -#if __has_feature(objc_arc) - NSAlert *alert = [NSAlert new]; -#else - NSAlert* alert = [[NSAlert new] autorelease]; -#endif - - if (!string_is_empty(state->title)) - [alert setMessageText:BOXSTRING(state->title)]; - [alert setInformativeText:BOXSTRING(state->text)]; - - switch (state->buttons) - { - case UI_MSG_WINDOW_OK: - [alert addButtonWithTitle:BOXSTRING("OK")]; - break; - case UI_MSG_WINDOW_YESNO: - [alert addButtonWithTitle:BOXSTRING("Yes")]; - [alert addButtonWithTitle:BOXSTRING("No")]; - break; - case UI_MSG_WINDOW_OKCANCEL: - [alert addButtonWithTitle:BOXSTRING("OK")]; - [alert addButtonWithTitle:BOXSTRING("Cancel")]; - break; - case UI_MSG_WINDOW_YESNOCANCEL: - [alert addButtonWithTitle:BOXSTRING("Yes")]; - [alert addButtonWithTitle:BOXSTRING("No")]; - [alert addButtonWithTitle:BOXSTRING("Cancel")]; - break; - } - - switch (type) - { - case UI_MSG_WINDOW_TYPE_ERROR: - [alert setAlertStyle:NSAlertStyleCritical]; - break; - case UI_MSG_WINDOW_TYPE_WARNING: - [alert setAlertStyle:NSAlertStyleWarning]; - break; - case UI_MSG_WINDOW_TYPE_QUESTION: - [alert setAlertStyle:NSAlertStyleInformational]; - break; - case UI_MSG_WINDOW_TYPE_INFORMATION: - [alert setAlertStyle:NSAlertStyleInformational]; - break; - } - -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 - [alert beginSheetModalForWindow:(BRIDGE NSWindow *)ui_companion_driver_get_main_window() - completionHandler:^(NSModalResponse returnCode) { - [[NSApplication sharedApplication] stopModalWithCode:returnCode]; - }]; - response = [alert runModal]; -#else - [alert beginSheetModalForWindow:(BRIDGE NSWindow *)ui_companion_driver_get_main_window() - modalDelegate:apple_platform - didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) - contextInfo:nil]; - response = [[NSApplication sharedApplication] runModalForWindow:[alert window]]; -#endif - - switch (state->buttons) - { - case UI_MSG_WINDOW_OK: - if (response == NSAlertFirstButtonReturn) - return UI_MSG_RESPONSE_OK; - break; - case UI_MSG_WINDOW_OKCANCEL: - if (response == NSAlertFirstButtonReturn) - return UI_MSG_RESPONSE_OK; - if (response == NSAlertSecondButtonReturn) - return UI_MSG_RESPONSE_CANCEL; - break; - case UI_MSG_WINDOW_YESNO: - if (response == NSAlertFirstButtonReturn) - return UI_MSG_RESPONSE_YES; - if (response == NSAlertSecondButtonReturn) - return UI_MSG_RESPONSE_NO; - break; - case UI_MSG_WINDOW_YESNOCANCEL: - if (response == NSAlertFirstButtonReturn) - return UI_MSG_RESPONSE_YES; - if (response == NSAlertSecondButtonReturn) - return UI_MSG_RESPONSE_NO; - if (response == NSAlertThirdButtonReturn) - return UI_MSG_RESPONSE_CANCEL; - break; - } - - return UI_MSG_RESPONSE_NA; + NSInteger response; + NSAlert* alert = [[NSAlert new] autorelease]; + + if (!string_is_empty(state->title)) + [alert setMessageText:BOXSTRING(state->title)]; + [alert setInformativeText:BOXSTRING(state->text)]; + + switch (state->buttons) + { + case UI_MSG_WINDOW_OK: + [alert addButtonWithTitle:BOXSTRING("OK")]; + break; + case UI_MSG_WINDOW_YESNO: + [alert addButtonWithTitle:BOXSTRING("Yes")]; + [alert addButtonWithTitle:BOXSTRING("No")]; + break; + case UI_MSG_WINDOW_OKCANCEL: + [alert addButtonWithTitle:BOXSTRING("OK")]; + [alert addButtonWithTitle:BOXSTRING("Cancel")]; + break; + case UI_MSG_WINDOW_YESNOCANCEL: + [alert addButtonWithTitle:BOXSTRING("Yes")]; + [alert addButtonWithTitle:BOXSTRING("No")]; + [alert addButtonWithTitle:BOXSTRING("Cancel")]; + break; + } + + switch (type) + { + case UI_MSG_WINDOW_TYPE_ERROR: + [alert setAlertStyle:NSCriticalAlertStyle]; + break; + case UI_MSG_WINDOW_TYPE_WARNING: + [alert setAlertStyle:NSWarningAlertStyle]; + break; + case UI_MSG_WINDOW_TYPE_QUESTION: + [alert setAlertStyle:NSInformationalAlertStyle]; + break; + case UI_MSG_WINDOW_TYPE_INFORMATION: + [alert setAlertStyle:NSInformationalAlertStyle]; + break; + } + + [alert beginSheetModalForWindow:ui_companion_driver_get_main_window() + modalDelegate:apple_platform + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; + response = [[NSApplication sharedApplication] runModalForWindow:[alert window]]; + + switch (state->buttons) + { + case UI_MSG_WINDOW_OK: + if (response == NSAlertFirstButtonReturn) + return UI_MSG_RESPONSE_OK; + break; + case UI_MSG_WINDOW_OKCANCEL: + if (response == NSAlertFirstButtonReturn) + return UI_MSG_RESPONSE_OK; + if (response == NSAlertSecondButtonReturn) + return UI_MSG_RESPONSE_CANCEL; + break; + case UI_MSG_WINDOW_YESNO: + if (response == NSAlertFirstButtonReturn) + return UI_MSG_RESPONSE_YES; + if (response == NSAlertSecondButtonReturn) + return UI_MSG_RESPONSE_NO; + break; + case UI_MSG_WINDOW_YESNOCANCEL: + if (response == NSAlertFirstButtonReturn) + return UI_MSG_RESPONSE_YES; + if (response == NSAlertSecondButtonReturn) + return UI_MSG_RESPONSE_NO; + if (response == NSAlertThirdButtonReturn) + return UI_MSG_RESPONSE_CANCEL; + break; + } + + return UI_MSG_RESPONSE_NA; } static enum ui_msg_window_response ui_msg_window_cocoa_error(ui_msg_window_state *state) diff --git a/ui/drivers/cocoa/ui_cocoa_msg_window_metal.m b/ui/drivers/cocoa/ui_cocoa_msg_window_metal.m new file mode 100644 index 0000000000..a209e8dc58 --- /dev/null +++ b/ui/drivers/cocoa/ui_cocoa_msg_window_metal.m @@ -0,0 +1,154 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include +#include + +#include + +#include "cocoa_common_metal.h" + +#include "../../ui_companion_driver.h" + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 +#define NSAlertStyleCritical NSCriticalAlertStyle +#define NSAlertStyleWarning NSWarningAlertStyle +#define NSAlertStyleInformational NSInformationalAlertStyle +#endif + +static enum ui_msg_window_response ui_msg_window_cocoa_dialog(ui_msg_window_state *state, enum ui_msg_window_type type) +{ + NSInteger response; +#if __has_feature(objc_arc) + NSAlert *alert = [NSAlert new]; +#else + NSAlert* alert = [[NSAlert new] autorelease]; +#endif + + if (!string_is_empty(state->title)) + [alert setMessageText:BOXSTRING(state->title)]; + [alert setInformativeText:BOXSTRING(state->text)]; + + switch (state->buttons) + { + case UI_MSG_WINDOW_OK: + [alert addButtonWithTitle:BOXSTRING("OK")]; + break; + case UI_MSG_WINDOW_YESNO: + [alert addButtonWithTitle:BOXSTRING("Yes")]; + [alert addButtonWithTitle:BOXSTRING("No")]; + break; + case UI_MSG_WINDOW_OKCANCEL: + [alert addButtonWithTitle:BOXSTRING("OK")]; + [alert addButtonWithTitle:BOXSTRING("Cancel")]; + break; + case UI_MSG_WINDOW_YESNOCANCEL: + [alert addButtonWithTitle:BOXSTRING("Yes")]; + [alert addButtonWithTitle:BOXSTRING("No")]; + [alert addButtonWithTitle:BOXSTRING("Cancel")]; + break; + } + + switch (type) + { + case UI_MSG_WINDOW_TYPE_ERROR: + [alert setAlertStyle:NSAlertStyleCritical]; + break; + case UI_MSG_WINDOW_TYPE_WARNING: + [alert setAlertStyle:NSAlertStyleWarning]; + break; + case UI_MSG_WINDOW_TYPE_QUESTION: + [alert setAlertStyle:NSAlertStyleInformational]; + break; + case UI_MSG_WINDOW_TYPE_INFORMATION: + [alert setAlertStyle:NSAlertStyleInformational]; + break; + } + +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 + [alert beginSheetModalForWindow:(BRIDGE NSWindow *)ui_companion_driver_get_main_window() + completionHandler:^(NSModalResponse returnCode) { + [[NSApplication sharedApplication] stopModalWithCode:returnCode]; + }]; + response = [alert runModal]; +#else + [alert beginSheetModalForWindow:(BRIDGE NSWindow *)ui_companion_driver_get_main_window() + modalDelegate:apple_platform + didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) + contextInfo:nil]; + response = [[NSApplication sharedApplication] runModalForWindow:[alert window]]; +#endif + + switch (state->buttons) + { + case UI_MSG_WINDOW_OK: + if (response == NSAlertFirstButtonReturn) + return UI_MSG_RESPONSE_OK; + break; + case UI_MSG_WINDOW_OKCANCEL: + if (response == NSAlertFirstButtonReturn) + return UI_MSG_RESPONSE_OK; + if (response == NSAlertSecondButtonReturn) + return UI_MSG_RESPONSE_CANCEL; + break; + case UI_MSG_WINDOW_YESNO: + if (response == NSAlertFirstButtonReturn) + return UI_MSG_RESPONSE_YES; + if (response == NSAlertSecondButtonReturn) + return UI_MSG_RESPONSE_NO; + break; + case UI_MSG_WINDOW_YESNOCANCEL: + if (response == NSAlertFirstButtonReturn) + return UI_MSG_RESPONSE_YES; + if (response == NSAlertSecondButtonReturn) + return UI_MSG_RESPONSE_NO; + if (response == NSAlertThirdButtonReturn) + return UI_MSG_RESPONSE_CANCEL; + break; + } + + return UI_MSG_RESPONSE_NA; +} + +static enum ui_msg_window_response ui_msg_window_cocoa_error(ui_msg_window_state *state) +{ + return ui_msg_window_cocoa_dialog(state, UI_MSG_WINDOW_TYPE_ERROR); +} + +static enum ui_msg_window_response ui_msg_window_cocoa_information(ui_msg_window_state *state) +{ + return ui_msg_window_cocoa_dialog(state, UI_MSG_WINDOW_TYPE_INFORMATION); +} + +static enum ui_msg_window_response ui_msg_window_cocoa_question(ui_msg_window_state *state) +{ + return ui_msg_window_cocoa_dialog(state, UI_MSG_WINDOW_TYPE_QUESTION); +} + +static enum ui_msg_window_response ui_msg_window_cocoa_warning(ui_msg_window_state *state) +{ + return ui_msg_window_cocoa_dialog(state, UI_MSG_WINDOW_TYPE_WARNING); +} + +ui_msg_window_t ui_msg_window_cocoa = { + ui_msg_window_cocoa_error, + ui_msg_window_cocoa_information, + ui_msg_window_cocoa_question, + ui_msg_window_cocoa_warning, + "cocoa" +}; diff --git a/ui/drivers/cocoa/ui_cocoa_window.m b/ui/drivers/cocoa/ui_cocoa_window.m index 94e2a15fcc..3ec869e569 100644 --- a/ui/drivers/cocoa/ui_cocoa_window.m +++ b/ui/drivers/cocoa/ui_cocoa_window.m @@ -32,18 +32,15 @@ static void* ui_window_cocoa_init(void) static void ui_window_cocoa_destroy(void *data) { -#if !__has_feature(objc_arc) ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; CocoaView *cocoa_view = (CocoaView*)cocoa->data; - // TODO(sgc): incorrect behavior [[cocoa_view window] release]; -#endif } static void ui_window_cocoa_set_focused(void *data) { ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; - CocoaView *cocoa_view = (BRIDGE CocoaView*)cocoa->data; + CocoaView *cocoa_view = (CocoaView*)cocoa->data; [[cocoa_view window] makeKeyAndOrderFront:nil]; } @@ -51,7 +48,7 @@ static void ui_window_cocoa_set_visible(void *data, bool set_visible) { ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; - CocoaView *cocoa_view = (BRIDGE CocoaView*)cocoa->data; + CocoaView *cocoa_view = (CocoaView*)cocoa->data; if (set_visible) [[cocoa_view window] makeKeyAndOrderFront:nil]; else @@ -61,7 +58,7 @@ static void ui_window_cocoa_set_visible(void *data, static void ui_window_cocoa_set_title(void *data, char *buf) { ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; - CocoaView *cocoa_view = (BRIDGE CocoaView*)cocoa->data; + CocoaView *cocoa_view = (CocoaView*)cocoa->data; const char* const text = buf; /* < Can't access buffer directly in the block */ [[cocoa_view window] setTitle:[NSString stringWithCString:text encoding:NSUTF8StringEncoding]]; } @@ -69,7 +66,7 @@ static void ui_window_cocoa_set_title(void *data, char *buf) static void ui_window_cocoa_set_droppable(void *data, bool droppable) { ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; - CocoaView *cocoa_view = (BRIDGE CocoaView*)cocoa->data; + CocoaView *cocoa_view = (CocoaView*)cocoa->data; if (droppable) { @@ -84,7 +81,7 @@ static void ui_window_cocoa_set_droppable(void *data, bool droppable) static bool ui_window_cocoa_focused(void *data) { ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; - CocoaView *cocoa_view = (BRIDGE CocoaView*)cocoa->data; + CocoaView *cocoa_view = (CocoaView*)cocoa->data; if ([[cocoa_view window] isMainWindow] == YES) return true; return false; diff --git a/ui/drivers/cocoa/ui_cocoa_window_metal.m b/ui/drivers/cocoa/ui_cocoa_window_metal.m new file mode 100644 index 0000000000..d9f39db124 --- /dev/null +++ b/ui/drivers/cocoa/ui_cocoa_window_metal.m @@ -0,0 +1,102 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include +#include + +#include + +#include "cocoa_common_metal.h" +#include "../ui_cocoa_metal.h" +#include "../../ui_companion_driver.h" + +static void* ui_window_cocoa_init(void) +{ + return NULL; +} + +static void ui_window_cocoa_destroy(void *data) +{ +#if !__has_feature(objc_arc) + ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; + CocoaView *cocoa_view = (CocoaView*)cocoa->data; + // TODO(sgc): incorrect behavior + [[cocoa_view window] release]; +#endif +} + +static void ui_window_cocoa_set_focused(void *data) +{ + ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; + CocoaView *cocoa_view = (BRIDGE CocoaView*)cocoa->data; + [[cocoa_view window] makeKeyAndOrderFront:nil]; +} + +static void ui_window_cocoa_set_visible(void *data, + bool set_visible) +{ + ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; + CocoaView *cocoa_view = (BRIDGE CocoaView*)cocoa->data; + if (set_visible) + [[cocoa_view window] makeKeyAndOrderFront:nil]; + else + [[cocoa_view window] orderOut:nil]; +} + +static void ui_window_cocoa_set_title(void *data, char *buf) +{ + ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; + CocoaView *cocoa_view = (BRIDGE CocoaView*)cocoa->data; + const char* const text = buf; /* < Can't access buffer directly in the block */ + [[cocoa_view window] setTitle:[NSString stringWithCString:text encoding:NSUTF8StringEncoding]]; +} + +static void ui_window_cocoa_set_droppable(void *data, bool droppable) +{ + ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; + CocoaView *cocoa_view = (BRIDGE CocoaView*)cocoa->data; + + if (droppable) + { + [[cocoa_view window] registerForDraggedTypes:[NSArray arrayWithObjects:NSColorPboardType, NSFilenamesPboardType, nil]]; + } + else + { + [[cocoa_view window] unregisterDraggedTypes]; + } +} + +static bool ui_window_cocoa_focused(void *data) +{ + ui_window_cocoa_t *cocoa = (ui_window_cocoa_t*)data; + CocoaView *cocoa_view = (BRIDGE CocoaView*)cocoa->data; + if ([[cocoa_view window] isMainWindow] == YES) + return true; + return false; +} + +ui_window_t ui_window_cocoa = { + ui_window_cocoa_init, + ui_window_cocoa_destroy, + ui_window_cocoa_set_focused, + ui_window_cocoa_set_visible, + ui_window_cocoa_set_title, + ui_window_cocoa_set_droppable, + ui_window_cocoa_focused, + "cocoa" +}; diff --git a/ui/drivers/ui_cocoa.h b/ui/drivers/ui_cocoa.h index 6b50692cef..11f6f5c5c0 100644 --- a/ui/drivers/ui_cocoa.h +++ b/ui/drivers/ui_cocoa.h @@ -36,7 +36,7 @@ typedef struct ui_application_cocoa typedef struct ui_window_cocoa { - void *data; + CocoaView *data; } ui_window_cocoa_t; RETRO_END_DECLS diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index bf917f53cf..d790dda58e 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -36,48 +36,16 @@ #include "../../core.h" #include "../../retroarch.h" #include "../../tasks/tasks_internal.h" -#include ".././verbosity.h" -#ifdef HAVE_METAL -#import -#import -#endif - -#if !((defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))) -@interface WindowListener : NSResponder -@end - -@implementation WindowListener - -/* Similarly to SDL, we'll respond to key events by doing nothing so we don't beep. - */ -- (void)flagsChanged:(NSEvent *)event -{} - -- (void)keyDown:(NSEvent *)event -{} - -- (void)keyUp:(NSEvent *)event -{} - -@end -#endif - -id apple_platform; +id apple_platform; #if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))) -@interface RetroArch_OSX : NSObject +@interface RetroArch_OSX : NSObject #else -@interface RetroArch_OSX : NSObject +@interface RetroArch_OSX : NSObject #endif { - NSWindow* _window; - apple_view_type_t _vt; - NSView* _renderView; - id _sleepActivity; -#if !(defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))) - WindowListener *_listener; -#endif + NSWindow* _window; } @property (nonatomic, retain) NSWindow IBOutlet* window; @@ -88,55 +56,26 @@ static void app_terminate(void) { [[NSApplication sharedApplication] terminate:nil]; } -#ifdef HAVE_METAL -@interface RAWindow : NSWindow -@end -@implementation RAWindow -#else @interface RApplication : NSApplication @end @implementation RApplication -#endif -#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 -#define NSEventTypeKeyDown NSKeyDown -#define NSEventTypeKeyUp NSKeyUp -#define NSEventTypeFlagsChanged NSFlagsChanged -#define NSEventTypeMouseMoved NSMouseMoved -#define NSEventTypeLeftMouseDragged NSLeftMouseDragged -#define NSEventTypeRightMouseDragged NSRightMouseDragged -#define NSEventTypeOtherMouseDragged NSOtherMouseDragged -#define NSEventTypeLeftMouseDown NSLeftMouseDown -#define NSEventTypeRightMouseDown NSRightMouseDown -#define NSEventTypeOtherMouseDown NSOtherMouseDown -#define NSEventTypeLeftMouseUp NSLeftMouseUp -#define NSEventTypeRightMouseUp NSRightMouseUp -#define NSEventTypeOtherMouseUp NSOtherMouseUp -#define NSEventTypeScrollWheel NSScrollWheel - -// modifier flags -#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask -#define NSEventModifierFlagShift NSShiftKeyMask -#define NSEventModifierFlagControl NSControlKeyMask -#define NSEventModifierFlagOption NSAlternateKeyMask -#define NSEventModifierFlagCommand NSCommandKeyMask -#define NSEventModifierFlagNumericPad NSNumericPadKeyMask -#endif - -- (void)sendEvent:(NSEvent *)event { - [super sendEvent:event]; - +- (void)sendEvent:(NSEvent *)event +{ + NSEventType event_type; cocoa_input_data_t *apple = NULL; - NSEventType event_type = event.type; + [super sendEvent:event]; - switch (event_type) + event_type = event.type; + + switch ((int32_t)event_type) { - case NSEventTypeKeyDown: - case NSEventTypeKeyUp: + case NSKeyDown: + case NSKeyUp: { - NSString* ch = event.characters; + NSString* ch = (NSString*)event.characters; uint32_t character = 0; uint32_t mod = 0; @@ -145,29 +84,29 @@ static void app_terminate(void) uint32_t i; character = [ch characterAtIndex:0]; - if (event.modifierFlags & NSEventModifierFlagCapsLock) + if (event.modifierFlags & NSAlphaShiftKeyMask) mod |= RETROKMOD_CAPSLOCK; - if (event.modifierFlags & NSEventModifierFlagShift) + if (event.modifierFlags & NSShiftKeyMask) mod |= RETROKMOD_SHIFT; - if (event.modifierFlags & NSEventModifierFlagControl) + if (event.modifierFlags & NSControlKeyMask) mod |= RETROKMOD_CTRL; - if (event.modifierFlags & NSEventModifierFlagOption) + if (event.modifierFlags & NSAlternateKeyMask) mod |= RETROKMOD_ALT; - if (event.modifierFlags & NSEventModifierFlagCommand) + if (event.modifierFlags & NSCommandKeyMask) mod |= RETROKMOD_META; - if (event.modifierFlags & NSEventModifierFlagNumericPad) + if (event.modifierFlags & NSNumericPadKeyMask) mod |= RETROKMOD_NUMLOCK; for (i = 1; i < ch.length; i++) - apple_input_keyboard_event(event_type == NSEventTypeKeyDown, + apple_input_keyboard_event(event_type == NSKeyDown, 0, [ch characterAtIndex:i], mod, RETRO_DEVICE_KEYBOARD); } - apple_input_keyboard_event(event_type == NSEventTypeKeyDown, + apple_input_keyboard_event(event_type == NSKeyDown, event.keyCode, character, mod, RETRO_DEVICE_KEYBOARD); } break; - case NSEventTypeFlagsChanged: + case NSFlagsChanged: { static uint32_t old_flags = 0; uint32_t new_flags = event.modifierFlags; @@ -179,10 +118,10 @@ static void app_terminate(void) 0, event.modifierFlags, RETRO_DEVICE_KEYBOARD); } break; - case NSEventTypeMouseMoved: - case NSEventTypeLeftMouseDragged: - case NSEventTypeRightMouseDragged: - case NSEventTypeOtherMouseDragged: + case NSMouseMoved: + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: { NSPoint pos; NSPoint mouse_pos; @@ -191,27 +130,27 @@ static void app_terminate(void) return; /* Relative */ - apple->mouse_rel_x = (int16_t)event.deltaX; - apple->mouse_rel_y = (int16_t)event.deltaY; + apple->mouse_rel_x = event.deltaX; + apple->mouse_rel_y = event.deltaY; /* Absolute */ - pos = [apple_platform.renderView convertPoint:[event locationInWindow] fromView:nil]; - apple->touches[0].screen_x = (int16_t)pos.x; - apple->touches[0].screen_y = (int16_t)pos.y; + pos = [[CocoaView get] convertPoint:[event locationInWindow] fromView:nil]; + apple->touches[0].screen_x = pos.x; + apple->touches[0].screen_y = pos.y; - mouse_pos = [apple_platform.renderView convertPoint:[event locationInWindow] fromView:nil]; + mouse_pos = [[CocoaView get] convertPoint:[event locationInWindow] fromView:nil]; apple->window_pos_x = (int16_t)mouse_pos.x; apple->window_pos_y = (int16_t)mouse_pos.y; } break; - case NSEventTypeScrollWheel: + case NSScrollWheel: /* TODO/FIXME - properly implement. */ break; - case NSEventTypeLeftMouseDown: - case NSEventTypeRightMouseDown: - case NSEventTypeOtherMouseDown: + case NSLeftMouseDown: + case NSRightMouseDown: + case NSOtherMouseDown: { - NSPoint pos = [apple_platform.renderView convertPoint:[event locationInWindow] fromView:nil]; + NSPoint pos = [[CocoaView get] convertPoint:[event locationInWindow] fromView:nil]; apple = (cocoa_input_data_t*)input_driver_get_data(); if (!apple || pos.y < 0) return; @@ -220,11 +159,11 @@ static void app_terminate(void) apple->touch_count = 1; } break; - case NSEventTypeLeftMouseUp: - case NSEventTypeRightMouseUp: - case NSEventTypeOtherMouseUp: + case NSLeftMouseUp: + case NSRightMouseUp: + case NSOtherMouseUp: { - NSPoint pos = [apple_platform.renderView convertPoint:[event locationInWindow] fromView:nil]; + NSPoint pos = [[CocoaView get] convertPoint:[event locationInWindow] fromView:nil]; apple = (cocoa_input_data_t*)input_driver_get_data(); if (!apple || pos.y < 0) return; @@ -232,8 +171,6 @@ static void app_terminate(void) apple->touch_count = 0; } break; - default: - break; } } @@ -246,41 +183,33 @@ static char** waiting_argv; @synthesize window = _window; -#if !__has_feature(objc_arc) - (void)dealloc { [_window release]; [super dealloc]; } -#endif #define NS_WINDOW_COLLECTION_BEHAVIOR_FULLSCREEN_PRIMARY (1 << 17) - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { unsigned i; - apple_platform = self; - SEL selector = NSSelectorFromString(BOXSTRING("setCollectionBehavior:")); SEL fsselector = NSSelectorFromString(BOXSTRING("toggleFullScreen:")); + apple_platform = self; if ([self.window respondsToSelector:selector]) { if ([self.window respondsToSelector:fsselector]) [self.window setCollectionBehavior:NS_WINDOW_COLLECTION_BEHAVIOR_FULLSCREEN_PRIMARY]; } - -#if !(defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))) - _listener = [WindowListener new]; -#endif - + [self.window setAcceptsMouseMovedEvents: YES]; -#if !(defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))) - [self.window setNextResponder:_listener]; - self.window.delegate = _listener; -#endif - + + [[CocoaView get] setFrame: [[self.window contentView] bounds]]; [[self.window contentView] setAutoresizesSubviews:YES]; + [[self.window contentView] addSubview:[CocoaView get]]; + [self.window makeFirstResponder:[CocoaView get]]; for (i = 0; i < waiting_argc; i++) { @@ -295,156 +224,26 @@ static char** waiting_argv; app_terminate(); waiting_argc = 0; - - [self.window makeMainWindow]; - [self.window makeKeyWindow]; - + [self performSelectorOnMainThread:@selector(rarch_main) withObject:nil waitUntilDone:NO]; } -#pragma mark - ApplePlatform - -- (void)setViewType:(apple_view_type_t)vt { - if (vt == _vt) { - return; - } - - RARCH_LOG("[Cocoa]: change view type: %d → %d\n", _vt, vt); - - _vt = vt; - if (_renderView != nil) - { - _renderView.wantsLayer = NO; - _renderView.layer = nil; - [_renderView removeFromSuperview]; - self.window.contentView = nil; - _renderView = nil; - } - - switch (vt) { - case APPLE_VIEW_TYPE_VULKAN: - case APPLE_VIEW_TYPE_METAL: -#if defined(HAVE_METAL) || defined(HAVE_VULKAN) - { - MetalView *v = [MetalView new]; - v.paused = YES; - v.enableSetNeedsDisplay = NO; - _renderView = v; - } -#endif - break; - - case APPLE_VIEW_TYPE_OPENGL: - { - _renderView = [CocoaView get]; - break; - } - - case APPLE_VIEW_TYPE_NONE: - default: - return; - } - - _renderView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; - [_renderView setFrame: [[self.window contentView] bounds]]; - - self.window.contentView = _renderView; -#if !(defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))) - [self.window.contentView setNextResponder:_listener]; -#endif -} - -- (apple_view_type_t)viewType { - return _vt; -} - -- (id)renderView { - return _renderView; -} - -- (bool)hasFocus { - return [NSApp isActive]; -} - -- (void)setVideoMode:(gfx_ctx_mode_t)mode { -#ifdef HAVE_METAL - BOOL isFullScreen = (self.window.styleMask & NSFullScreenWindowMask) == NSFullScreenWindowMask; - if (mode.fullscreen && !isFullScreen) - { - [self.window toggleFullScreen:self]; - return; - } - - if (!mode.fullscreen && isFullScreen) - { - [self.window toggleFullScreen:self]; - } - - if (mode.width > 0) - { - // HACK(sgc): ensure MTKView posts a drawable resize event - [self.window setContentSize:NSMakeSize(mode.width-1, mode.height)]; - } - [self.window setContentSize:NSMakeSize(mode.width, mode.height)]; -#endif -} - -- (void)setCursorVisible:(bool)v { - if (v) - [NSCursor unhide]; - else - [NSCursor hide]; -} - -- (bool)setDisableDisplaySleep:(bool)disable -{ -#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 - if (disable && _sleepActivity == nil) - { - _sleepActivity = [NSProcessInfo.processInfo beginActivityWithOptions:NSActivityIdleDisplaySleepDisabled reason:@"disable screen saver"]; - } - else if (!disable && _sleepActivity != nil) - { - [NSProcessInfo.processInfo endActivity:_sleepActivity]; - _sleepActivity = nil; - } - return YES; -#else - return NO; -#endif - -} - - - (void) rarch_main { do { int ret; unsigned sleep_ms = 0; -#ifdef HAVE_QT - const ui_application_t *application = &ui_application_qt; -#else const ui_application_t *application = ui_companion_driver_get_application_ptr(); -#endif if (application) application->process_events(); - ret = runloop_iterate(&sleep_ms); - if (ret == 1 && sleep_ms > 0) retro_sleep(sleep_ms); - task_queue_check(); - while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, FALSE) == kCFRunLoopRunHandledSource); if (ret == -1) - { -#ifdef HAVE_QT - ui_application_qt.quit(); -#endif break; - } }while(1); main_exit(NULL); @@ -470,7 +269,7 @@ static char** waiting_argv; if (rarch_ctl(RARCH_CTL_IS_INITED, NULL)) reply = NSTerminateCancel; - command_event(CMD_EVENT_QUIT, NULL); + ui_companion_event_command(CMD_EVENT_QUIT); return reply; } @@ -480,9 +279,13 @@ static char** waiting_argv; { if (filenames.count == 1 && [filenames objectAtIndex:0]) { - struct retro_system_info *system = runloop_get_libretro_system_info(); + rarch_system_info_t *info = runloop_get_system_info(); + struct retro_system_info *system = &info->info; NSString *__core = [filenames objectAtIndex:0]; - const char *core_name = system ? system->library_name : NULL; + const char *core_name = NULL; + + if (system) + core_name = system->library_name; if (core_name) { @@ -505,7 +308,7 @@ static char** waiting_argv; { ui_msg_window_state msg_window_state; msg_window_state.text = strdup("Cannot open multiple files"); - msg_window_state.title = strdup(msg_hash_to_str(MSG_PROGRAM)); + msg_window_state.title = strdup("RetroArch"); msg_window->information(&msg_window_state); free(msg_window_state.text); @@ -552,8 +355,12 @@ static void open_document_handler(ui_browser_window_state_t *state, bool result) if (!result) return; - struct retro_system_info *system = runloop_get_libretro_system_info(); - const char *core_name = system ? system->library_name : NULL; + rarch_system_info_t *info = runloop_get_system_info(); + struct retro_system_info *system = &info->info; + const char *core_name = NULL; + + if (system) + core_name = system->library_name; path_set(RARCH_PATH_CONTENT, state->result); @@ -577,8 +384,8 @@ static void open_document_handler(ui_browser_window_state_t *state, bool result) settings_t *settings = config_get_ptr(); browser_state.filters = strdup("dylib"); - browser_state.filters_title = strdup(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_SETTINGS)); - browser_state.title = strdup(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LIST)); + browser_state.filters_title = strdup("Core"); + browser_state.title = strdup("Load Core"); browser_state.startdir = strdup(settings->paths.directory_libretro); bool result = browser->open(&browser_state); @@ -604,7 +411,7 @@ static void open_document_handler(ui_browser_window_state_t *state, bool result) if (!startdir.length) startdir = BOXSTRING("/"); - browser_state.title = strdup(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST)); + browser_state.title = strdup("Load Content"); browser_state.startdir = strdup([startdir UTF8String]); bool result = browser->open(&browser_state); @@ -749,7 +556,7 @@ static void *ui_companion_cocoa_init(void) static void ui_companion_cocoa_event_command(void *data, enum event_command cmd) { (void)data; - (void)cmd; + command_event(cmd, NULL); } static void ui_companion_cocoa_notify_list_pushed(void *data, @@ -762,7 +569,7 @@ static void ui_companion_cocoa_notify_list_pushed(void *data, static void *ui_companion_cocoa_get_main_window(void *data) { - return (BRIDGE void *)((RetroArch_OSX*)[[NSApplication sharedApplication] delegate]).window; + return ((RetroArch_OSX*)[[NSApplication sharedApplication] delegate]).window; } ui_companion_driver_t ui_companion_cocoa = { @@ -773,11 +580,11 @@ ui_companion_driver_t ui_companion_cocoa = { ui_companion_cocoa_event_command, ui_companion_cocoa_notify_content_loaded, ui_companion_cocoa_notify_list_pushed, - NULL, /* notify_refresh */ - NULL, /* msg_queue_push */ - NULL, /* render_messagebox */ + NULL, + NULL, + NULL, ui_companion_cocoa_get_main_window, - NULL, /* log_msg */ + NULL, &ui_browser_window_cocoa, &ui_msg_window_cocoa, &ui_window_cocoa, diff --git a/ui/drivers/ui_cocoa_metal.h b/ui/drivers/ui_cocoa_metal.h new file mode 100644 index 0000000000..8bbe7cd8c7 --- /dev/null +++ b/ui/drivers/ui_cocoa_metal.h @@ -0,0 +1,44 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#ifndef _COCOA_METAL_UI +#define _COCOA_METAL_UI + +#include +#include + +#include +#include + +#include "cocoa/cocoa_common_metal.h" + +#include "../ui_companion_driver.h" + +RETRO_BEGIN_DECLS + +typedef struct ui_application_cocoa +{ + void *empty; +} ui_application_cocoa_t; + +typedef struct ui_window_cocoa +{ + void *data; +} ui_window_cocoa_t; + +RETRO_END_DECLS + +#endif diff --git a/ui/drivers/ui_cocoa_metal.m b/ui/drivers/ui_cocoa_metal.m new file mode 100644 index 0000000000..854fac7de5 --- /dev/null +++ b/ui/drivers/ui_cocoa_metal.m @@ -0,0 +1,786 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2013-2014 - Jason Fetters + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "cocoa/cocoa_common_metal.h" +#include "../ui_companion_driver.h" +#include "../../input/drivers/cocoa_input.h" +#include "../../input/drivers_keyboard/keyboard_event_apple.h" +#include "../../frontend/frontend.h" +#include "../../configuration.h" +#include "../../paths.h" +#include "../../core.h" +#include "../../retroarch.h" +#include "../../tasks/tasks_internal.h" +#include ".././verbosity.h" + +#ifdef HAVE_METAL +#import +#import +#endif + +#if !((defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__)))) +@interface WindowListener : NSResponder +@end + +@implementation WindowListener + +/* Similarly to SDL, we'll respond to key events by doing nothing so we don't beep. + */ +- (void)flagsChanged:(NSEvent *)event +{} + +- (void)keyDown:(NSEvent *)event +{} + +- (void)keyUp:(NSEvent *)event +{} + +@end +#endif + +id apple_platform; + +#if (defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))) +@interface RetroArch_OSX : NSObject +#else +@interface RetroArch_OSX : NSObject +#endif +{ + NSWindow* _window; + apple_view_type_t _vt; + NSView* _renderView; + id _sleepActivity; +#if !(defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))) + WindowListener *_listener; +#endif +} + +@property (nonatomic, retain) NSWindow IBOutlet* window; + +@end + +static void app_terminate(void) +{ + [[NSApplication sharedApplication] terminate:nil]; +} +#ifdef HAVE_METAL +@interface RAWindow : NSWindow +@end + +@implementation RAWindow +#else +@interface RApplication : NSApplication +@end + +@implementation RApplication +#endif + +#if MAC_OS_X_VERSION_MAX_ALLOWED < 101200 +#define NSEventTypeKeyDown NSKeyDown +#define NSEventTypeKeyUp NSKeyUp +#define NSEventTypeFlagsChanged NSFlagsChanged +#define NSEventTypeMouseMoved NSMouseMoved +#define NSEventTypeLeftMouseDragged NSLeftMouseDragged +#define NSEventTypeRightMouseDragged NSRightMouseDragged +#define NSEventTypeOtherMouseDragged NSOtherMouseDragged +#define NSEventTypeLeftMouseDown NSLeftMouseDown +#define NSEventTypeRightMouseDown NSRightMouseDown +#define NSEventTypeOtherMouseDown NSOtherMouseDown +#define NSEventTypeLeftMouseUp NSLeftMouseUp +#define NSEventTypeRightMouseUp NSRightMouseUp +#define NSEventTypeOtherMouseUp NSOtherMouseUp +#define NSEventTypeScrollWheel NSScrollWheel + +// modifier flags +#define NSEventModifierFlagCapsLock NSAlphaShiftKeyMask +#define NSEventModifierFlagShift NSShiftKeyMask +#define NSEventModifierFlagControl NSControlKeyMask +#define NSEventModifierFlagOption NSAlternateKeyMask +#define NSEventModifierFlagCommand NSCommandKeyMask +#define NSEventModifierFlagNumericPad NSNumericPadKeyMask +#endif + +- (void)sendEvent:(NSEvent *)event { + [super sendEvent:event]; + + cocoa_input_data_t *apple = NULL; + NSEventType event_type = event.type; + + switch (event_type) + { + case NSEventTypeKeyDown: + case NSEventTypeKeyUp: + { + NSString* ch = event.characters; + uint32_t character = 0; + uint32_t mod = 0; + + if (ch && ch.length != 0) + { + uint32_t i; + character = [ch characterAtIndex:0]; + + if (event.modifierFlags & NSEventModifierFlagCapsLock) + mod |= RETROKMOD_CAPSLOCK; + if (event.modifierFlags & NSEventModifierFlagShift) + mod |= RETROKMOD_SHIFT; + if (event.modifierFlags & NSEventModifierFlagControl) + mod |= RETROKMOD_CTRL; + if (event.modifierFlags & NSEventModifierFlagOption) + mod |= RETROKMOD_ALT; + if (event.modifierFlags & NSEventModifierFlagCommand) + mod |= RETROKMOD_META; + if (event.modifierFlags & NSEventModifierFlagNumericPad) + mod |= RETROKMOD_NUMLOCK; + + for (i = 1; i < ch.length; i++) + apple_input_keyboard_event(event_type == NSEventTypeKeyDown, + 0, [ch characterAtIndex:i], mod, RETRO_DEVICE_KEYBOARD); + } + + apple_input_keyboard_event(event_type == NSEventTypeKeyDown, + event.keyCode, character, mod, RETRO_DEVICE_KEYBOARD); + } + break; + case NSEventTypeFlagsChanged: + { + static uint32_t old_flags = 0; + uint32_t new_flags = event.modifierFlags; + bool down = (new_flags & old_flags) == old_flags; + + old_flags = new_flags; + + apple_input_keyboard_event(down, event.keyCode, + 0, event.modifierFlags, RETRO_DEVICE_KEYBOARD); + } + break; + case NSEventTypeMouseMoved: + case NSEventTypeLeftMouseDragged: + case NSEventTypeRightMouseDragged: + case NSEventTypeOtherMouseDragged: + { + NSPoint pos; + NSPoint mouse_pos; + apple = (cocoa_input_data_t*)input_driver_get_data(); + if (!apple) + return; + + /* Relative */ + apple->mouse_rel_x = (int16_t)event.deltaX; + apple->mouse_rel_y = (int16_t)event.deltaY; + + /* Absolute */ + pos = [apple_platform.renderView convertPoint:[event locationInWindow] fromView:nil]; + apple->touches[0].screen_x = (int16_t)pos.x; + apple->touches[0].screen_y = (int16_t)pos.y; + + mouse_pos = [apple_platform.renderView convertPoint:[event locationInWindow] fromView:nil]; + apple->window_pos_x = (int16_t)mouse_pos.x; + apple->window_pos_y = (int16_t)mouse_pos.y; + } + break; + case NSEventTypeScrollWheel: + /* TODO/FIXME - properly implement. */ + break; + case NSEventTypeLeftMouseDown: + case NSEventTypeRightMouseDown: + case NSEventTypeOtherMouseDown: + { + NSPoint pos = [apple_platform.renderView convertPoint:[event locationInWindow] fromView:nil]; + apple = (cocoa_input_data_t*)input_driver_get_data(); + if (!apple || pos.y < 0) + return; + apple->mouse_buttons |= 1 << event.buttonNumber; + + apple->touch_count = 1; + } + break; + case NSEventTypeLeftMouseUp: + case NSEventTypeRightMouseUp: + case NSEventTypeOtherMouseUp: + { + NSPoint pos = [apple_platform.renderView convertPoint:[event locationInWindow] fromView:nil]; + apple = (cocoa_input_data_t*)input_driver_get_data(); + if (!apple || pos.y < 0) + return; + apple->mouse_buttons &= ~(1 << event.buttonNumber); + apple->touch_count = 0; + } + break; + default: + break; + } +} + +@end + +static int waiting_argc; +static char** waiting_argv; + +@implementation RetroArch_OSX + +@synthesize window = _window; + +#if !__has_feature(objc_arc) +- (void)dealloc +{ + [_window release]; + [super dealloc]; +} +#endif + +#define NS_WINDOW_COLLECTION_BEHAVIOR_FULLSCREEN_PRIMARY (1 << 17) + +- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +{ + unsigned i; + apple_platform = self; + + SEL selector = NSSelectorFromString(BOXSTRING("setCollectionBehavior:")); + SEL fsselector = NSSelectorFromString(BOXSTRING("toggleFullScreen:")); + + if ([self.window respondsToSelector:selector]) + { + if ([self.window respondsToSelector:fsselector]) + [self.window setCollectionBehavior:NS_WINDOW_COLLECTION_BEHAVIOR_FULLSCREEN_PRIMARY]; + } + +#if !(defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))) + _listener = [WindowListener new]; +#endif + + [self.window setAcceptsMouseMovedEvents: YES]; +#if !(defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))) + [self.window setNextResponder:_listener]; + self.window.delegate = _listener; +#endif + + [[self.window contentView] setAutoresizesSubviews:YES]; + + for (i = 0; i < waiting_argc; i++) + { + if (string_is_equal(waiting_argv[i], "-NSDocumentRevisionsDebugMode")) + { + waiting_argv[i] = NULL; + waiting_argv[i+1] = NULL; + waiting_argc -= 2; + } + } + if (rarch_main(waiting_argc, waiting_argv, NULL)) + app_terminate(); + + waiting_argc = 0; + + [self.window makeMainWindow]; + [self.window makeKeyWindow]; + + [self performSelectorOnMainThread:@selector(rarch_main) withObject:nil waitUntilDone:NO]; +} + +#pragma mark - ApplePlatform + +- (void)setViewType:(apple_view_type_t)vt { + if (vt == _vt) { + return; + } + + RARCH_LOG("[Cocoa]: change view type: %d → %d\n", _vt, vt); + + _vt = vt; + if (_renderView != nil) + { + _renderView.wantsLayer = NO; + _renderView.layer = nil; + [_renderView removeFromSuperview]; + self.window.contentView = nil; + _renderView = nil; + } + + switch (vt) { + case APPLE_VIEW_TYPE_VULKAN: + case APPLE_VIEW_TYPE_METAL: +#if defined(HAVE_METAL) || defined(HAVE_VULKAN) + { + MetalView *v = [MetalView new]; + v.paused = YES; + v.enableSetNeedsDisplay = NO; + _renderView = v; + } +#endif + break; + + case APPLE_VIEW_TYPE_OPENGL: + { + _renderView = [CocoaView get]; + break; + } + + case APPLE_VIEW_TYPE_NONE: + default: + return; + } + + _renderView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable; + [_renderView setFrame: [[self.window contentView] bounds]]; + + self.window.contentView = _renderView; +#if !(defined(__MACH__) && (defined(__ppc__) || defined(__ppc64__))) + [self.window.contentView setNextResponder:_listener]; +#endif +} + +- (apple_view_type_t)viewType { + return _vt; +} + +- (id)renderView { + return _renderView; +} + +- (bool)hasFocus { + return [NSApp isActive]; +} + +- (void)setVideoMode:(gfx_ctx_mode_t)mode { +#ifdef HAVE_METAL + BOOL isFullScreen = (self.window.styleMask & NSFullScreenWindowMask) == NSFullScreenWindowMask; + if (mode.fullscreen && !isFullScreen) + { + [self.window toggleFullScreen:self]; + return; + } + + if (!mode.fullscreen && isFullScreen) + { + [self.window toggleFullScreen:self]; + } + + if (mode.width > 0) + { + // HACK(sgc): ensure MTKView posts a drawable resize event + [self.window setContentSize:NSMakeSize(mode.width-1, mode.height)]; + } + [self.window setContentSize:NSMakeSize(mode.width, mode.height)]; +#endif +} + +- (void)setCursorVisible:(bool)v { + if (v) + [NSCursor unhide]; + else + [NSCursor hide]; +} + +- (bool)setDisableDisplaySleep:(bool)disable +{ +#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 + if (disable && _sleepActivity == nil) + { + _sleepActivity = [NSProcessInfo.processInfo beginActivityWithOptions:NSActivityIdleDisplaySleepDisabled reason:@"disable screen saver"]; + } + else if (!disable && _sleepActivity != nil) + { + [NSProcessInfo.processInfo endActivity:_sleepActivity]; + _sleepActivity = nil; + } + return YES; +#else + return NO; +#endif + +} + + +- (void) rarch_main +{ + do + { + int ret; + unsigned sleep_ms = 0; +#ifdef HAVE_QT + const ui_application_t *application = &ui_application_qt; +#else + const ui_application_t *application = ui_companion_driver_get_application_ptr(); +#endif + if (application) + application->process_events(); + + ret = runloop_iterate(&sleep_ms); + + if (ret == 1 && sleep_ms > 0) + retro_sleep(sleep_ms); + + task_queue_check(); + + while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, FALSE) == kCFRunLoopRunHandledSource); + if (ret == -1) + { +#ifdef HAVE_QT + ui_application_qt.quit(); +#endif + break; + } + }while(1); + + main_exit(NULL); +} + +- (void)applicationDidBecomeActive:(NSNotification *)notification +{ +} + +- (void)applicationWillResignActive:(NSNotification *)notification +{ +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication +{ + return YES; +} + +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender +{ + NSApplicationTerminateReply reply = NSTerminateNow; + + if (rarch_ctl(RARCH_CTL_IS_INITED, NULL)) + reply = NSTerminateCancel; + + command_event(CMD_EVENT_QUIT, NULL); + + return reply; +} + + +- (void)application:(NSApplication *)sender openFiles:(NSArray *)filenames +{ + if (filenames.count == 1 && [filenames objectAtIndex:0]) + { + struct retro_system_info *system = runloop_get_libretro_system_info(); + NSString *__core = [filenames objectAtIndex:0]; + const char *core_name = system ? system->library_name : NULL; + + if (core_name) + { + content_ctx_info_t content_info = {0}; + task_push_load_content_with_current_core_from_companion_ui( + __core.UTF8String, + &content_info, + CORE_TYPE_PLAIN, + NULL, NULL); + } + else + path_set(RARCH_PATH_CONTENT, __core.UTF8String); + + [sender replyToOpenOrPrint:NSApplicationDelegateReplySuccess]; + } + else + { + const ui_msg_window_t *msg_window = ui_companion_driver_get_msg_window_ptr(); + if (msg_window) + { + ui_msg_window_state msg_window_state; + msg_window_state.text = strdup("Cannot open multiple files"); + msg_window_state.title = strdup(msg_hash_to_str(MSG_PROGRAM)); + msg_window->information(&msg_window_state); + + free(msg_window_state.text); + free(msg_window_state.title); + } + [sender replyToOpenOrPrint:NSApplicationDelegateReplyFailure]; + } +} + +static void open_core_handler(ui_browser_window_state_t *state, bool result) +{ + rarch_system_info_t *info = runloop_get_system_info(); + if (!state) + return; + if (string_is_empty(state->result)) + return; + if (!result) + return; + + settings_t *settings = config_get_ptr(); + + rarch_ctl(RARCH_CTL_SET_LIBRETRO_PATH, (void*)state->result); + ui_companion_event_command(CMD_EVENT_LOAD_CORE); + + if (info && info->load_no_content + && settings->bools.set_supports_no_game_enable) + { + content_ctx_info_t content_info = {0}; + path_clear(RARCH_PATH_CONTENT); + task_push_load_content_with_current_core_from_companion_ui( + NULL, + &content_info, + CORE_TYPE_PLAIN, + NULL, NULL); + } +} + +static void open_document_handler(ui_browser_window_state_t *state, bool result) +{ + if (!state) + return; + if (string_is_empty(state->result)) + return; + if (!result) + return; + + struct retro_system_info *system = runloop_get_libretro_system_info(); + const char *core_name = system ? system->library_name : NULL; + + path_set(RARCH_PATH_CONTENT, state->result); + + if (core_name) + { + content_ctx_info_t content_info = {0}; + task_push_load_content_with_current_core_from_companion_ui( + NULL, + &content_info, + CORE_TYPE_PLAIN, + NULL, NULL); + } +} + +- (IBAction)openCore:(id)sender { + const ui_browser_window_t *browser = ui_companion_driver_get_browser_window_ptr(); + + if (browser) + { + ui_browser_window_state_t browser_state; + settings_t *settings = config_get_ptr(); + + browser_state.filters = strdup("dylib"); + browser_state.filters_title = strdup(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_SETTINGS)); + browser_state.title = strdup(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LIST)); + browser_state.startdir = strdup(settings->paths.directory_libretro); + + bool result = browser->open(&browser_state); + open_core_handler(&browser_state, result); + + free(browser_state.filters); + free(browser_state.filters_title); + free(browser_state.title); + free(browser_state.startdir); + } +} + +- (void)openDocument:(id)sender +{ + const ui_browser_window_t *browser = ui_companion_driver_get_browser_window_ptr(); + + if (browser) + { + ui_browser_window_state_t browser_state = {{0}}; + settings_t *settings = config_get_ptr(); + NSString *startdir = BOXSTRING(settings->paths.directory_menu_content); + + if (!startdir.length) + startdir = BOXSTRING("/"); + + browser_state.title = strdup(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST)); + browser_state.startdir = strdup([startdir UTF8String]); + + bool result = browser->open(&browser_state); + open_document_handler(&browser_state, result); + + free(browser_state.startdir); + free(browser_state.title); + } +} + +- (void)unloadingCore +{ +} + +- (IBAction)showCoresDirectory:(id)sender +{ + settings_t *settings = config_get_ptr(); + [[NSWorkspace sharedWorkspace] openFile:BOXSTRING(settings->paths.directory_libretro)]; +} + +- (IBAction)showPreferences:(id)sender +{ +} + +- (IBAction)basicEvent:(id)sender +{ + enum event_command cmd; + unsigned sender_tag = (unsigned)[sender tag]; + + switch (sender_tag) + { + case 1: + cmd = CMD_EVENT_RESET; + break; + case 2: + cmd = CMD_EVENT_LOAD_STATE; + break; + case 3: + cmd = CMD_EVENT_SAVE_STATE; + break; + case 4: + cmd = CMD_EVENT_DISK_EJECT_TOGGLE; + break; + case 5: + cmd = CMD_EVENT_DISK_PREV; + break; + case 6: + cmd = CMD_EVENT_DISK_NEXT; + break; + case 7: + cmd = CMD_EVENT_GRAB_MOUSE_TOGGLE; + break; + case 8: + cmd = CMD_EVENT_MENU_TOGGLE; + break; + case 9: + cmd = CMD_EVENT_PAUSE_TOGGLE; + break; + case 20: + cmd = CMD_EVENT_FULLSCREEN_TOGGLE; + break; + default: + cmd = CMD_EVENT_NONE; + break; + } + + if (sender_tag >= 10 && sender_tag <= 19) + { + unsigned idx = (sender_tag - (10-1)); + rarch_ctl(RARCH_CTL_SET_WINDOWED_SCALE, &idx); + cmd = CMD_EVENT_RESIZE_WINDOWED_SCALE; + } + + ui_companion_event_command(cmd); +} + +- (void)alertDidEnd:(NSAlert *)alert returnCode:(int32_t)returnCode contextInfo:(void *)contextInfo +{ + [[NSApplication sharedApplication] stopModal]; +} + +@end + +int main(int argc, char *argv[]) +{ + if (argc == 2) + { + if (argv[1] != '\0') + if (!strncmp(argv[1], "-psn", 4)) + argc = 1; + } + + waiting_argc = argc; + waiting_argv = argv; + + return NSApplicationMain(argc, (const char **) argv); +} + +typedef struct ui_companion_cocoa +{ + void *empty; +} ui_companion_cocoa_t; + +static void ui_companion_cocoa_notify_content_loaded(void *data) +{ + (void)data; +} + +static void ui_companion_cocoa_toggle(void *data, bool force) +{ + (void)data; + (void)force; +} + +static int ui_companion_cocoa_iterate(void *data, unsigned action) +{ + (void)data; + + return 0; +} + +static void ui_companion_cocoa_deinit(void *data) +{ + ui_companion_cocoa_t *handle = (ui_companion_cocoa_t*)data; + + app_terminate(); + + if (handle) + free(handle); +} + +static void *ui_companion_cocoa_init(void) +{ + ui_companion_cocoa_t *handle = (ui_companion_cocoa_t*)calloc(1, sizeof(*handle)); + + if (!handle) + return NULL; + + return handle; +} + +static void ui_companion_cocoa_event_command(void *data, enum event_command cmd) +{ + (void)data; + (void)cmd; +} + +static void ui_companion_cocoa_notify_list_pushed(void *data, + file_list_t *list, file_list_t *menu_list) +{ + (void)data; + (void)list; + (void)menu_list; +} + +static void *ui_companion_cocoa_get_main_window(void *data) +{ + return (BRIDGE void *)((RetroArch_OSX*)[[NSApplication sharedApplication] delegate]).window; +} + +ui_companion_driver_t ui_companion_cocoa = { + ui_companion_cocoa_init, + ui_companion_cocoa_deinit, + ui_companion_cocoa_iterate, + ui_companion_cocoa_toggle, + ui_companion_cocoa_event_command, + ui_companion_cocoa_notify_content_loaded, + ui_companion_cocoa_notify_list_pushed, + NULL, /* notify_refresh */ + NULL, /* msg_queue_push */ + NULL, /* render_messagebox */ + ui_companion_cocoa_get_main_window, + NULL, /* log_msg */ + &ui_browser_window_cocoa, + &ui_msg_window_cocoa, + &ui_window_cocoa, + &ui_application_cocoa, + "cocoa", +}; diff --git a/ui/drivers/ui_cocoatouch.m b/ui/drivers/ui_cocoatouch.m index 4e637feb21..5b1ca47f55 100644 --- a/ui/drivers/ui_cocoatouch.m +++ b/ui/drivers/ui_cocoatouch.m @@ -41,7 +41,7 @@ #endif static char msg_old[PATH_MAX_LENGTH]; -id apple_platform; +static id apple_platform; static CFRunLoopObserverRef iterate_observer; /* forward declaration */ @@ -79,6 +79,7 @@ static void ui_companion_cocoatouch_event_command( void *data, enum event_command cmd) { (void)data; + command_event(cmd, NULL); } static void rarch_draw_observer(CFRunLoopObserverRef observer, @@ -239,7 +240,7 @@ enum // This is for iOS versions < 9.0 - (id)_keyCommandForEvent:(UIEvent*)event { - /* This gets called twice with the same timestamp + /* This gets called twice with the same timestamp * for each keypress, that's fine for polling * but is bad for business with events. */ static double last_time_stamp; @@ -248,7 +249,7 @@ enum return [super _keyCommandForEvent:event]; last_time_stamp = event.timestamp; - /* If the _hidEvent is null, [event _keyCode] will crash. + /* If the _hidEvent is null, [event _keyCode] will crash. * (This happens with the on screen keyboard). */ if (event._hidEvent) { @@ -299,13 +300,13 @@ enum handle_touch_event(event.allTouches.allObjects); get_ios_version(&major, &minor); - + #if __IPHONE_OS_VERSION_MAX_ALLOWED < 70000 if ((major < 7) && [event respondsToSelector:@selector(_gsEvent)]) { /* Keyboard event hack for iOS versions prior to iOS 7. * - * Derived from: + * Derived from: * http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html */ const uint8_t *eventMem = objc_unretainedPointer([event performSelector:@selector(_gsEvent)]); @@ -379,7 +380,7 @@ enum iterate_observer = CFRunLoopObserverCreate(0, kCFRunLoopBeforeWaiting, true, 0, rarch_draw_observer, 0); CFRunLoopAddObserver(CFRunLoopGetMain(), iterate_observer, kCFRunLoopCommonModes); - + #ifdef HAVE_MFI extern bool apple_gamecontroller_joypad_init(void *data); apple_gamecontroller_joypad_init(NULL); @@ -430,7 +431,7 @@ enum { NSString *filename = (NSString*)url.path.lastPathComponent; NSError *error = nil; - + [[NSFileManager defaultManager] moveItemAtPath:[url path] toPath:[self.documentsDirectory stringByAppendingPathComponent:filename] error:&error]; if (error) @@ -497,11 +498,11 @@ enum if (string_is_equal(apple_frontend_settings.orientations, "landscape")) apple_frontend_settings.orientation_flags = UIInterfaceOrientationMaskLandscape; else if (string_is_equal(apple_frontend_settings.orientations, "portrait")) - apple_frontend_settings.orientation_flags = UIInterfaceOrientationMaskPortrait + apple_frontend_settings.orientation_flags = UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskPortraitUpsideDown; } -- (void)mainMenuRefresh +- (void)mainMenuRefresh { [self.mainmenu reloadData]; } @@ -525,7 +526,7 @@ enum self.menu_count--; [self popViewControllerAnimated:YES]; - self.mainmenu = self.mainmenu.last_menu; + self.mainmenu = self.mainmenu.last_menu; } } } @@ -593,7 +594,7 @@ static void ui_companion_cocoatouch_notify_content_loaded(void *data) [ap showGameView]; } -static void ui_companion_cocoatouch_toggle(void *data, bool force) +static void ui_companion_cocoatouch_toggle(void *data) { RetroArch_iOS *ap = (RetroArch_iOS *)apple_platform; @@ -608,7 +609,7 @@ static int ui_companion_cocoatouch_iterate(void *data, unsigned action) RetroArch_iOS *ap = (RetroArch_iOS*)apple_platform; (void)data; - + if (ap) [ap showPauseMenu:ap]; @@ -662,7 +663,7 @@ static void ui_companion_cocoatouch_notify_list_pushed(void *data, printf( "notify_list_pushed: old size should not be larger\n" ); old_size = new_size; - + if (ap) [ap mainMenuPushPop: pushp]; } @@ -686,9 +687,8 @@ static void ui_companion_cocoatouch_render_messagebox(const char *msg) } } -static void ui_companion_cocoatouch_msg_queue_push(void *data, - const char *msg, - unsigned priority, unsigned duration, bool flush) +static void ui_companion_cocoatouch_msg_queue_push(const char *msg, + unsigned priority, unsigned duration, bool flush) { RetroArch_iOS *ap = (RetroArch_iOS *)apple_platform; @@ -709,8 +709,8 @@ ui_companion_driver_t ui_companion_cocoatouch = { ui_companion_cocoatouch_notify_refresh, ui_companion_cocoatouch_msg_queue_push, ui_companion_cocoatouch_render_messagebox, - NULL, /* get_main_window */ - NULL, /* log_msg */ + NULL, + NULL, &ui_browser_window_null, &ui_msg_window_null, &ui_window_null, diff --git a/ui/drivers/ui_cocoatouch_metal.m b/ui/drivers/ui_cocoatouch_metal.m new file mode 100644 index 0000000000..b1c21a624a --- /dev/null +++ b/ui/drivers/ui_cocoatouch_metal.m @@ -0,0 +1,719 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2016 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "cocoa/cocoa_common_metal.h" +#include "../ui_companion_driver.h" +#include "../../configuration.h" +#include "../../frontend/frontend.h" +#include "../../input/drivers/cocoa_input.h" +#include "../../input/drivers_keyboard/keyboard_event_apple.h" +#include "../../retroarch.h" +#ifdef HAVE_AVFOUNDATION +#import +#endif + +#ifdef HAVE_MENU +#include "../../menu/menu_setting.h" +#endif + +static char msg_old[PATH_MAX_LENGTH]; +id apple_platform; +static CFRunLoopObserverRef iterate_observer; + +/* forward declaration */ +static void apple_rarch_exited(void); + +static void rarch_enable_ui(void) +{ + bool boolean = true; +#ifdef HAVE_AVFOUNDATION + [[RetroArch_iOS get] supportOtherAudioSessions]; +#endif + + ui_companion_set_foreground(true); + + rarch_ctl(RARCH_CTL_SET_PAUSED, &boolean); + rarch_ctl(RARCH_CTL_SET_IDLE, &boolean); + rarch_menu_running(); +} + +static void rarch_disable_ui(void) +{ + bool boolean = false; + + ui_companion_set_foreground(false); + + rarch_ctl(RARCH_CTL_SET_PAUSED, &boolean); + rarch_ctl(RARCH_CTL_SET_IDLE, &boolean); + rarch_menu_running_finished(); +#ifdef HAVE_AVFOUNDATION + [[RetroArch_iOS get] supportOtherAudioSessions]; +#endif +} + +static void ui_companion_cocoatouch_event_command( + void *data, enum event_command cmd) +{ + (void)data; +} + +static void rarch_draw_observer(CFRunLoopObserverRef observer, + CFRunLoopActivity activity, void *info) +{ + unsigned sleep_ms = 0; + int ret = runloop_iterate(&sleep_ms); + + if (ret == 1 && !ui_companion_is_on_foreground() && sleep_ms > 0) + retro_sleep(sleep_ms); + task_queue_check(); + + if (ret == -1) + { + ui_companion_cocoatouch_event_command(NULL, CMD_EVENT_MENU_SAVE_CURRENT_CONFIG); + main_exit(NULL); + return; + } + + if (rarch_ctl(RARCH_CTL_IS_IDLE, NULL)) + return; + CFRunLoopWakeUp(CFRunLoopGetMain()); +} + +apple_frontend_settings_t apple_frontend_settings; + +void get_ios_version(int *major, int *minor) +{ + NSArray *decomposed_os_version = [[UIDevice currentDevice].systemVersion componentsSeparatedByString:@"."]; + + if (major && decomposed_os_version.count > 0) + *major = (int)[decomposed_os_version[0] integerValue]; + if (minor && decomposed_os_version.count > 1) + *minor = (int)[decomposed_os_version[1] integerValue]; +} + +extern float cocoagl_gfx_ctx_get_native_scale(void); + +/* Input helpers: This is kept here because it needs ObjC */ +static void handle_touch_event(NSArray* touches) +{ + unsigned i; + cocoa_input_data_t *apple = (cocoa_input_data_t*)input_driver_get_data(); + float scale = cocoagl_gfx_ctx_get_native_scale(); + + if (!apple) + return; + + apple->touch_count = 0; + + for (i = 0; i < touches.count && (apple->touch_count < MAX_TOUCHES); i++) + { + CGPoint coord; + UITouch *touch = [touches objectAtIndex:i]; + + if (touch.view != [CocoaView get].view) + continue; + + coord = [touch locationInView:[touch view]]; + + if (touch.phase != UITouchPhaseEnded && touch.phase != UITouchPhaseCancelled) + { + apple->touches[apple->touch_count ].screen_x = coord.x * scale; + apple->touches[apple->touch_count ++].screen_y = coord.y * scale; + } + } +} + +#ifndef HAVE_APPLE_STORE +// iO7 Keyboard support +@interface UIEvent(iOS7Keyboard) +@property(readonly, nonatomic) long long _keyCode; +@property(readonly, nonatomic) _Bool _isKeyDown; +@property(retain, nonatomic) NSString *_privateInput; +@property(nonatomic) long long _modifierFlags; +- (struct __IOHIDEvent { }*)_hidEvent; +@end + +@interface UIApplication(iOS7Keyboard) +- (void)handleKeyUIEvent:(UIEvent*)event; +- (id)_keyCommandForEvent:(UIEvent*)event; +@end +#endif + +@interface RApplication : UIApplication +@end + +@implementation RApplication + +#ifndef HAVE_APPLE_STORE +/* Keyboard handler for iOS 7. */ + +/* This is copied here as it isn't + * defined in any standard iOS header */ +enum +{ + NSAlphaShiftKeyMask = 1 << 16, + NSShiftKeyMask = 1 << 17, + NSControlKeyMask = 1 << 18, + NSAlternateKeyMask = 1 << 19, + NSCommandKeyMask = 1 << 20, + NSNumericPadKeyMask = 1 << 21, + NSHelpKeyMask = 1 << 22, + NSFunctionKeyMask = 1 << 23, + NSDeviceIndependentModifierFlagsMask = 0xffff0000U +}; + +// This is specifically for iOS 9, according to the private headers +-(void)handleKeyUIEvent:(UIEvent *)event { + /* This gets called twice with the same timestamp + * for each keypress, that's fine for polling + * but is bad for business with events. */ + static double last_time_stamp; + + if (last_time_stamp == event.timestamp) + return [super handleKeyUIEvent:event]; + + last_time_stamp = event.timestamp; + + /* If the _hidEvent is null, [event _keyCode] will crash. + * (This happens with the on screen keyboard). */ + if (event._hidEvent) + { + NSString *ch = (NSString*)event._privateInput; + uint32_t character = 0; + uint32_t mod = 0; + + mod |= (event._modifierFlags & NSAlphaShiftKeyMask) ? RETROKMOD_CAPSLOCK : 0; + mod |= (event._modifierFlags & NSShiftKeyMask ) ? RETROKMOD_SHIFT : 0; + mod |= (event._modifierFlags & NSControlKeyMask ) ? RETROKMOD_CTRL : 0; + mod |= (event._modifierFlags & NSAlternateKeyMask ) ? RETROKMOD_ALT : 0; + mod |= (event._modifierFlags & NSCommandKeyMask ) ? RETROKMOD_META : 0; + mod |= (event._modifierFlags & NSNumericPadKeyMask) ? RETROKMOD_NUMLOCK : 0; + + if (ch && ch.length != 0) + { + unsigned i; + character = [ch characterAtIndex:0]; + + apple_input_keyboard_event(event._isKeyDown, + (uint32_t)event._keyCode, 0, mod, + RETRO_DEVICE_KEYBOARD); + + for (i = 1; i < ch.length; i++) + apple_input_keyboard_event(event._isKeyDown, + 0, [ch characterAtIndex:i], mod, + RETRO_DEVICE_KEYBOARD); + } + + apple_input_keyboard_event(event._isKeyDown, + (uint32_t)event._keyCode, character, mod, + RETRO_DEVICE_KEYBOARD); + } + + [super handleKeyUIEvent:event]; +} + +// This is for iOS versions < 9.0 +- (id)_keyCommandForEvent:(UIEvent*)event +{ + /* This gets called twice with the same timestamp + * for each keypress, that's fine for polling + * but is bad for business with events. */ + static double last_time_stamp; + + if (last_time_stamp == event.timestamp) + return [super _keyCommandForEvent:event]; + last_time_stamp = event.timestamp; + + /* If the _hidEvent is null, [event _keyCode] will crash. + * (This happens with the on screen keyboard). */ + if (event._hidEvent) + { + NSString *ch = (NSString*)event._privateInput; + uint32_t character = 0; + uint32_t mod = 0; + + mod |= (event._modifierFlags & NSAlphaShiftKeyMask) ? RETROKMOD_CAPSLOCK : 0; + mod |= (event._modifierFlags & NSShiftKeyMask ) ? RETROKMOD_SHIFT : 0; + mod |= (event._modifierFlags & NSControlKeyMask ) ? RETROKMOD_CTRL : 0; + mod |= (event._modifierFlags & NSAlternateKeyMask ) ? RETROKMOD_ALT : 0; + mod |= (event._modifierFlags & NSCommandKeyMask ) ? RETROKMOD_META : 0; + mod |= (event._modifierFlags & NSNumericPadKeyMask) ? RETROKMOD_NUMLOCK : 0; + + if (ch && ch.length != 0) + { + unsigned i; + character = [ch characterAtIndex:0]; + + apple_input_keyboard_event(event._isKeyDown, + (uint32_t)event._keyCode, 0, mod, + RETRO_DEVICE_KEYBOARD); + + for (i = 1; i < ch.length; i++) + apple_input_keyboard_event(event._isKeyDown, + 0, [ch characterAtIndex:i], mod, + RETRO_DEVICE_KEYBOARD); + } + + apple_input_keyboard_event(event._isKeyDown, + (uint32_t)event._keyCode, character, mod, + RETRO_DEVICE_KEYBOARD); + } + + return [super _keyCommandForEvent:event]; +} +#endif + +#define GSEVENT_TYPE_KEYDOWN 10 +#define GSEVENT_TYPE_KEYUP 11 + +- (void)sendEvent:(UIEvent *)event +{ + int major, minor; + [super sendEvent:event]; + + if (event.allTouches.count) + handle_touch_event(event.allTouches.allObjects); + + get_ios_version(&major, &minor); + +#if __IPHONE_OS_VERSION_MAX_ALLOWED < 70000 + if ((major < 7) && [event respondsToSelector:@selector(_gsEvent)]) + { + /* Keyboard event hack for iOS versions prior to iOS 7. + * + * Derived from: + * http://nacho4d-nacho4d.blogspot.com/2012/01/catching-keyboard-events-in-ios.html + */ + const uint8_t *eventMem = objc_unretainedPointer([event performSelector:@selector(_gsEvent)]); + int eventType = eventMem ? *(int*)&eventMem[8] : 0; + + switch (eventType) + { + case GSEVENT_TYPE_KEYDOWN: + case GSEVENT_TYPE_KEYUP: + apple_input_keyboard_event(eventType == GSEVENT_TYPE_KEYDOWN, + *(uint16_t*)&eventMem[0x3C], 0, 0, RETRO_DEVICE_KEYBOARD); + break; + } + } +#endif +} + +@end + +@implementation RetroArch_iOS + ++ (RetroArch_iOS*)get +{ +#ifdef HAVE_AVFOUNDATION + /* Implicitly initializes your audio session. */ + [(RetroArch_iOS*)[[UIApplication sharedApplication] delegate] supportOtherAudioSessions]; +#endif + return (RetroArch_iOS*)[[UIApplication sharedApplication] delegate]; +} + +-(NSString*)documentsDirectory { + if ( _documentsDirectory == nil ) { + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + _documentsDirectory = paths.firstObject; + } + return _documentsDirectory; +} + +- (void)applicationDidFinishLaunching:(UIApplication *)application +{ + char arguments[] = "retroarch"; + char *argv[] = {arguments, NULL}; + int argc = 1; + apple_platform = self; + + [self setDelegate:self]; + +#ifdef HAVE_AVFOUNDATION + /* Other background audio check */ + [self supportOtherAudioSessions]; +#endif + + /* Setup window */ + self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; + [self.window makeKeyAndVisible]; + + self.mainmenu = [RAMainMenu new]; + self.mainmenu.last_menu = self.mainmenu; + [self pushViewController:self.mainmenu animated:NO]; + + [self refreshSystemConfig]; + [self showGameView]; + +#ifdef HAVE_AVFOUNDATION + [self supportOtherAudioSessions]; +#endif + + if (rarch_main(argc, argv, NULL)) + apple_rarch_exited(); + + iterate_observer = CFRunLoopObserverCreate(0, kCFRunLoopBeforeWaiting, + true, 0, rarch_draw_observer, 0); + CFRunLoopAddObserver(CFRunLoopGetMain(), iterate_observer, kCFRunLoopCommonModes); + +#ifdef HAVE_MFI + extern bool apple_gamecontroller_joypad_init(void *data); + apple_gamecontroller_joypad_init(NULL); +#endif + +} + +- (void)applicationDidEnterBackground:(UIApplication *)application +{ +#ifdef HAVE_AVFOUNDATION + [self supportOtherAudioSessions]; +#endif +} + +- (void)applicationWillTerminate:(UIApplication *)application +{ + CFRunLoopObserverInvalidate(iterate_observer); + CFRelease(iterate_observer); + iterate_observer = NULL; +} + +- (void)applicationDidBecomeActive:(UIApplication *)application +{ + settings_t *settings = config_get_ptr(); + +#ifdef HAVE_AVFOUNDATION + [self supportOtherAudioSessions]; +#endif + if (settings->bools.ui_companion_start_on_boot) + return; + + [self showGameView]; +} + +- (void)applicationWillResignActive:(UIApplication *)application +{ +#ifdef HAVE_AVFOUNDATION + [self supportOtherAudioSessions]; +#endif + dispatch_async(dispatch_get_main_queue(), + ^{ + ui_companion_cocoatouch_event_command(NULL, CMD_EVENT_MENU_SAVE_CURRENT_CONFIG); + }); + [self showPauseMenu: self]; +} + +-(BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation +{ + NSString *filename = (NSString*)url.path.lastPathComponent; + NSError *error = nil; + + [[NSFileManager defaultManager] moveItemAtPath:[url path] toPath:[self.documentsDirectory stringByAppendingPathComponent:filename] error:&error]; + + if (error) + printf("%s\n", [[error description] UTF8String]); + + return true; +} + +- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated +{ + [self setToolbarHidden:![[viewController toolbarItems] count] animated:YES]; + [self refreshSystemConfig]; +} + +- (void)showGameView +{ +#ifdef HAVE_AVFOUNDATION + /* implicitly initializes your audio session */ + [self supportOtherAudioSessions]; +#endif + [self popToRootViewControllerAnimated:NO]; + [self setToolbarHidden:true animated:NO]; + [[UIApplication sharedApplication] setStatusBarHidden:true withAnimation:UIStatusBarAnimationNone]; + [[UIApplication sharedApplication] setIdleTimerDisabled:true]; + [self.window setRootViewController:[CocoaView get]]; + + ui_companion_cocoatouch_event_command(NULL, CMD_EVENT_AUDIO_START); + rarch_disable_ui(); +} + +- (IBAction)showPauseMenu:(id)sender +{ +#ifndef HAVE_AVFOUNDATION + ui_companion_cocoatouch_event_command(NULL, CMD_EVENT_AUDIO_STOP); +#endif + rarch_enable_ui(); + + [[UIApplication sharedApplication] setStatusBarHidden:false withAnimation:UIStatusBarAnimationNone]; + [[UIApplication sharedApplication] setIdleTimerDisabled:false]; + [self.window setRootViewController:self]; +} + + +- (void)toggleUI +{ + if (ui_companion_is_on_foreground()) + { + [self showGameView]; + } + else + { + [self showPauseMenu:self]; + } +#ifdef HAVE_AVFOUNDATION + [self supportOtherAudioSessions]; +#endif +} + +- (void)refreshSystemConfig +{ + /* Get enabled orientations */ + apple_frontend_settings.orientation_flags = UIInterfaceOrientationMaskAll; + + if (string_is_equal(apple_frontend_settings.orientations, "landscape")) + apple_frontend_settings.orientation_flags = UIInterfaceOrientationMaskLandscape; + else if (string_is_equal(apple_frontend_settings.orientations, "portrait")) + apple_frontend_settings.orientation_flags = UIInterfaceOrientationMaskPortrait + | UIInterfaceOrientationMaskPortraitUpsideDown; +} + +- (void)mainMenuRefresh +{ + [self.mainmenu reloadData]; +} + +- (void)mainMenuPushPop: (bool)pushp +{ + if ( pushp ) + { + self.menu_count++; + RAMenuBase* next_menu = [RAMainMenu new]; + next_menu.last_menu = self.mainmenu; + self.mainmenu = next_menu; + [self pushViewController:self.mainmenu animated:YES]; + } + else + { + if ( self.menu_count == 0 ) + [self.mainmenu reloadData]; + else + { + self.menu_count--; + + [self popViewControllerAnimated:YES]; + self.mainmenu = self.mainmenu.last_menu; + } + } +} + +- (void)supportOtherAudioSessions +{ +#ifdef HAVE_AVFOUNDATION + /* implicitly initializes your audio session */ + AVAudioSession *audioSession = [AVAudioSession sharedInstance]; + [audioSession setCategory: AVAudioSessionCategoryAmbient error: nil]; + [audioSession setActive:YES error:nil]; +#endif +} + +- (void)mainMenuRenderMessageBox:(NSString *)msg +{ + [self.mainmenu renderMessageBox:msg]; +} + +@end + +int main(int argc, char *argv[]) +{ + @autoreleasepool { + return UIApplicationMain(argc, argv, NSStringFromClass([RApplication class]), NSStringFromClass([RetroArch_iOS class])); + } +} + +#if 0 +static void apple_display_alert(const char *message, const char *title) +{ + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:BOXSTRING(title) + message:BOXSTRING(message) + delegate:nil + cancelButtonTitle:BOXSTRING("OK") + otherButtonTitles:nil]; + [alert show]; +} +#endif + +static void apple_rarch_exited(void) +{ + RetroArch_iOS *ap = (RetroArch_iOS *)apple_platform; + + if (!ap) + return; +#ifdef HAVE_AVFOUNDATION + [ap supportOtherAudioSessions]; +#endif + [ap showPauseMenu:ap]; +} + +typedef struct ui_companion_cocoatouch +{ + void *empty; +} ui_companion_cocoatouch_t; + +static void ui_companion_cocoatouch_notify_content_loaded(void *data) +{ + RetroArch_iOS *ap = (RetroArch_iOS *)apple_platform; + + (void)data; + + if (ap) + [ap showGameView]; +} + +static void ui_companion_cocoatouch_toggle(void *data, bool force) +{ + RetroArch_iOS *ap = (RetroArch_iOS *)apple_platform; + + (void)data; + + if (ap) + [ap toggleUI]; +} + +static int ui_companion_cocoatouch_iterate(void *data, unsigned action) +{ + RetroArch_iOS *ap = (RetroArch_iOS*)apple_platform; + + (void)data; + + if (ap) + [ap showPauseMenu:ap]; + + return 0; +} + +static void ui_companion_cocoatouch_deinit(void *data) +{ + ui_companion_cocoatouch_t *handle = (ui_companion_cocoatouch_t*)data; + + apple_rarch_exited(); + + if (handle) + free(handle); +} + +static void *ui_companion_cocoatouch_init(void) +{ + ui_companion_cocoatouch_t *handle = (ui_companion_cocoatouch_t*) + calloc(1, sizeof(*handle)); + + if (!handle) + return NULL; + + rarch_enable_ui(); + + return handle; +} + +static size_t old_size = 0; + +static void ui_companion_cocoatouch_notify_list_pushed(void *data, + file_list_t *list, file_list_t *menu_list) +{ + RetroArch_iOS *ap = (RetroArch_iOS *)apple_platform; + bool pushp = false; + size_t new_size = file_list_get_size( menu_list ); + + /* FIXME workaround for the double call */ + if ( old_size == 0 ) + { + old_size = new_size; + return; + } + + if ( old_size == new_size ) + pushp = false; + else if ( old_size < new_size ) + pushp = true; + else if ( old_size > new_size ) + printf( "notify_list_pushed: old size should not be larger\n" ); + + old_size = new_size; + + if (ap) + [ap mainMenuPushPop: pushp]; +} + +static void ui_companion_cocoatouch_notify_refresh(void *data) +{ + RetroArch_iOS *ap = (RetroArch_iOS *)apple_platform; + + if (ap) + [ap mainMenuRefresh]; +} + +static void ui_companion_cocoatouch_render_messagebox(const char *msg) +{ + RetroArch_iOS *ap = (RetroArch_iOS *)apple_platform; + + if (ap && !string_is_equal(msg, msg_old)) + { + [ap mainMenuRenderMessageBox: [NSString stringWithUTF8String:msg]]; + strlcpy(msg_old, msg, sizeof(msg_old)); + } +} + +static void ui_companion_cocoatouch_msg_queue_push(void *data, + const char *msg, + unsigned priority, unsigned duration, bool flush) +{ + RetroArch_iOS *ap = (RetroArch_iOS *)apple_platform; + + if (ap && msg) + { + [ap.mainmenu msgQueuePush: [NSString stringWithUTF8String:msg]]; + } +} + +ui_companion_driver_t ui_companion_cocoatouch = { + ui_companion_cocoatouch_init, + ui_companion_cocoatouch_deinit, + ui_companion_cocoatouch_iterate, + ui_companion_cocoatouch_toggle, + ui_companion_cocoatouch_event_command, + ui_companion_cocoatouch_notify_content_loaded, + ui_companion_cocoatouch_notify_list_pushed, + ui_companion_cocoatouch_notify_refresh, + ui_companion_cocoatouch_msg_queue_push, + ui_companion_cocoatouch_render_messagebox, + NULL, /* get_main_window */ + NULL, /* log_msg */ + &ui_browser_window_null, + &ui_msg_window_null, + &ui_window_null, + &ui_application_null, + "cocoatouch", +}; From 04c046e8317c78713512d4671d5ad3d94d3d8325 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Fri, 31 Aug 2018 16:14:26 -0700 Subject: [PATCH 02/10] Update (cherry picked from commit 64cc28a48784e4bfb8e468cd03fa6f7fd058db80) --- ui/drivers/ui_cocoa.m | 8 ++++---- ui/drivers/ui_cocoatouch.m | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index d790dda58e..9d710f08b7 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -580,11 +580,11 @@ ui_companion_driver_t ui_companion_cocoa = { ui_companion_cocoa_event_command, ui_companion_cocoa_notify_content_loaded, ui_companion_cocoa_notify_list_pushed, - NULL, - NULL, - NULL, + NULL, /* notify_refresh */ + NULL, /* msg_queue_push */ + NULL, /* render_messagebox */ ui_companion_cocoa_get_main_window, - NULL, + NULL, /* log_msg */ &ui_browser_window_cocoa, &ui_msg_window_cocoa, &ui_window_cocoa, diff --git a/ui/drivers/ui_cocoatouch.m b/ui/drivers/ui_cocoatouch.m index 5b1ca47f55..04fb6d4065 100644 --- a/ui/drivers/ui_cocoatouch.m +++ b/ui/drivers/ui_cocoatouch.m @@ -709,8 +709,8 @@ ui_companion_driver_t ui_companion_cocoatouch = { ui_companion_cocoatouch_notify_refresh, ui_companion_cocoatouch_msg_queue_push, ui_companion_cocoatouch_render_messagebox, - NULL, - NULL, + NULL, /* get_main_window */ + NULL, /* log_msg */ &ui_browser_window_null, &ui_msg_window_null, &ui_window_null, From 7880e11ca0a0215922b3128fbe54aec88db5662b Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 30 Sep 2018 18:43:53 -0700 Subject: [PATCH 03/10] Warning fix (cherry picked from commit fa1096a6049cbb428e1de72aa46a31c28bafce76) --- ui/drivers/ui_cocoa.m | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index 9d710f08b7..2a7324e9f0 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -36,6 +36,7 @@ #include "../../core.h" #include "../../retroarch.h" #include "../../tasks/tasks_internal.h" +#include ".././verbosity.h" id apple_platform; From 0db432ca687195da3159531b1e29a102307fc83e Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 14 Oct 2018 18:38:15 -0700 Subject: [PATCH 04/10] Add HAVE_QT ifdefs (cherry picked from commit 9f74b05b13eb9875d9d7df55e533f45ed79a831d) --- ui/drivers/ui_cocoa.m | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index 2a7324e9f0..6258f34eba 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -235,16 +235,29 @@ static char** waiting_argv; { int ret; unsigned sleep_ms = 0; +#ifdef HAVE_QT + const ui_application_t *application = ui_application_qt.process_events(); +#else const ui_application_t *application = ui_companion_driver_get_application_ptr(); +#endif if (application) application->process_events(); + ret = runloop_iterate(&sleep_ms); + if (ret == 1 && sleep_ms > 0) retro_sleep(sleep_ms); + task_queue_check(); + while(CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.002, FALSE) == kCFRunLoopRunHandledSource); if (ret == -1) + { +#ifdef HAVE_QT + ui_application_qt.quit(); +#endif break; + } }while(1); main_exit(NULL); From 9a73bae8685ddd8c80f1b57af8265b01a03c1b34 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Sun, 14 Oct 2018 18:38:43 -0700 Subject: [PATCH 05/10] Buildfix (cherry picked from commit 7717631909cf5195b747603165d9e5824de3f7ad) --- ui/drivers/ui_cocoa.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index 6258f34eba..2a99d15528 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -236,7 +236,7 @@ static char** waiting_argv; int ret; unsigned sleep_ms = 0; #ifdef HAVE_QT - const ui_application_t *application = ui_application_qt.process_events(); + const ui_application_t *application = &ui_application_qt; #else const ui_application_t *application = ui_companion_driver_get_application_ptr(); #endif From 512a6813453f8785778284036f250f2201b7ebc0 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Tue, 30 Oct 2018 09:11:07 -0700 Subject: [PATCH 06/10] Use runloop_get_libretro_system_info in more places - clean some code up (cherry picked from commit a662b62d192787543f504f4535da523991c906ba) --- ui/drivers/ui_cocoa.m | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index 2a99d15528..2a4561a584 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -293,13 +293,9 @@ static char** waiting_argv; { if (filenames.count == 1 && [filenames objectAtIndex:0]) { - rarch_system_info_t *info = runloop_get_system_info(); - struct retro_system_info *system = &info->info; + struct retro_system_info *system = runloop_get_libretro_system_info(); NSString *__core = [filenames objectAtIndex:0]; - const char *core_name = NULL; - - if (system) - core_name = system->library_name; + const char *core_name = system ? system->library_name : NULL; if (core_name) { @@ -369,12 +365,8 @@ static void open_document_handler(ui_browser_window_state_t *state, bool result) if (!result) return; - rarch_system_info_t *info = runloop_get_system_info(); - struct retro_system_info *system = &info->info; - const char *core_name = NULL; - - if (system) - core_name = system->library_name; + struct retro_system_info *system = runloop_get_libretro_system_info(); + const char *core_name = system ? system->library_name : NULL; path_set(RARCH_PATH_CONTENT, state->result); From 69aae94e5f3a7333ec19bd145487b0865e10a5d2 Mon Sep 17 00:00:00 2001 From: twinaphex Date: Tue, 30 Oct 2018 11:32:52 -0700 Subject: [PATCH 07/10] (Cocoa) Dehardcode some strings (cherry picked from commit 7c93a0934e897a98a3053495cc313605094c2ddf) --- ui/drivers/ui_cocoa.m | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/drivers/ui_cocoa.m b/ui/drivers/ui_cocoa.m index 2a4561a584..b93d748cf3 100644 --- a/ui/drivers/ui_cocoa.m +++ b/ui/drivers/ui_cocoa.m @@ -318,7 +318,7 @@ static char** waiting_argv; { ui_msg_window_state msg_window_state; msg_window_state.text = strdup("Cannot open multiple files"); - msg_window_state.title = strdup("RetroArch"); + msg_window_state.title = strdup(msg_hash_to_str(MSG_PROGRAM)); msg_window->information(&msg_window_state); free(msg_window_state.text); @@ -390,8 +390,8 @@ static void open_document_handler(ui_browser_window_state_t *state, bool result) settings_t *settings = config_get_ptr(); browser_state.filters = strdup("dylib"); - browser_state.filters_title = strdup("Core"); - browser_state.title = strdup("Load Core"); + browser_state.filters_title = strdup(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_SETTINGS)); + browser_state.title = strdup(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_CORE_LIST)); browser_state.startdir = strdup(settings->paths.directory_libretro); bool result = browser->open(&browser_state); @@ -417,7 +417,7 @@ static void open_document_handler(ui_browser_window_state_t *state, bool result) if (!startdir.length) startdir = BOXSTRING("/"); - browser_state.title = strdup("Load Content"); + browser_state.title = strdup(msg_hash_to_str(MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST)); browser_state.startdir = strdup([startdir UTF8String]); bool result = browser->open(&browser_state); From 43e8702e125b53534edf54084bd7ecf3ce3e9dc9 Mon Sep 17 00:00:00 2001 From: Stuart Carnie Date: Sun, 4 Nov 2018 10:49:56 -0700 Subject: [PATCH 08/10] fix(cocoa): Copy xib for PPC compat; upgrade GL-legacy xib to 10.6 --- pkg/apple/OSX/en.lproj/MainMenu.xib | 2149 ++++------------------- pkg/apple/OSX/en.lproj/MainMenu_PPC.xib | 1809 +++++++++++++++++++ ui/ui_companion_driver.c | 2 +- 3 files changed, 2151 insertions(+), 1809 deletions(-) create mode 100644 pkg/apple/OSX/en.lproj/MainMenu_PPC.xib diff --git a/pkg/apple/OSX/en.lproj/MainMenu.xib b/pkg/apple/OSX/en.lproj/MainMenu.xib index b9d83c4861..111ef503b3 100644 --- a/pkg/apple/OSX/en.lproj/MainMenu.xib +++ b/pkg/apple/OSX/en.lproj/MainMenu.xib @@ -1,1809 +1,342 @@ - - - 1050 - 12F45 - 3084 - 1187.40 - 626.00 - - com.apple.InterfaceBuilder.CocoaPlugin - 3084 - - - YES - NSCustomObject - NSMenu - NSMenuItem - NSView - NSWindowTemplate - - - YES - com.apple.InterfaceBuilder.CocoaPlugin - - - PluginDependencyRecalculationVersion - - - - YES - - NSApplication - - - FirstResponder - - - NSApplication - - - AMainMenu - - YES - - - RetroArch - - 1048576 - 2147483647 - - NSImage - NSMenuCheckmark - - - NSImage - NSMenuMixedState - - submenuAction: - - - RetroArch - - YES - - - About RetroArch - - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Services - - 1048576 - 2147483647 - - - submenuAction: - - - Services - - YES - - _NSServicesMenu - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Hide RetroArch - h - 1048576 - 2147483647 - - - - - - Hide Others - h - 1572864 - 2147483647 - - - - - - Show All - - 1048576 - 2147483647 - - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Quit RetroArch - q - 1048576 - 2147483647 - - - - - _NSAppleMenu - - - - - File - - 1048576 - 2147483647 - - - submenuAction: - - - File - - YES - - - Load Core... - - 2147483647 - - - - - - Load Content... - o - 1048576 - 2147483647 - - - - - - Open Recent - - 1048576 - 2147483647 - - - submenuAction: - - - Open Recent - - YES - - - Clear Menu - - 1048576 - 2147483647 - - - - - _NSRecentDocumentsMenu - - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Close - w - 1048576 - 2147483647 - - - - - - - - - Command - - 2147483647 - - - submenuAction: - - - Command - - YES - - - Audio Options - - 2147483647 - - - submenuAction: - - Audio Options - - YES - - - Mute Toggle - - 2147483647 - - - 11 - - - - - - - Disk Options - - 1048576 - 2147483647 - - - submenuAction: - - Disk Options - - YES - - - Cycle Tray - - 2147483647 - - - 4 - - - - Next Disk - - 2147483647 - - - 6 - - - - Previous Disk - - 2147483647 - - - 5 - - - - - - - Mouse Options - - 1048576 - 2147483647 - - - submenuAction: - - Mouse Options - - YES - - - Mouse Grab Toggle - - 2147483647 - - - 7 - - - - - - - Save State Options - - 1048576 - 2147483647 - - - submenuAction: - - Save State Options - - YES - - - Load State - - 2147483647 - - - 2 - - - - Save State - - 2147483647 - - - 3 - - - - - - - Reset - - 2147483647 - - - 1 - - - - Menu Toggle - - 2147483647 - - - 8 - - - - Pause Toggle - - 2147483647 - - - 9 - - - - Take Screenshot - - 2147483647 - - - 10 - - - - - - - Paths - - 2147483647 - - - submenuAction: - - - Paths - - YES - - - Core Directory - - 2147483647 - - - - - - - - - Window - - 1048576 - 2147483647 - - - submenuAction: - - - Window - - YES - - - Minimize - m - 1048576 - 2147483647 - - - - - - Zoom - - 1048576 - 2147483647 - - - - - - Windowed Scale - - 1048576 - 2147483647 - - - submenuAction: - - - - YES - - - 1x - - 2147483647 - - - 10 - - - - 2x - - 2147483647 - - - 11 - - - - 3x - - 2147483647 - - - 12 - - - - 4x - - 2147483647 - - - 13 - - - - 5x - - 2147483647 - - - 14 - - - - 6x - - 2147483647 - - - 15 - - - - 7x - - 2147483647 - - - 16 - - - - 8x - - 2147483647 - - - 17 - - - - 9x - - 2147483647 - - - 18 - - - - 10x - - 2147483647 - - - 19 - - - - - - - Enter Full Screen - f - 1310720 - 2147483647 - - - - - - Toggle Exclusive Full Screen - - 2147483647 - - - 20 - - - - YES - YES - - - 1048576 - 2147483647 - - - - - - Bring All to Front - - 1048576 - 2147483647 - - - - - _NSWindowsMenu - - - - - Help - - 2147483647 - - - submenuAction: - - - Help - - YES - - - RetroArch Help - ? - 1048576 - 2147483647 - - - - - _NSHelpMenu - - - - _NSMainMenu - - - 15 - 2 - {{335, 390}, {480, 360}} - 1954021376 - RetroArch_OSX - NSWindow - - - - - 256 - {480, 360} - - - - {{0, 0}, {2560, 1418}} - {10000000000000, 10000000000000} - YES - - - RetroArch_OSX - - - - - YES - - - terminate: - - - - 449 - - - - orderFrontStandardAboutPanel: - - - - 142 - - - - delegate - - - - 495 - - - - performMiniaturize: - - - - 37 - - - - arrangeInFront: - - - - 39 - - - - clearRecentDocuments: - - - - 127 - - - - performClose: - - - - 193 - - - - performZoom: - - - - 240 - - - - hide: - - - - 367 - - - - hideOtherApplications: - - - - 368 - - - - unhideAllApplications: - - - - 370 - - - - showHelp: - - - - 493 - - - - toggleFullScreen: - - - - 593 - - - - openDocument: - - - - 657 - - - - basicEvent: - - - - 550 - - - - basicEvent: - - - - 552 - - - - showCoresDirectory: - - - - 588 - - - - window - - - - 591 - - - - basicEvent: - - - - 615 - - - - basicEvent: - - - - 617 - - - - basicEvent: - - - - 619 - - - - basicEvent: - - - - 621 - - - - basicEvent: - - - - 623 - - - - basicEvent: - - - - 625 - - - - basicEvent: - - - - 627 - - - - basicEvent: - - - - 634 - - - - basicEvent: - - - - 636 - - - - basicEvent: - - - - 638 - - - - basicEvent: - - - - 640 - - - - basicEvent: - - - - 642 - - - - basicEvent: - - - - 644 - - - - basicEvent: - - - - 646 - - - - basicEvent: - - - - 648 - - - - basicEvent: - - - - 650 - - - - basicEvent: - - - - 652 - - - - basicEvent: - - - - 655 - - - - basicEvent: - - - - 659 - - - - basicEvent: - - - - 664 - - - - openCore: - - - - 665 - - - - - YES - - 0 - - YES - - - - - - -2 - - - File's Owner - - - -1 - - - First Responder - - - -3 - - - Application - - - 29 - - - YES - - - - - - - - - - - 19 - - - YES - - - - - - 56 - - - YES - - - - - - 83 - - - YES - - - - - - 81 - - - YES - - - - - - - - - - 72 - - - - - 124 - - - YES - - - - - - 73 - - - - - 79 - - - - - 125 - - - YES - - - - - - 126 - - - - - 57 - - - YES - - - - - - - - - - - - - - 58 - - - - - 134 - - - - - 150 - - - - - 136 - - - - - 144 - - - - - 236 - - - - - 131 - - - YES - - - - - - 149 - - - - - 145 - - - - - 130 - - - - - 371 - - - YES - - - - - - 372 - - - - - 490 - - - YES - - - - - - 491 - - - YES - - - - - - 492 - - - - - 494 - - - - - 545 - - - YES - - - - - - 546 - - - YES - - - - - - - - - - - - - 585 - - - YES - - - - - - 586 - - - YES - - - - - - 587 - - - - - 597 - - - YES - - - - - - 598 - - - YES - - - - - - - - 602 - - - YES - - - - - - 603 - - - YES - - - - - - 24 - - - YES - - - - - - - - - - - - 592 - - - - - 23 - - - - - 239 - - - - - 5 - - - - - 92 - - - - - 612 - - - YES - - - - - - 613 - - - YES - - - - - - - 549 - - - - - 551 - - - - - 614 - - - - - 616 - - - - - 618 - - - - - 620 - - - - - 629 - - - YES - - - - - - 630 - - - YES - - - - - - - - - - - - - - - 633 - - - - - 635 - - - - - 637 - - - - - 639 - - - - - 641 - - - - - 643 - - - - - 645 - - - - - 647 - - - - - 649 - - - - - 651 - - - - - 654 - - - - - 622 - - - - - 624 - - - - - 626 - - - - - 656 - - - - - 658 - - - - - 660 - - - YES - - - - - - 661 - - - YES - - - - - - 663 - - - - - - - YES - - YES - -1.IBPluginDependency - -2.IBPluginDependency - -3.IBPluginDependency - 124.IBPluginDependency - 125.IBPluginDependency - 126.IBPluginDependency - 130.IBPluginDependency - 131.IBPluginDependency - 134.IBPluginDependency - 136.IBPluginDependency - 144.IBPluginDependency - 145.IBPluginDependency - 149.IBPluginDependency - 150.IBPluginDependency - 19.IBPluginDependency - 23.IBPluginDependency - 236.IBPluginDependency - 239.IBPluginDependency - 24.IBPluginDependency - 29.IBPluginDependency - 371.IBPluginDependency - 371.IBWindowTemplateEditedContentRect - 371.NSWindowTemplate.visibleAtLaunch - 372.IBPluginDependency - 490.IBPluginDependency - 491.IBPluginDependency - 492.IBPluginDependency - 494.IBPluginDependency - 5.IBPluginDependency - 545.IBPluginDependency - 546.IBPluginDependency - 549.IBPluginDependency - 551.IBPluginDependency - 56.IBPluginDependency - 57.IBPluginDependency - 58.IBPluginDependency - 585.IBPluginDependency - 586.IBPluginDependency - 587.IBPluginDependency - 592.IBPluginDependency - 597.IBPluginDependency - 598.IBPluginDependency - 602.IBPluginDependency - 603.IBPluginDependency - 612.IBPluginDependency - 613.IBPluginDependency - 614.IBPluginDependency - 616.IBPluginDependency - 618.IBPluginDependency - 620.IBPluginDependency - 622.IBPluginDependency - 624.IBPluginDependency - 626.IBPluginDependency - 629.IBPluginDependency - 630.IBPluginDependency - 633.IBPluginDependency - 635.IBPluginDependency - 637.IBPluginDependency - 639.IBPluginDependency - 641.IBPluginDependency - 643.IBPluginDependency - 645.IBPluginDependency - 647.IBPluginDependency - 649.IBPluginDependency - 651.IBPluginDependency - 654.IBPluginDependency - 656.IBPluginDependency - 658.IBPluginDependency - 660.IBPluginDependency - 661.IBPluginDependency - 663.IBPluginDependency - 72.IBPluginDependency - 73.IBPluginDependency - 79.IBPluginDependency - 81.IBPluginDependency - 83.IBPluginDependency - 92.IBPluginDependency - - - YES - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - {{438, 199}, {480, 360}} - - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - - - - YES - - - - - - YES - - - - - 665 - - - - YES - - RetroArch_OSX - NSObject - - YES - - YES - basicEvent: - openCore: - showCoresDirectory: - showPreferences: - - - YES - id - id - id - id - - - - YES - - YES - basicEvent: - openCore: - showCoresDirectory: - showPreferences: - - - YES - - basicEvent: - id - - - openCore: - id - - - showCoresDirectory: - id - - - showPreferences: - id - - - - - window - NSWindow - - - window - - window - NSWindow - - - - IBProjectSource - ./Classes/RetroArch.h - - - - - 0 - IBCocoaFramework - - com.apple.InterfaceBuilder.CocoaPlugin.macosx - - - - com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 - - - YES - 3 - - YES - - YES - NSMenuCheckmark - NSMenuMixedState - - - YES - {11, 11} - {10, 3} - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pkg/apple/OSX/en.lproj/MainMenu_PPC.xib b/pkg/apple/OSX/en.lproj/MainMenu_PPC.xib new file mode 100644 index 0000000000..b9d83c4861 --- /dev/null +++ b/pkg/apple/OSX/en.lproj/MainMenu_PPC.xib @@ -0,0 +1,1809 @@ + + + + 1050 + 12F45 + 3084 + 1187.40 + 626.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 3084 + + + YES + NSCustomObject + NSMenu + NSMenuItem + NSView + NSWindowTemplate + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + YES + + NSApplication + + + FirstResponder + + + NSApplication + + + AMainMenu + + YES + + + RetroArch + + 1048576 + 2147483647 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + submenuAction: + + + RetroArch + + YES + + + About RetroArch + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + + Services + + YES + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide RetroArch + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit RetroArch + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + + File + + YES + + + Load Core... + + 2147483647 + + + + + + Load Content... + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + + Open Recent + + YES + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + + + + Command + + 2147483647 + + + submenuAction: + + + Command + + YES + + + Audio Options + + 2147483647 + + + submenuAction: + + Audio Options + + YES + + + Mute Toggle + + 2147483647 + + + 11 + + + + + + + Disk Options + + 1048576 + 2147483647 + + + submenuAction: + + Disk Options + + YES + + + Cycle Tray + + 2147483647 + + + 4 + + + + Next Disk + + 2147483647 + + + 6 + + + + Previous Disk + + 2147483647 + + + 5 + + + + + + + Mouse Options + + 1048576 + 2147483647 + + + submenuAction: + + Mouse Options + + YES + + + Mouse Grab Toggle + + 2147483647 + + + 7 + + + + + + + Save State Options + + 1048576 + 2147483647 + + + submenuAction: + + Save State Options + + YES + + + Load State + + 2147483647 + + + 2 + + + + Save State + + 2147483647 + + + 3 + + + + + + + Reset + + 2147483647 + + + 1 + + + + Menu Toggle + + 2147483647 + + + 8 + + + + Pause Toggle + + 2147483647 + + + 9 + + + + Take Screenshot + + 2147483647 + + + 10 + + + + + + + Paths + + 2147483647 + + + submenuAction: + + + Paths + + YES + + + Core Directory + + 2147483647 + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + + Window + + YES + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + Windowed Scale + + 1048576 + 2147483647 + + + submenuAction: + + + + YES + + + 1x + + 2147483647 + + + 10 + + + + 2x + + 2147483647 + + + 11 + + + + 3x + + 2147483647 + + + 12 + + + + 4x + + 2147483647 + + + 13 + + + + 5x + + 2147483647 + + + 14 + + + + 6x + + 2147483647 + + + 15 + + + + 7x + + 2147483647 + + + 16 + + + + 8x + + 2147483647 + + + 17 + + + + 9x + + 2147483647 + + + 18 + + + + 10x + + 2147483647 + + + 19 + + + + + + + Enter Full Screen + f + 1310720 + 2147483647 + + + + + + Toggle Exclusive Full Screen + + 2147483647 + + + 20 + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 2147483647 + + + submenuAction: + + + Help + + YES + + + RetroArch Help + ? + 1048576 + 2147483647 + + + + + _NSHelpMenu + + + + _NSMainMenu + + + 15 + 2 + {{335, 390}, {480, 360}} + 1954021376 + RetroArch_OSX + NSWindow + + + + + 256 + {480, 360} + + + + {{0, 0}, {2560, 1418}} + {10000000000000, 10000000000000} + YES + + + RetroArch_OSX + + + + + YES + + + terminate: + + + + 449 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 495 + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + clearRecentDocuments: + + + + 127 + + + + performClose: + + + + 193 + + + + performZoom: + + + + 240 + + + + hide: + + + + 367 + + + + hideOtherApplications: + + + + 368 + + + + unhideAllApplications: + + + + 370 + + + + showHelp: + + + + 493 + + + + toggleFullScreen: + + + + 593 + + + + openDocument: + + + + 657 + + + + basicEvent: + + + + 550 + + + + basicEvent: + + + + 552 + + + + showCoresDirectory: + + + + 588 + + + + window + + + + 591 + + + + basicEvent: + + + + 615 + + + + basicEvent: + + + + 617 + + + + basicEvent: + + + + 619 + + + + basicEvent: + + + + 621 + + + + basicEvent: + + + + 623 + + + + basicEvent: + + + + 625 + + + + basicEvent: + + + + 627 + + + + basicEvent: + + + + 634 + + + + basicEvent: + + + + 636 + + + + basicEvent: + + + + 638 + + + + basicEvent: + + + + 640 + + + + basicEvent: + + + + 642 + + + + basicEvent: + + + + 644 + + + + basicEvent: + + + + 646 + + + + basicEvent: + + + + 648 + + + + basicEvent: + + + + 650 + + + + basicEvent: + + + + 652 + + + + basicEvent: + + + + 655 + + + + basicEvent: + + + + 659 + + + + basicEvent: + + + + 664 + + + + openCore: + + + + 665 + + + + + YES + + 0 + + YES + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + -3 + + + Application + + + 29 + + + YES + + + + + + + + + + + 19 + + + YES + + + + + + 56 + + + YES + + + + + + 83 + + + YES + + + + + + 81 + + + YES + + + + + + + + + + 72 + + + + + 124 + + + YES + + + + + + 73 + + + + + 79 + + + + + 125 + + + YES + + + + + + 126 + + + + + 57 + + + YES + + + + + + + + + + + + + + 58 + + + + + 134 + + + + + 150 + + + + + 136 + + + + + 144 + + + + + 236 + + + + + 131 + + + YES + + + + + + 149 + + + + + 145 + + + + + 130 + + + + + 371 + + + YES + + + + + + 372 + + + + + 490 + + + YES + + + + + + 491 + + + YES + + + + + + 492 + + + + + 494 + + + + + 545 + + + YES + + + + + + 546 + + + YES + + + + + + + + + + + + + 585 + + + YES + + + + + + 586 + + + YES + + + + + + 587 + + + + + 597 + + + YES + + + + + + 598 + + + YES + + + + + + + + 602 + + + YES + + + + + + 603 + + + YES + + + + + + 24 + + + YES + + + + + + + + + + + + 592 + + + + + 23 + + + + + 239 + + + + + 5 + + + + + 92 + + + + + 612 + + + YES + + + + + + 613 + + + YES + + + + + + + 549 + + + + + 551 + + + + + 614 + + + + + 616 + + + + + 618 + + + + + 620 + + + + + 629 + + + YES + + + + + + 630 + + + YES + + + + + + + + + + + + + + + 633 + + + + + 635 + + + + + 637 + + + + + 639 + + + + + 641 + + + + + 643 + + + + + 645 + + + + + 647 + + + + + 649 + + + + + 651 + + + + + 654 + + + + + 622 + + + + + 624 + + + + + 626 + + + + + 656 + + + + + 658 + + + + + 660 + + + YES + + + + + + 661 + + + YES + + + + + + 663 + + + + + + + YES + + YES + -1.IBPluginDependency + -2.IBPluginDependency + -3.IBPluginDependency + 124.IBPluginDependency + 125.IBPluginDependency + 126.IBPluginDependency + 130.IBPluginDependency + 131.IBPluginDependency + 134.IBPluginDependency + 136.IBPluginDependency + 144.IBPluginDependency + 145.IBPluginDependency + 149.IBPluginDependency + 150.IBPluginDependency + 19.IBPluginDependency + 23.IBPluginDependency + 236.IBPluginDependency + 239.IBPluginDependency + 24.IBPluginDependency + 29.IBPluginDependency + 371.IBPluginDependency + 371.IBWindowTemplateEditedContentRect + 371.NSWindowTemplate.visibleAtLaunch + 372.IBPluginDependency + 490.IBPluginDependency + 491.IBPluginDependency + 492.IBPluginDependency + 494.IBPluginDependency + 5.IBPluginDependency + 545.IBPluginDependency + 546.IBPluginDependency + 549.IBPluginDependency + 551.IBPluginDependency + 56.IBPluginDependency + 57.IBPluginDependency + 58.IBPluginDependency + 585.IBPluginDependency + 586.IBPluginDependency + 587.IBPluginDependency + 592.IBPluginDependency + 597.IBPluginDependency + 598.IBPluginDependency + 602.IBPluginDependency + 603.IBPluginDependency + 612.IBPluginDependency + 613.IBPluginDependency + 614.IBPluginDependency + 616.IBPluginDependency + 618.IBPluginDependency + 620.IBPluginDependency + 622.IBPluginDependency + 624.IBPluginDependency + 626.IBPluginDependency + 629.IBPluginDependency + 630.IBPluginDependency + 633.IBPluginDependency + 635.IBPluginDependency + 637.IBPluginDependency + 639.IBPluginDependency + 641.IBPluginDependency + 643.IBPluginDependency + 645.IBPluginDependency + 647.IBPluginDependency + 649.IBPluginDependency + 651.IBPluginDependency + 654.IBPluginDependency + 656.IBPluginDependency + 658.IBPluginDependency + 660.IBPluginDependency + 661.IBPluginDependency + 663.IBPluginDependency + 72.IBPluginDependency + 73.IBPluginDependency + 79.IBPluginDependency + 81.IBPluginDependency + 83.IBPluginDependency + 92.IBPluginDependency + + + YES + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + {{438, 199}, {480, 360}} + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + YES + + + + + + YES + + + + + 665 + + + + YES + + RetroArch_OSX + NSObject + + YES + + YES + basicEvent: + openCore: + showCoresDirectory: + showPreferences: + + + YES + id + id + id + id + + + + YES + + YES + basicEvent: + openCore: + showCoresDirectory: + showPreferences: + + + YES + + basicEvent: + id + + + openCore: + id + + + showCoresDirectory: + id + + + showPreferences: + id + + + + + window + NSWindow + + + window + + window + NSWindow + + + + IBProjectSource + ./Classes/RetroArch.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 + + + YES + 3 + + YES + + YES + NSMenuCheckmark + NSMenuMixedState + + + YES + {11, 11} + {10, 3} + + + + diff --git a/ui/ui_companion_driver.c b/ui/ui_companion_driver.c index a866b6749b..daeae6e1d3 100644 --- a/ui/ui_companion_driver.c +++ b/ui/ui_companion_driver.c @@ -30,7 +30,7 @@ static const ui_companion_driver_t *ui_companion_drivers[] = { #if defined(_WIN32) && !defined(_XBOX) &ui_companion_win32, #endif -#ifdef HAVE_COCOA +#if defined(HAVE_COCOA) || defined(HAVE_COCOA_METAL) &ui_companion_cocoa, #endif #ifdef HAVE_COCOATOUCH From dde354560002ed0bea840ad72cfc7771a3fbdd70 Mon Sep 17 00:00:00 2001 From: Stuart Carnie Date: Sun, 4 Nov 2018 10:59:54 -0700 Subject: [PATCH 09/10] chore(cocoa): Revert to using cocoa_gl_ctx.m; remove macos_ctx.m --- gfx/drivers_context/macos_ctx.m | 917 ------------------ .../RetroArch_Metal.xcodeproj/project.pbxproj | 2 - 2 files changed, 919 deletions(-) delete mode 100644 gfx/drivers_context/macos_ctx.m diff --git a/gfx/drivers_context/macos_ctx.m b/gfx/drivers_context/macos_ctx.m deleted file mode 100644 index 329fc062cf..0000000000 --- a/gfx/drivers_context/macos_ctx.m +++ /dev/null @@ -1,917 +0,0 @@ -/* RetroArch - A frontend for libretro. - * Copyright (C) 2018 - Stuart Carnie - * - * RetroArch is free software: you can redistribute it and/or modify it under the terms - * of the GNU General Public License as published by the Free Software Found- - * ation, either version 3 of the License, or (at your option) any later version. - * - * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along with RetroArch. - * If not, see . - */ - -#ifdef HAVE_CONFIG_H -#include "../../config.h" -#endif - -#if TARGET_OS_IPHONE -#include -#else -#include -#endif -#if defined(HAVE_COCOA) -#include -#include -#include -#include -#elif defined(HAVE_COCOATOUCH) -#include -#ifdef HAVE_AVFOUNDATION -#import -#endif -#endif - -#include -#include - -#import "../../ui/drivers/cocoa/cocoa_common.h" -#include "../video_driver.h" -#include "../../configuration.h" -#include "../../verbosity.h" -#ifdef HAVE_VULKAN -#include "../common/vulkan_common.h" -#endif - -#if defined(HAVE_COCOATOUCH) -#define GLContextClass EAGLContext -#define GLFrameworkID CFSTR("com.apple.opengles") -#define RAScreen UIScreen - -#ifndef UIUserInterfaceIdiomTV -#define UIUserInterfaceIdiomTV 2 -#endif - -#ifndef UIUserInterfaceIdiomCarPlay -#define UIUserInterfaceIdiomCarPlay 3 -#endif - -@interface EAGLContext (OSXCompat) @end -@implementation EAGLContext (OSXCompat) -+ (void)clearCurrentContext { [EAGLContext setCurrentContext:nil]; } -- (void)makeCurrentContext { [EAGLContext setCurrentContext:self]; } -@end - -#else - -@interface NSScreen (IOSCompat) @end -@implementation NSScreen (IOSCompat) -- (CGRect)bounds -{ - CGRect cgrect = NSRectToCGRect(self.frame); - return CGRectMake(0, 0, CGRectGetWidth(cgrect), CGRectGetHeight(cgrect)); -} -- (float) scale { return 1.0f; } -@end - -#define GLContextClass NSOpenGLContext -#define GLFrameworkID CFSTR("com.apple.opengl") -#define RAScreen NSScreen -#endif - -static enum gfx_ctx_api cocoagl_api = GFX_CTX_NONE; - -typedef struct cocoa_ctx_data -{ - bool core_hw_context_enable; -#ifdef HAVE_VULKAN - gfx_ctx_vulkan_data_t vk; - int swap_interval; -#endif - unsigned width; - unsigned height; -} cocoa_ctx_data_t; - -#if defined(HAVE_COCOATOUCH) - -static GLKView *g_view; -UIView *g_pause_indicator_view; -#endif - -static GLContextClass* g_hw_ctx; -static GLContextClass* g_context; - -static int g_fast_forward_skips; -static bool g_is_syncing = true; -static bool g_use_hw_ctx = false; - -#if defined(HAVE_COCOA) -#include "../../ui/drivers/ui_cocoa.h" -static NSOpenGLPixelFormat* g_format; - -void *glcontext_get_ptr(void) -{ - return (BRIDGE void *)g_context; -} -#endif - -static unsigned g_minor = 0; -static unsigned g_major = 0; - -/* forward declaration */ -void *nsview_get_ptr(void); - -#if defined(HAVE_COCOATOUCH) -static void glkitview_init_xibs(void) -{ - /* iOS Pause menu and lifecycle. */ - UINib *xib = (UINib*)[UINib nibWithNibName:BOXSTRING("PauseIndicatorView") bundle:nil]; - g_pause_indicator_view = [[xib instantiateWithOwner:[RetroArch_iOS get] options:nil] lastObject]; -} -#endif - -void *glkitview_init(void) -{ -#if defined(HAVE_COCOATOUCH) - glkitview_init_xibs(); - - g_view = [GLKView new]; - g_view.multipleTouchEnabled = YES; - g_view.enableSetNeedsDisplay = NO; - [g_view addSubview:g_pause_indicator_view]; - - return (BRIDGE void *)((GLKView*)g_view); -#else - return nsview_get_ptr(); -#endif -} - -#if defined(HAVE_COCOATOUCH) -void cocoagl_bind_game_view_fbo(void) -{ -#ifdef HAVE_AVFOUNDATION - /* Implicitly initializes your audio session */ - AVAudioSession *audio_session = [AVAudioSession sharedInstance]; - [audio_session setCategory:AVAudioSessionCategoryAmbient error:nil]; - [audio_session setActive:YES error:nil]; -#endif - if (g_context) - [g_view bindDrawable]; -} -#endif - -static float get_from_selector(Class obj_class, id obj_id, SEL selector, CGFloat *ret) -{ - NSInvocation *invocation = [NSInvocation invocationWithMethodSignature: - [obj_class instanceMethodSignatureForSelector:selector]]; - [invocation setSelector:selector]; - [invocation setTarget:obj_id]; - [invocation invoke]; - [invocation getReturnValue:ret]; - RELEASE(invocation); - return *ret; -} - -void *get_chosen_screen(void) -{ - settings_t *settings = config_get_ptr(); - NSArray *screens = [RAScreen screens]; - if (!screens || !settings) - return NULL; - - if (settings->uints.video_monitor_index >= screens.count) - { - RARCH_WARN("video_monitor_index is greater than the number of connected monitors; using main screen instead."); - return (BRIDGE void*)screens; - } - - return ((BRIDGE void*)[screens objectAtIndex:settings->uints.video_monitor_index]); -} - - -float get_backing_scale_factor(void) -{ - static float - backing_scale_def = 0.0f; - RAScreen *screen = NULL; - - (void)screen; - - if (backing_scale_def != 0.0f) - return backing_scale_def; - - backing_scale_def = 1.0f; -#ifdef HAVE_COCOA - screen = (BRIDGE RAScreen*)get_chosen_screen(); - - if (screen) - { - SEL selector = NSSelectorFromString(BOXSTRING("backingScaleFactor")); - if ([screen respondsToSelector:selector]) - { - CGFloat ret; - NSView *g_view = apple_platform.renderView; - //CocoaView *g_view = (CocoaView*)nsview_get_ptr(); - backing_scale_def = (float)get_from_selector - ([[g_view window] class], [g_view window], selector, &ret); - } - } -#endif - - return backing_scale_def; -} - -void cocoagl_gfx_ctx_update(void) -{ - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: -#if defined(HAVE_COCOA) -#if MAC_OS_X_VERSION_10_7 - CGLUpdateContext(g_hw_ctx.CGLContextObj); - CGLUpdateContext(g_context.CGLContextObj); -#else - [g_hw_ctx update]; - [g_context update]; -#endif -#endif - break; - default: - break; - } -} - -static void cocoagl_gfx_ctx_destroy(void *data) -{ - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; - - if (!cocoa_ctx) - return; - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - [GLContextClass clearCurrentContext]; - -#if defined(HAVE_COCOA) - [g_context clearDrawable]; - RELEASE(g_context); - RELEASE(g_format); - if (g_hw_ctx) - { - [g_hw_ctx clearDrawable]; - } - RELEASE(g_hw_ctx); -#endif - [GLContextClass clearCurrentContext]; - g_context = nil; - break; - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - vulkan_context_destroy(&cocoa_ctx->vk, cocoa_ctx->vk.vk_surface != VK_NULL_HANDLE); - if (cocoa_ctx->vk.context.queue_lock) { - slock_free(cocoa_ctx->vk.context.queue_lock); - } - memset(&cocoa_ctx->vk, 0, sizeof(cocoa_ctx->vk)); - -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - - free(cocoa_ctx); -} - -static void *cocoagl_gfx_ctx_init(video_frame_info_t *video_info, void *video_driver) -{ - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*) - calloc(1, sizeof(cocoa_ctx_data_t)); - - if (!cocoa_ctx) - return NULL; - - switch (cocoagl_api) - { -#if defined(HAVE_COCOATOUCH) - case GFX_CTX_OPENGL_ES_API: - // setViewType is not (yet?) defined for iOS - // [apple_platform setViewType:APPLE_VIEW_TYPE_OPENGL_ES]; - break; -#elif defined(HAVE_COCOA) - case GFX_CTX_OPENGL_API: - [apple_platform setViewType:APPLE_VIEW_TYPE_OPENGL]; - break; -#endif - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - [apple_platform setViewType:APPLE_VIEW_TYPE_VULKAN]; - if (!vulkan_context_init(&cocoa_ctx->vk, VULKAN_WSI_MVK_MACOS)) - { - goto error; - } -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - - return cocoa_ctx; - -error: - free(cocoa_ctx); - return NULL; -} - -static enum gfx_ctx_api cocoagl_gfx_ctx_get_api(void *data) -{ - return cocoagl_api; -} - -static bool cocoagl_gfx_ctx_bind_api(void *data, enum gfx_ctx_api api, unsigned major, unsigned minor) -{ - (void)data; - switch (api) - { -#if defined(HAVE_COCOATOUCH) - case GFX_CTX_OPENGL_ES_API: - break; -#elif defined(HAVE_COCOA) - case GFX_CTX_OPENGL_API: - break; -#ifdef HAVE_VULKAN - case GFX_CTX_VULKAN_API: - break; -#endif -#endif - case GFX_CTX_NONE: - default: - return false; - } - - cocoagl_api = api; - g_minor = minor; - g_major = major; - - return true; -} - -static void cocoagl_gfx_ctx_swap_interval(void *data, int interval) -{ -#ifdef HAVE_VULKAN - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; -#endif - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - { -#if defined(HAVE_COCOATOUCH) // < No way to disable Vsync on iOS? - // Just skip presents so fast forward still works. - g_is_syncing = interval ? true : false; - g_fast_forward_skips = interval ? 0 : 3; -#elif defined(HAVE_COCOA) - GLint value = interval ? 1 : 0; - [g_context setValues:&value forParameter:NSOpenGLCPSwapInterval]; -#endif - break; - } - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - if (cocoa_ctx->swap_interval != interval) - { - cocoa_ctx->swap_interval = interval; - if (cocoa_ctx->vk.swapchain) - { - cocoa_ctx->vk.need_new_swapchain = true; - } - } -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - -} - -static void cocoagl_gfx_ctx_show_mouse(void *data, bool state) -{ - (void)data; - -#ifdef HAVE_COCOA - if (state) - [NSCursor unhide]; - else - [NSCursor hide]; -#endif -} - -static bool cocoagl_gfx_ctx_set_video_mode(void *data, - video_frame_info_t *video_info, - unsigned width, unsigned height, bool fullscreen) -{ - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; - cocoa_ctx->width = width; - cocoa_ctx->height = height; - -#if defined(HAVE_COCOA) - //CocoaView *g_view = (BRIDGE CocoaView *)nsview_get_ptr(); - NSView *g_view = apple_platform.renderView; -#endif - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - { -#if defined(HAVE_COCOA) - if ([g_view respondsToSelector: @selector(setWantsBestResolutionOpenGLSurface:)]) - [g_view setWantsBestResolutionOpenGLSurface:YES]; - - NSOpenGLPixelFormatAttribute attributes [] = { - NSOpenGLPFAColorSize, - 24, - NSOpenGLPFADoubleBuffer, - NSOpenGLPFAAllowOfflineRenderers, - NSOpenGLPFADepthSize, - (NSOpenGLPixelFormatAttribute)16, // 16 bit depth buffer - 0, /* profile */ - 0, /* profile enum */ - (NSOpenGLPixelFormatAttribute)0 - }; - -#if MAC_OS_X_VERSION_10_7 - if (g_major == 3 && (g_minor >= 1 && g_minor <= 3)) - { - attributes[6] = NSOpenGLPFAOpenGLProfile; - attributes[7] = NSOpenGLProfileVersion3_2Core; - } -#endif - -#if MAC_OS_X_VERSION_10_10 - if (g_major == 4 && g_minor == 1) - { - attributes[6] = NSOpenGLPFAOpenGLProfile; - attributes[7] = NSOpenGLProfileVersion4_1Core; - } -#endif - - g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1050 - if (g_format == nil) - { - /* NSOpenGLFPAAllowOfflineRenderers is - not supported on this OS version. */ - attributes[3] = (NSOpenGLPixelFormatAttribute)0; - g_format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; - } -#endif - - if (g_use_hw_ctx) - g_hw_ctx = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:nil]; - g_context = [[NSOpenGLContext alloc] initWithFormat:g_format shareContext:(g_use_hw_ctx) ? g_hw_ctx : nil]; - [g_context setView:g_view]; -#else - if (g_use_hw_ctx) - g_hw_ctx = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - g_context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2]; - g_view.context = g_context; -#endif - - [g_context makeCurrentContext]; - break; - } - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - RARCH_LOG("[macOS]: Native window size: %u x %u.\n", cocoa_ctx->width, cocoa_ctx->height); - if (!vulkan_surface_create(&cocoa_ctx->vk, - VULKAN_WSI_MVK_MACOS, NULL, - (BRIDGE void *)g_view, cocoa_ctx->width, cocoa_ctx->height, - cocoa_ctx->swap_interval)) - { - RARCH_ERR("[macOS]: Failed to create surface.\n"); - return false; - } -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - -#if defined(HAVE_COCOA) - static bool has_went_fullscreen = false; - /* TODO: Screen mode support. */ - - if (fullscreen) - { - if (!has_went_fullscreen) - { - [g_view enterFullScreenMode:(BRIDGE NSScreen *)get_chosen_screen() withOptions:nil]; - cocoagl_gfx_ctx_show_mouse(data, false); - } - } - else - { - if (has_went_fullscreen) - { - [g_view exitFullScreenModeWithOptions:nil]; - [[g_view window] makeFirstResponder:g_view]; - cocoagl_gfx_ctx_show_mouse(data, true); - } - - [[g_view window] setContentSize:NSMakeSize(width, height)]; - } - - has_went_fullscreen = fullscreen; -#endif - - /* TODO: Maybe iOS users should be able to show/hide the status bar here? */ - - return true; -} - -float cocoagl_gfx_ctx_get_native_scale(void) -{ - static CGFloat ret = 0.0f; - SEL selector = NSSelectorFromString(BOXSTRING("nativeScale")); - RAScreen *screen = (BRIDGE RAScreen*)get_chosen_screen(); - - if (ret != 0.0f) - return ret; - if (!screen) - return 0.0f; - - if ([screen respondsToSelector:selector]) - return (float)get_from_selector([screen class], screen, selector, &ret); - - ret = 1.0f; - selector = NSSelectorFromString(BOXSTRING("scale")); - if ([screen respondsToSelector:selector]) - ret = screen.scale; - return ret; -} - -static void cocoagl_gfx_ctx_get_video_size(void *data, unsigned* width, unsigned* height) -{ - float screenscale = cocoagl_gfx_ctx_get_native_scale(); -#if defined(HAVE_COCOA) - CGRect size; - GLsizei backingPixelWidth, backingPixelHeight; - NSView *g_view = apple_platform.renderView; - //CocoaView *g_view = (CocoaView*)nsview_get_ptr(); - CGRect cgrect = NSRectToCGRect([g_view frame]); -#if MAC_OS_X_VERSION_10_7 - SEL selector = NSSelectorFromString(BOXSTRING("convertRectToBacking:")); - if ([g_view respondsToSelector:selector]) - cgrect = NSRectToCGRect([g_view convertRectToBacking:[g_view bounds]]); -#endif - backingPixelWidth = CGRectGetWidth(cgrect); - backingPixelHeight = CGRectGetHeight(cgrect); - size = CGRectMake(0, 0, backingPixelWidth, backingPixelHeight); -#else - CGRect size = g_view.bounds; -#endif - *width = CGRectGetWidth(size) * screenscale; - *height = CGRectGetHeight(size) * screenscale; -} - -#if defined(HAVE_COCOA) -static void cocoagl_gfx_ctx_update_title(void *data, void *data2) -{ - ui_window_cocoa_t view; - const ui_window_t *window = ui_companion_driver_get_window_ptr(); - - //view.data = (CocoaView*)nsview_get_ptr(); - view.data = (BRIDGE void *)apple_platform.renderView; - - if (window) - { - char title[128]; - - title[0] = '\0'; - - video_driver_get_window_title(title, sizeof(title)); - - if (title[0]) - window->set_title(&view, title); - } -} -#endif - -static bool cocoagl_gfx_ctx_get_metrics(void *data, enum display_metric_types type, - float *value) -{ - RAScreen *screen = (BRIDGE RAScreen*)get_chosen_screen(); -#if defined(HAVE_COCOA) - NSDictionary *description = [screen deviceDescription]; - NSSize display_pixel_size = [[description objectForKey:NSDeviceSize] sizeValue]; - CGSize display_physical_size = CGDisplayScreenSize( - [[description objectForKey:@"NSScreenNumber"] unsignedIntValue]); - - float display_width = display_pixel_size.width; - float display_height = display_pixel_size.height; - float physical_width = display_physical_size.width; - float physical_height = display_physical_size.height; - float scale = get_backing_scale_factor(); - float dpi = (display_width/ physical_width) * 25.4f * scale; -#elif defined(HAVE_COCOATOUCH) - float scale = cocoagl_gfx_ctx_get_native_scale(); - CGRect screen_rect = [screen bounds]; - float display_height = screen_rect.size.height; - float physical_width = screen_rect.size.width * scale; - float physical_height = screen_rect.size.height * scale; - float dpi = 160 * scale; - unsigned idiom_type = UI_USER_INTERFACE_IDIOM(); - - switch (idiom_type) - { - case -1: /* UIUserInterfaceIdiomUnspecified */ - /* TODO */ - break; - case UIUserInterfaceIdiomPad: - dpi = 132 * scale; - break; - case UIUserInterfaceIdiomPhone: - dpi = 163 * scale; - break; - case UIUserInterfaceIdiomTV: - case UIUserInterfaceIdiomCarPlay: - /* TODO */ - break; - } -#endif - - (void)display_height; - - switch (type) - { - case DISPLAY_METRIC_MM_WIDTH: - *value = physical_width; - break; - case DISPLAY_METRIC_MM_HEIGHT: - *value = physical_height; - break; - case DISPLAY_METRIC_DPI: - *value = dpi; - break; - case DISPLAY_METRIC_NONE: - default: - *value = 0; - return false; - } - - return true; -} - -static bool cocoagl_gfx_ctx_has_focus(void *data) -{ - (void)data; -#if defined(HAVE_COCOATOUCH) - return ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive); -#else - return [NSApp isActive]; -#endif -} - -static bool cocoagl_gfx_ctx_suppress_screensaver(void *data, bool enable) -{ - (void)data; - (void)enable; - - return false; -} - -#if !defined(HAVE_COCOATOUCH) -static bool cocoagl_gfx_ctx_has_windowed(void *data) -{ - return true; -} -#endif - -#ifdef HAVE_VULKAN -static void *cocoagl_gfx_ctx_get_context_data(void *data) -{ - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; - return &cocoa_ctx->vk.context; -} -#endif - - -static void cocoagl_gfx_ctx_swap_buffers(void *data, void *data2) -{ -#ifdef HAVE_VULKAN - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; -#endif - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - if (!(--g_fast_forward_skips < 0)) - return; - -#if defined(HAVE_COCOA) - [g_context flushBuffer]; - [g_hw_ctx flushBuffer]; -#elif defined(HAVE_COCOATOUCH) - if (g_view) - [g_view display]; -#endif - - g_fast_forward_skips = g_is_syncing ? 0 : 3; - break; - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - vulkan_present(&cocoa_ctx->vk, cocoa_ctx->vk.context.current_swapchain_index); - vulkan_acquire_next_image(&cocoa_ctx->vk); -#endif - break; - case GFX_CTX_NONE: - default: - break; - } -} - -static gfx_ctx_proc_t cocoagl_gfx_ctx_get_proc_address(const char *symbol_name) -{ - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - return (gfx_ctx_proc_t)CFBundleGetFunctionPointerForName(CFBundleGetBundleWithIdentifier(GLFrameworkID), - (BRIDGE CFStringRef)BOXSTRING(symbol_name) - ); - case GFX_CTX_NONE: - default: - break; - } - - return NULL; -} - -static bool cocoagl_gfx_ctx_set_resize(void *data, unsigned width, unsigned height) -{ -#ifdef HAVE_VULKAN - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; -#endif - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - break; - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - cocoa_ctx->width = width; - cocoa_ctx->height = height; - - if (vulkan_create_swapchain(&cocoa_ctx->vk, - width, height, cocoa_ctx->swap_interval)) - { - cocoa_ctx->vk.context.invalid_swapchain = true; - if (cocoa_ctx->vk.created_new_swapchain) - vulkan_acquire_next_image(&cocoa_ctx->vk); - } - else - { - RARCH_ERR("[macOS/Vulkan]: Failed to update swapchain.\n"); - return false; - } - - cocoa_ctx->vk.need_new_swapchain = false; -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - - return true; -} - - -static void cocoagl_gfx_ctx_check_window(void *data, bool *quit, - bool *resize, unsigned *width, unsigned *height, bool is_shutdown) -{ - unsigned new_width, new_height; -#ifdef HAVE_VULKAN - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; -#endif - - *quit = false; - - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - break; - case GFX_CTX_VULKAN_API: -#ifdef HAVE_VULKAN - *resize = cocoa_ctx->vk.need_new_swapchain; -#endif - break; - case GFX_CTX_NONE: - default: - break; - } - - cocoagl_gfx_ctx_get_video_size(data, &new_width, &new_height); - if (new_width != *width || new_height != *height) - { - *width = new_width; - *height = new_height; - *resize = true; - } -} - -static void cocoagl_gfx_ctx_input_driver(void *data, - const char *name, - const input_driver_t **input, void **input_data) -{ - *input = NULL; - *input_data = NULL; -} - -static void cocoagl_gfx_ctx_bind_hw_render(void *data, bool enable) -{ - (void)data; - switch (cocoagl_api) - { - case GFX_CTX_OPENGL_API: - case GFX_CTX_OPENGL_ES_API: - g_use_hw_ctx = enable; - - if (enable) - [g_hw_ctx makeCurrentContext]; - else - [g_context makeCurrentContext]; - break; - case GFX_CTX_NONE: - default: - break; - } -} - -static uint32_t cocoagl_gfx_ctx_get_flags(void *data) -{ - uint32_t flags = 0; - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; - - BIT32_SET(flags, GFX_CTX_FLAGS_NONE); - - if (cocoa_ctx->core_hw_context_enable) - BIT32_SET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT); - - return flags; -} - -static void cocoagl_gfx_ctx_set_flags(void *data, uint32_t flags) -{ - (void)flags; - cocoa_ctx_data_t *cocoa_ctx = (cocoa_ctx_data_t*)data; - - if (BIT32_GET(flags, GFX_CTX_FLAGS_GL_CORE_CONTEXT)) - cocoa_ctx->core_hw_context_enable = true; -} - -const gfx_ctx_driver_t gfx_ctx_cocoagl = { - .init = cocoagl_gfx_ctx_init, - .destroy = cocoagl_gfx_ctx_destroy, - .get_api = cocoagl_gfx_ctx_get_api, - .bind_api = cocoagl_gfx_ctx_bind_api, - .swap_interval = cocoagl_gfx_ctx_swap_interval, - .set_video_mode = cocoagl_gfx_ctx_set_video_mode, - .get_video_size = cocoagl_gfx_ctx_get_video_size, - .get_metrics = cocoagl_gfx_ctx_get_metrics, -#if defined(HAVE_COCOA) - .update_window_title = cocoagl_gfx_ctx_update_title, -#endif - .check_window = cocoagl_gfx_ctx_check_window, - .set_resize = cocoagl_gfx_ctx_set_resize, - .has_focus = cocoagl_gfx_ctx_has_focus, - .suppress_screensaver = cocoagl_gfx_ctx_suppress_screensaver, -#if !defined(HAVE_COCOATOUCH) - .has_windowed = cocoagl_gfx_ctx_has_windowed, -#endif - .swap_buffers = cocoagl_gfx_ctx_swap_buffers, - .input_driver = cocoagl_gfx_ctx_input_driver, - .get_proc_address = cocoagl_gfx_ctx_get_proc_address, - .ident = "macOS", - .get_flags = cocoagl_gfx_ctx_get_flags, - .set_flags = cocoagl_gfx_ctx_set_flags, - .bind_hw_render = cocoagl_gfx_ctx_bind_hw_render, -#if defined(HAVE_VULKAN) - .get_context_data = cocoagl_gfx_ctx_get_context_data, -#else - .get_context_data = NULL, -#endif -}; diff --git a/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj b/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj index 5475e66f4d..bf606084c4 100644 --- a/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj +++ b/pkg/apple/RetroArch_Metal.xcodeproj/project.pbxproj @@ -291,7 +291,6 @@ 05A8C5D220DB72F000FF7857 /* ui_companion_driver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ui_companion_driver.h; sourceTree = ""; }; 05A8C5D320DB72F000FF7857 /* ui_companion_driver.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = ui_companion_driver.c; sourceTree = ""; }; 05A8C5D520DB72F000FF7857 /* video_display_server.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = video_display_server.c; sourceTree = ""; }; - 05A8C5DD20DB72F000FF7857 /* macos_ctx.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = macos_ctx.m; sourceTree = ""; }; 05A8C5E720DB72F000FF7857 /* cocoa_gl_ctx.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = cocoa_gl_ctx.m; sourceTree = ""; }; 05A8C5F020DB72F000FF7857 /* gl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = gl.c; sourceTree = ""; }; 05A8C5F720DB72F000FF7857 /* metal.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = metal.m; sourceTree = ""; }; @@ -1014,7 +1013,6 @@ isa = PBXGroup; children = ( 05A8C5E720DB72F000FF7857 /* cocoa_gl_ctx.m */, - 05A8C5DD20DB72F000FF7857 /* macos_ctx.m */, A9020FA64527ED74C836B41D /* cocoa_gl_ctx_metal.m */, ); path = drivers_context; From 879a1b7092cdbb1631abe3113ad57e2602552355 Mon Sep 17 00:00:00 2001 From: Stuart Carnie Date: Sun, 4 Nov 2018 11:38:35 -0700 Subject: [PATCH 10/10] fix(cocoa): Update Metal xib to use deployment target --- pkg/apple/OSX/en.lproj/MainMenu_Metal.xib | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/apple/OSX/en.lproj/MainMenu_Metal.xib b/pkg/apple/OSX/en.lproj/MainMenu_Metal.xib index 934ee76845..ecf5bbe58b 100644 --- a/pkg/apple/OSX/en.lproj/MainMenu_Metal.xib +++ b/pkg/apple/OSX/en.lproj/MainMenu_Metal.xib @@ -1,8 +1,8 @@ - + - - + +