2016-05-04 19:24:41 +02:00
|
|
|
#pragma region Copyright (c) 2014-2016 OpenRCT2 Developers
|
2014-10-06 18:36:58 +02:00
|
|
|
/*****************************************************************************
|
|
|
|
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
|
2015-10-20 20:16:30 +02:00
|
|
|
*
|
2016-05-04 19:24:41 +02:00
|
|
|
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
|
|
|
|
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
|
2015-10-20 20:16:30 +02:00
|
|
|
*
|
2014-10-06 18:36:58 +02:00
|
|
|
* OpenRCT2 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 Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
2016-05-04 19:24:41 +02:00
|
|
|
*
|
|
|
|
* A full copy of the GNU General Public License can be found in licence.txt
|
2014-10-06 18:36:58 +02:00
|
|
|
*****************************************************************************/
|
2016-05-04 19:24:41 +02:00
|
|
|
#pragma endregion
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2015-11-27 18:01:22 +01:00
|
|
|
#if defined(__APPLE__) && defined(__MACH__)
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2015-12-13 00:22:14 +01:00
|
|
|
@import AppKit;
|
2015-12-18 22:59:41 +01:00
|
|
|
@import Foundation;
|
2015-12-13 00:22:14 +01:00
|
|
|
#include <mach-o/dyld.h>
|
2015-11-27 18:01:22 +01:00
|
|
|
#include "platform.h"
|
2015-12-06 18:34:34 +01:00
|
|
|
#include "../util/util.h"
|
2016-08-21 16:28:24 +02:00
|
|
|
#include "../localisation/language.h"
|
|
|
|
#include "../config.h"
|
2014-10-06 18:36:58 +02:00
|
|
|
|
2015-11-27 18:01:22 +01:00
|
|
|
bool platform_check_steam_overlay_attached() {
|
|
|
|
STUB();
|
|
|
|
return false;
|
2014-10-06 18:36:58 +02:00
|
|
|
}
|
|
|
|
|
2016-09-26 04:24:29 +02:00
|
|
|
void platform_get_exe_path(utf8 *outPath, size_t outSize)
|
2015-12-01 21:38:35 +01:00
|
|
|
{
|
2016-09-26 04:24:29 +02:00
|
|
|
if (outSize == 0) return;
|
2015-12-01 21:38:35 +01:00
|
|
|
char exePath[MAX_PATH];
|
2015-12-06 18:34:34 +01:00
|
|
|
uint32_t size = MAX_PATH;
|
2015-12-01 21:38:35 +01:00
|
|
|
int result = _NSGetExecutablePath(exePath, &size);
|
|
|
|
if (result != 0) {
|
|
|
|
log_fatal("failed to get path");
|
|
|
|
}
|
|
|
|
exePath[MAX_PATH - 1] = '\0';
|
2016-09-26 04:24:29 +02:00
|
|
|
char *exeDelimiter = strrchr(exePath, *PATH_SEPARATOR);
|
2015-12-01 21:38:35 +01:00
|
|
|
if (exeDelimiter == NULL)
|
|
|
|
{
|
|
|
|
log_error("should never happen here");
|
|
|
|
outPath[0] = '\0';
|
|
|
|
return;
|
|
|
|
}
|
2016-09-26 04:24:29 +02:00
|
|
|
*exeDelimiter = '\0';
|
2015-12-01 21:38:35 +01:00
|
|
|
|
2016-09-26 04:24:29 +02:00
|
|
|
safe_strcpy(outPath, exePath, outSize);
|
2015-12-01 21:38:35 +01:00
|
|
|
}
|
|
|
|
|
2015-12-12 00:02:47 +01:00
|
|
|
/**
|
|
|
|
* Default directory fallback is:
|
|
|
|
* - (command line argument)
|
|
|
|
* - ~/Library/Application Support/OpenRCT2
|
|
|
|
*/
|
2016-09-26 04:24:29 +02:00
|
|
|
void platform_posix_sub_user_data_path(char *buffer, size_t size, const char *homedir) {
|
2015-12-12 00:02:47 +01:00
|
|
|
if (homedir == NULL)
|
|
|
|
{
|
|
|
|
log_fatal("Couldn't find user data directory");
|
|
|
|
exit(-1);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-09-26 04:24:29 +02:00
|
|
|
safe_strcpy(buffer, homedir, size);
|
|
|
|
safe_strcat_path(buffer, "Library", size);
|
|
|
|
safe_strcat_path(buffer, "Application Support", size);
|
|
|
|
safe_strcat_path(buffer, "OpenRCT2", size);
|
|
|
|
path_end_with_separator(buffer, size);
|
2015-12-12 00:02:47 +01:00
|
|
|
}
|
|
|
|
|
2015-12-18 22:59:41 +01:00
|
|
|
/**
|
|
|
|
* Default directory fallback is:
|
|
|
|
* - (command line argument)
|
|
|
|
* - <exePath>/data
|
|
|
|
* - <Resources Folder>
|
|
|
|
*/
|
2016-09-26 04:24:29 +02:00
|
|
|
void platform_posix_sub_resolve_openrct_data_path(utf8 *out, size_t size) {
|
2015-12-18 22:59:41 +01:00
|
|
|
@autoreleasepool
|
|
|
|
{
|
|
|
|
NSBundle *bundle = [NSBundle mainBundle];
|
|
|
|
if (bundle)
|
|
|
|
{
|
|
|
|
const utf8 *resources = bundle.resourcePath.UTF8String;
|
|
|
|
if (platform_directory_exists(resources))
|
|
|
|
{
|
|
|
|
out[0] = '\0';
|
2016-09-26 04:24:29 +02:00
|
|
|
safe_strcpy(out, resources, size);
|
2015-12-18 22:59:41 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-13 00:22:14 +01:00
|
|
|
void platform_show_messagebox(char *message)
|
|
|
|
{
|
|
|
|
@autoreleasepool
|
|
|
|
{
|
2015-12-18 05:06:07 +01:00
|
|
|
NSAlert *alert = [[[NSAlert alloc] init] autorelease];
|
2015-12-13 00:22:14 +01:00
|
|
|
[alert addButtonWithTitle:@"OK"];
|
2015-12-18 05:06:07 +01:00
|
|
|
alert.messageText = [NSString stringWithUTF8String:message];
|
2015-12-13 00:22:14 +01:00
|
|
|
[alert runModal];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
utf8 *platform_open_directory_browser(utf8 *title)
|
|
|
|
{
|
|
|
|
@autoreleasepool
|
|
|
|
{
|
|
|
|
NSOpenPanel *panel = [NSOpenPanel openPanel];
|
|
|
|
panel.canChooseFiles = false;
|
|
|
|
panel.canChooseDirectories = true;
|
|
|
|
panel.allowsMultipleSelection = false;
|
|
|
|
utf8 *url = NULL;
|
|
|
|
if ([panel runModal] == NSFileHandlingPanelOKButton)
|
|
|
|
{
|
2015-12-18 05:06:07 +01:00
|
|
|
NSString *selectedPath = panel.URL.path;
|
|
|
|
const char *path = selectedPath.UTF8String;
|
2016-09-26 04:24:29 +02:00
|
|
|
url = _strdup(path);
|
2015-12-13 00:22:14 +01:00
|
|
|
}
|
|
|
|
return url;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-26 04:24:29 +02:00
|
|
|
bool platform_open_common_file_dialog(utf8 *outFilename, file_dialog_desc *desc, size_t outSize) {
|
2015-12-13 00:22:14 +01:00
|
|
|
@autoreleasepool
|
|
|
|
{
|
2016-02-26 06:19:10 +01:00
|
|
|
NSMutableArray *extensions = [NSMutableArray new];
|
|
|
|
for (int i=0; i < countof(desc->filters); ++i) {
|
|
|
|
if (desc->filters[i].pattern != NULL) {
|
|
|
|
NSString *fp = [NSString stringWithUTF8String:desc->filters[i].pattern];
|
|
|
|
fp = [fp stringByReplacingOccurrencesOfString:@"*." withString:@""];
|
|
|
|
[extensions addObjectsFromArray:[fp componentsSeparatedByString:@";"]];
|
|
|
|
}
|
|
|
|
}
|
2015-12-18 05:06:07 +01:00
|
|
|
|
2016-04-04 08:25:33 +02:00
|
|
|
NSString *directory;
|
2015-12-18 05:06:07 +01:00
|
|
|
NSSavePanel *panel;
|
2016-02-26 06:19:10 +01:00
|
|
|
if (desc->type == FD_SAVE)
|
2015-12-13 00:22:14 +01:00
|
|
|
{
|
2016-04-04 08:25:33 +02:00
|
|
|
NSString *filePath = [NSString stringWithUTF8String:desc->default_filename];
|
|
|
|
directory = filePath.stringByDeletingLastPathComponent;
|
|
|
|
NSString *basename = filePath.lastPathComponent;
|
2015-12-18 05:06:07 +01:00
|
|
|
panel = [NSSavePanel savePanel];
|
|
|
|
panel.nameFieldStringValue = [NSString stringWithFormat:@"%@.%@", basename, extensions.firstObject];
|
2015-12-13 00:22:14 +01:00
|
|
|
}
|
2016-02-26 06:19:10 +01:00
|
|
|
else if (desc->type == FD_OPEN)
|
2015-12-13 00:22:14 +01:00
|
|
|
{
|
2016-04-04 08:25:33 +02:00
|
|
|
directory = [NSString stringWithUTF8String:desc->initial_directory];
|
2015-12-18 05:06:07 +01:00
|
|
|
NSOpenPanel *open = [NSOpenPanel openPanel];
|
|
|
|
open.canChooseDirectories = false;
|
|
|
|
open.canChooseFiles = true;
|
|
|
|
open.allowsMultipleSelection = false;
|
|
|
|
panel = open;
|
2015-12-13 00:22:14 +01:00
|
|
|
} else {
|
2016-02-26 06:19:10 +01:00
|
|
|
return false;
|
2015-12-13 00:22:14 +01:00
|
|
|
}
|
2015-12-18 05:06:07 +01:00
|
|
|
|
2016-02-26 06:19:10 +01:00
|
|
|
panel.title = [NSString stringWithUTF8String:desc->title];
|
2015-12-18 05:06:07 +01:00
|
|
|
panel.allowedFileTypes = extensions;
|
|
|
|
panel.directoryURL = [NSURL fileURLWithPath:directory];
|
|
|
|
if ([panel runModal] == NSFileHandlingPanelCancelButton){
|
2016-01-24 01:20:45 +01:00
|
|
|
SDL_RaiseWindow(gWindow);
|
2016-02-26 06:19:10 +01:00
|
|
|
return false;
|
2015-12-18 05:06:07 +01:00
|
|
|
} else {
|
2016-09-26 04:24:29 +02:00
|
|
|
safe_strcpy(outFilename, panel.URL.path.UTF8String, outSize);
|
2016-01-24 01:20:45 +01:00
|
|
|
SDL_RaiseWindow(gWindow);
|
2016-02-26 06:19:10 +01:00
|
|
|
return true;
|
2015-12-18 05:06:07 +01:00
|
|
|
}
|
2015-12-13 00:22:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-09-26 04:24:29 +02:00
|
|
|
bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer, size_t size)
|
2015-12-24 18:52:33 +01:00
|
|
|
{
|
|
|
|
@autoreleasepool
|
|
|
|
{
|
|
|
|
CTFontDescriptorRef fontRef = CTFontDescriptorCreateWithNameAndSize((CFStringRef)[NSString stringWithUTF8String:font->font_name], 0.0);
|
|
|
|
CFURLRef url = (CFURLRef)CTFontDescriptorCopyAttribute(fontRef, kCTFontURLAttribute);
|
|
|
|
if (url) {
|
|
|
|
NSString *fontPath = [NSString stringWithString:[(NSURL *)CFBridgingRelease(url) path]];
|
2016-09-26 04:24:29 +02:00
|
|
|
safe_strcpy(buffer, fontPath.UTF8String, size);
|
2015-12-24 18:52:33 +01:00
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-21 16:28:24 +02:00
|
|
|
bool platform_has_matching_language(NSString *preferredLocale, uint16* languageIdentifier)
|
|
|
|
{
|
|
|
|
@autoreleasepool
|
|
|
|
{
|
|
|
|
if ([preferredLocale isEqualToString:@"en"] || [preferredLocale isEqualToString:@"en-CA"]) {
|
|
|
|
*languageIdentifier = LANGUAGE_ENGLISH_US;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([preferredLocale isEqualToString:@"zh-CN"]) {
|
|
|
|
*languageIdentifier = LANGUAGE_CHINESE_SIMPLIFIED;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ([preferredLocale isEqualToString:@"zh-TW"]) {
|
|
|
|
*languageIdentifier = LANGUAGE_CHINESE_TRADITIONAL;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Find an exact match (language and region)
|
|
|
|
for (int i = 1; i < LANGUAGE_COUNT; i++) {
|
|
|
|
if([preferredLocale isEqualToString:[NSString stringWithUTF8String:LanguagesDescriptors[i].locale]]) {
|
|
|
|
*languageIdentifier = i;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Only check for a matching language
|
|
|
|
NSString *languageCode = [[preferredLocale componentsSeparatedByString:@"-"] firstObject];
|
|
|
|
for (int i = 1; i < LANGUAGE_COUNT; i++) {
|
|
|
|
NSString *optionLanguageCode = [[[NSString stringWithUTF8String:LanguagesDescriptors[i].locale] componentsSeparatedByString:@"-"] firstObject];
|
|
|
|
if([languageCode isEqualToString:optionLanguageCode]) {
|
|
|
|
*languageIdentifier = i;
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16 platform_get_locale_language()
|
|
|
|
{
|
|
|
|
@autoreleasepool
|
|
|
|
{
|
|
|
|
NSArray<NSString*> *preferredLanguages = [NSLocale preferredLanguages];
|
|
|
|
for (NSString *preferredLanguage in preferredLanguages) {
|
|
|
|
uint16 languageIdentifier;
|
|
|
|
if (platform_has_matching_language(preferredLanguage, &languageIdentifier)) {
|
|
|
|
return languageIdentifier;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fallback
|
|
|
|
return LANGUAGE_ENGLISH_UK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-21 15:14:54 +02:00
|
|
|
uint8 platform_get_locale_currency()
|
|
|
|
{
|
|
|
|
@autoreleasepool
|
|
|
|
{
|
|
|
|
NSString *currencyCode = [[NSLocale currentLocale] objectForKey:NSLocaleCurrencyCode];
|
|
|
|
return platform_get_currency_value(currencyCode.UTF8String);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8 platform_get_locale_measurement_format()
|
|
|
|
{
|
|
|
|
@autoreleasepool
|
|
|
|
{
|
|
|
|
NSNumber *metricSystem = [[NSLocale currentLocale] objectForKey:NSLocaleUsesMetricSystem];
|
|
|
|
|
|
|
|
if (metricSystem.boolValue) {
|
|
|
|
return MEASUREMENT_FORMAT_METRIC;
|
|
|
|
}
|
|
|
|
|
|
|
|
return MEASUREMENT_FORMAT_IMPERIAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-27 18:01:22 +01:00
|
|
|
#endif
|