Add iOS platform (refactor Mac into shared Apple platform impl)
This commit is contained in:
@@ -996,16 +996,6 @@ Float2 AndroidPlatform::GetDesktopSize()
|
||||
return Float2((float)ScreenWidth, (float)ScreenHeight);
|
||||
}
|
||||
|
||||
Rectangle AndroidPlatform::GetMonitorBounds(const Float2& screenPos)
|
||||
{
|
||||
return Rectangle(Float2::Zero, GetDesktopSize());
|
||||
}
|
||||
|
||||
Rectangle AndroidPlatform::GetVirtualDesktopBounds()
|
||||
{
|
||||
return Rectangle(Float2::Zero, GetDesktopSize());
|
||||
}
|
||||
|
||||
String AndroidPlatform::GetMainDirectory()
|
||||
{
|
||||
return String(App->activity->internalDataPath);
|
||||
|
||||
@@ -120,9 +120,7 @@ public:
|
||||
static void OpenUrl(const StringView& url);
|
||||
static Float2 GetMousePosition();
|
||||
static void SetMousePosition(const Float2& pos);
|
||||
static Rectangle GetMonitorBounds(const Float2& screenPos);
|
||||
static Float2 GetDesktopSize();
|
||||
static Rectangle GetVirtualDesktopBounds();
|
||||
static String GetMainDirectory();
|
||||
static String GetExecutableFilePath();
|
||||
static Guid GetUniqueDeviceId();
|
||||
|
||||
532
Source/Engine/Platform/Apple/AppleFileSystem.cpp
Normal file
532
Source/Engine/Platform/Apple/AppleFileSystem.cpp
Normal file
@@ -0,0 +1,532 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_MAC || PLATFORM_IOS
|
||||
|
||||
#include "AppleFileSystem.h"
|
||||
#include "AppleUtils.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Types/StringView.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <cerrno>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
const DateTime UnixEpoch(1970, 1, 1);
|
||||
|
||||
bool AppleFileSystem::CreateDirectory(const StringView& path)
|
||||
{
|
||||
const StringAsANSI<> pathAnsi(*path, path.Length());
|
||||
|
||||
// Skip if already exists
|
||||
struct stat fileInfo;
|
||||
if (stat(pathAnsi.Get(), &fileInfo) != -1 && S_ISDIR(fileInfo.st_mode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Recursively do it all again for the parent directory, if any
|
||||
const int32 slashIndex = path.FindLast('/');
|
||||
if (slashIndex > 1)
|
||||
{
|
||||
if (CreateDirectory(path.Substring(0, slashIndex)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the last directory on the path (the recursive calls will have taken care of the parent directories by now)
|
||||
return mkdir(pathAnsi.Get(), 0755) != 0 && errno != EEXIST;
|
||||
}
|
||||
|
||||
bool DeletePathTree(const char* path)
|
||||
{
|
||||
size_t pathLength;
|
||||
DIR* dir;
|
||||
struct stat statPath, statEntry;
|
||||
struct dirent* entry;
|
||||
|
||||
// Stat for the path
|
||||
stat(path, &statPath);
|
||||
|
||||
// If path does not exists or is not dir - exit with status -1
|
||||
if (S_ISDIR(statPath.st_mode) == 0)
|
||||
{
|
||||
// Is not directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not possible to read the directory for this user
|
||||
if ((dir = opendir(path)) == NULL)
|
||||
{
|
||||
// Cannot open directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// The length of the path
|
||||
pathLength = strlen(path);
|
||||
|
||||
// Iteration through entries in the directory
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
// Skip entries "." and ".."
|
||||
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
// Determinate a full path of an entry
|
||||
char full_path[256];
|
||||
ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path));
|
||||
strcpy(full_path, path);
|
||||
strcat(full_path, "/");
|
||||
strcat(full_path, entry->d_name);
|
||||
|
||||
// Stat for the entry
|
||||
stat(full_path, &statEntry);
|
||||
|
||||
// Recursively remove a nested directory
|
||||
if (S_ISDIR(statEntry.st_mode) != 0)
|
||||
{
|
||||
if (DeletePathTree(full_path))
|
||||
return true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove a file object
|
||||
if (unlink(full_path) != 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove the devastated directory and close the object of it
|
||||
if (rmdir(path) != 0)
|
||||
return true;
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::DeleteDirectory(const String& path, bool deleteContents)
|
||||
{
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (deleteContents)
|
||||
return DeletePathTree(pathANSI.Get());
|
||||
return rmdir(pathANSI.Get()) != 0;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::DirectoryExists(const StringView& path)
|
||||
{
|
||||
struct stat fileInfo;
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (stat(pathANSI.Get(), &fileInfo) != -1)
|
||||
{
|
||||
return S_ISDIR(fileInfo.st_mode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::DirectoryGetFiles(Array<String>& results, const String& path, const Char* searchPattern, DirectorySearchOption option)
|
||||
{
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
const StringAsANSI<> searchPatternANSI(searchPattern);
|
||||
|
||||
// Check if use only top directory
|
||||
if (option == DirectorySearchOption::TopDirectoryOnly)
|
||||
return getFilesFromDirectoryTop(results, pathANSI.Get(), searchPatternANSI.Get());
|
||||
return getFilesFromDirectoryAll(results, pathANSI.Get(), searchPatternANSI.Get());
|
||||
}
|
||||
|
||||
bool AppleFileSystem::GetChildDirectories(Array<String>& results, const String& directory)
|
||||
{
|
||||
size_t pathLength;
|
||||
DIR* dir;
|
||||
struct stat statPath, statEntry;
|
||||
struct dirent* entry;
|
||||
const StringAsANSI<> pathANSI(*directory, directory.Length());
|
||||
const char* path = pathANSI.Get();
|
||||
|
||||
// Stat for the path
|
||||
stat(path, &statPath);
|
||||
|
||||
// If path does not exists or is not dir - exit with status -1
|
||||
if (S_ISDIR(statPath.st_mode) == 0)
|
||||
{
|
||||
// Is not directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not possible to read the directory for this user
|
||||
if ((dir = opendir(path)) == NULL)
|
||||
{
|
||||
// Cannot open directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// The length of the path
|
||||
pathLength = strlen(path);
|
||||
|
||||
// Iteration through entries in the directory
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
// Skip entries "." and ".."
|
||||
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
// Determinate a full path of an entry
|
||||
char full_path[256];
|
||||
ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path));
|
||||
strcpy(full_path, path);
|
||||
strcat(full_path, "/");
|
||||
strcat(full_path, entry->d_name);
|
||||
|
||||
// Stat for the entry
|
||||
stat(full_path, &statEntry);
|
||||
|
||||
// Check for directory
|
||||
if (S_ISDIR(statEntry.st_mode) != 0)
|
||||
{
|
||||
// Add directory
|
||||
results.Add(String(full_path));
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::FileExists(const StringView& path)
|
||||
{
|
||||
struct stat fileInfo;
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (stat(pathANSI.Get(), &fileInfo) != -1)
|
||||
{
|
||||
return S_ISREG(fileInfo.st_mode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::DeleteFile(const StringView& path)
|
||||
{
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
return unlink(pathANSI.Get()) == 0;
|
||||
}
|
||||
|
||||
uint64 AppleFileSystem::GetFileSize(const StringView& path)
|
||||
{
|
||||
struct stat fileInfo;
|
||||
fileInfo.st_size = -1;
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (stat(pathANSI.Get(), &fileInfo) != -1)
|
||||
{
|
||||
// Check for directories
|
||||
if (S_ISDIR(fileInfo.st_mode))
|
||||
{
|
||||
fileInfo.st_size = -1;
|
||||
}
|
||||
}
|
||||
return fileInfo.st_size;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::IsReadOnly(const StringView& path)
|
||||
{
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (access(pathANSI.Get(), W_OK) == -1)
|
||||
{
|
||||
return errno == EACCES;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::SetReadOnly(const StringView& path, bool isReadOnly)
|
||||
{
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
struct stat fileInfo;
|
||||
if (stat(pathANSI.Get(), &fileInfo) != -1)
|
||||
{
|
||||
if (isReadOnly)
|
||||
{
|
||||
fileInfo.st_mode &= ~S_IWUSR;
|
||||
}
|
||||
else
|
||||
{
|
||||
fileInfo.st_mode |= S_IWUSR;
|
||||
}
|
||||
return chmod(pathANSI.Get(), fileInfo.st_mode) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::MoveFile(const StringView& dst, const StringView& src, bool overwrite)
|
||||
{
|
||||
if (!overwrite && FileExists(dst))
|
||||
{
|
||||
// Already exists
|
||||
return true;
|
||||
}
|
||||
|
||||
if (overwrite)
|
||||
{
|
||||
unlink(StringAsANSI<>(*dst, dst.Length()).Get());
|
||||
}
|
||||
if (rename(StringAsANSI<>(*src, src.Length()).Get(), StringAsANSI<>(*dst, dst.Length()).Get()) != 0)
|
||||
{
|
||||
if (errno == EXDEV)
|
||||
{
|
||||
if (!CopyFile(dst, src))
|
||||
{
|
||||
unlink(StringAsANSI<>(*src, src.Length()).Get());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::CopyFile(const StringView& dst, const StringView& src)
|
||||
{
|
||||
const StringAsANSI<> srcANSI(*src, src.Length());
|
||||
const StringAsANSI<> dstANSI(*dst, dst.Length());
|
||||
|
||||
int srcFile, dstFile;
|
||||
char buffer[4096];
|
||||
ssize_t readSize;
|
||||
int cachedError;
|
||||
|
||||
srcFile = open(srcANSI.Get(), O_RDONLY);
|
||||
if (srcFile < 0)
|
||||
return true;
|
||||
dstFile = open(dstANSI.Get(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
if (dstFile < 0)
|
||||
goto out_error;
|
||||
|
||||
while (readSize = read(srcFile, buffer, sizeof(buffer)), readSize > 0)
|
||||
{
|
||||
char* ptr = buffer;
|
||||
ssize_t writeSize;
|
||||
|
||||
do
|
||||
{
|
||||
writeSize = write(dstFile, ptr, readSize);
|
||||
if (writeSize >= 0)
|
||||
{
|
||||
readSize -= writeSize;
|
||||
ptr += writeSize;
|
||||
}
|
||||
else if (errno != EINTR)
|
||||
{
|
||||
goto out_error;
|
||||
}
|
||||
} while (readSize > 0);
|
||||
}
|
||||
|
||||
if (readSize == 0)
|
||||
{
|
||||
if (close(dstFile) < 0)
|
||||
{
|
||||
dstFile = -1;
|
||||
goto out_error;
|
||||
}
|
||||
close(srcFile);
|
||||
|
||||
// Success
|
||||
return false;
|
||||
}
|
||||
|
||||
out_error:
|
||||
cachedError = errno;
|
||||
close(srcFile);
|
||||
if (dstFile >= 0)
|
||||
close(dstFile);
|
||||
errno = cachedError;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::getFilesFromDirectoryTop(Array<String>& results, const char* path, const char* searchPattern)
|
||||
{
|
||||
size_t pathLength;
|
||||
struct stat statPath, statEntry;
|
||||
struct dirent* entry;
|
||||
|
||||
// Stat for the path
|
||||
stat(path, &statPath);
|
||||
|
||||
// If path does not exists or is not dir - exit with status -1
|
||||
if (S_ISDIR(statPath.st_mode) == 0)
|
||||
{
|
||||
// Is not directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not possible to read the directory for this user
|
||||
DIR* dir = opendir(path);
|
||||
if (dir == NULL)
|
||||
{
|
||||
// Cannot open directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// The length of the path
|
||||
pathLength = strlen(path);
|
||||
|
||||
// Iteration through entries in the directory
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
// Skip entries "." and ".."
|
||||
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
// Determinate a full path of an entry
|
||||
char fullPath[256];
|
||||
ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(fullPath));
|
||||
strcpy(fullPath, path);
|
||||
strcat(fullPath, "/");
|
||||
strcat(fullPath, entry->d_name);
|
||||
|
||||
// Stat for the entry
|
||||
stat(fullPath, &statEntry);
|
||||
|
||||
// Check for file
|
||||
if (S_ISREG(statEntry.st_mode) != 0)
|
||||
{
|
||||
// Validate with filter
|
||||
const int32 fullPathLength = StringUtils::Length(fullPath);
|
||||
const int32 searchPatternLength = StringUtils::Length(searchPattern);
|
||||
if (searchPatternLength == 0 || StringUtils::Compare(searchPattern, "*") == 0)
|
||||
{
|
||||
// All files
|
||||
}
|
||||
else if (searchPattern[0] == '*' && searchPatternLength < fullPathLength && StringUtils::Compare(fullPath + fullPathLength - searchPatternLength + 1, searchPattern + 1, searchPatternLength - 1) == 0)
|
||||
{
|
||||
// Path ending
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: implement all cases in a generic way
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add file
|
||||
results.Add(String(fullPath));
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AppleFileSystem::getFilesFromDirectoryAll(Array<String>& results, const char* path, const char* searchPattern)
|
||||
{
|
||||
// Find all files in this directory
|
||||
getFilesFromDirectoryTop(results, path, searchPattern);
|
||||
|
||||
size_t pathLength;
|
||||
DIR* dir;
|
||||
struct stat statPath, statEntry;
|
||||
struct dirent* entry;
|
||||
|
||||
// Stat for the path
|
||||
stat(path, &statPath);
|
||||
|
||||
// If path does not exists or is not dir - exit with status -1
|
||||
if (S_ISDIR(statPath.st_mode) == 0)
|
||||
{
|
||||
// Is not directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not possible to read the directory for this user
|
||||
if ((dir = opendir(path)) == NULL)
|
||||
{
|
||||
// Cannot open directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// The length of the path
|
||||
pathLength = strlen(path);
|
||||
|
||||
// Iteration through entries in the directory
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
// Skip entries "." and ".."
|
||||
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
// Determinate a full path of an entry
|
||||
char full_path[256];
|
||||
ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path));
|
||||
strcpy(full_path, path);
|
||||
strcat(full_path, "/");
|
||||
strcat(full_path, entry->d_name);
|
||||
|
||||
// Stat for the entry
|
||||
stat(full_path, &statEntry);
|
||||
|
||||
// Check for directory
|
||||
if (S_ISDIR(statEntry.st_mode) != 0)
|
||||
{
|
||||
if (getFilesFromDirectoryAll(results, full_path, searchPattern))
|
||||
{
|
||||
closedir(dir);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DateTime AppleFileSystem::GetFileLastEditTime(const StringView& path)
|
||||
{
|
||||
struct stat fileInfo;
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (stat(pathANSI.Get(), &fileInfo) == -1)
|
||||
{
|
||||
return DateTime::MinValue();
|
||||
}
|
||||
|
||||
const TimeSpan timeSinceEpoch(0, 0, fileInfo.st_mtime);
|
||||
return UnixEpoch + timeSinceEpoch;
|
||||
}
|
||||
|
||||
void AppleFileSystem::GetSpecialFolderPath(const SpecialFolder type, String& result)
|
||||
{
|
||||
String home;
|
||||
Platform::GetEnvironmentVariable(TEXT("HOME"), home);
|
||||
switch (type)
|
||||
{
|
||||
case SpecialFolder::Desktop:
|
||||
result = home / TEXT("/Desktop");
|
||||
break;
|
||||
case SpecialFolder::Documents:
|
||||
result = home / TEXT("/Documents");
|
||||
break;
|
||||
case SpecialFolder::Pictures:
|
||||
result = home / TEXT("/Pictures");
|
||||
break;
|
||||
case SpecialFolder::AppData:
|
||||
case SpecialFolder::LocalAppData:
|
||||
result = home / TEXT("/Library/Caches");
|
||||
break;
|
||||
case SpecialFolder::ProgramData:
|
||||
result = home / TEXT("/Library/Application Support");
|
||||
break;
|
||||
case SpecialFolder::Temporary:
|
||||
Platform::GetEnvironmentVariable(TEXT("TMPDIR"), result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
52
Source/Engine/Platform/Apple/AppleFileSystem.h
Normal file
52
Source/Engine/Platform/Apple/AppleFileSystem.h
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if PLATFORM_MAC || PLATFORM_IOS
|
||||
|
||||
#include "Engine/Platform/Base/FileSystemBase.h"
|
||||
|
||||
/// <summary>
|
||||
/// Apple platform implementation of filesystem service.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API AppleFileSystem : public FileSystemBase
|
||||
{
|
||||
public:
|
||||
|
||||
// [FileSystemBase]
|
||||
static bool CreateDirectory(const StringView& path);
|
||||
static bool DeleteDirectory(const String& path, bool deleteContents = true);
|
||||
static bool DirectoryExists(const StringView& path);
|
||||
static bool DirectoryGetFiles(Array<String, HeapAllocation>& results, const String& path, const Char* searchPattern, DirectorySearchOption option = DirectorySearchOption::AllDirectories);
|
||||
static bool GetChildDirectories(Array<String, HeapAllocation>& results, const String& directory);
|
||||
static bool FileExists(const StringView& path);
|
||||
static bool DeleteFile(const StringView& path);
|
||||
static uint64 GetFileSize(const StringView& path);
|
||||
static bool IsReadOnly(const StringView& path);
|
||||
static bool SetReadOnly(const StringView& path, bool isReadOnly);
|
||||
static bool MoveFile(const StringView& dst, const StringView& src, bool overwrite = false);
|
||||
static bool CopyFile(const StringView& dst, const StringView& src);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets last time when file has been modified (in UTC).
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to check.</param>
|
||||
/// <returns>The last write time or DateTime::MinValue() if cannot get data.</returns>
|
||||
static DateTime GetFileLastEditTime(const StringView& path);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the special folder path.
|
||||
/// </summary>
|
||||
/// <param name="type">The folder type.</param>
|
||||
/// <param name="result">The result full path.</param>
|
||||
static void GetSpecialFolderPath(const SpecialFolder type, String& result);
|
||||
|
||||
private:
|
||||
|
||||
static bool getFilesFromDirectoryTop(Array<String, HeapAllocation>& results, const char* path, const char* searchPattern);
|
||||
static bool getFilesFromDirectoryAll(Array<String, HeapAllocation>& results, const char* path, const char* searchPattern);
|
||||
};
|
||||
|
||||
#endif
|
||||
418
Source/Engine/Platform/Apple/ApplePlatform.cpp
Normal file
418
Source/Engine/Platform/Apple/ApplePlatform.cpp
Normal file
@@ -0,0 +1,418 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_MAC || PLATFORM_IOS
|
||||
|
||||
#include "ApplePlatform.h"
|
||||
#include "AppleUtils.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/Guid.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Collections/HashFunctions.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "Engine/Core/Collections/Dictionary.h"
|
||||
#include "Engine/Core/Collections/HashFunctions.h"
|
||||
#include "Engine/Core/Math/Math.h"
|
||||
#include "Engine/Core/Math/Rectangle.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Platform/CPUInfo.h"
|
||||
#include "Engine/Platform/MemoryStats.h"
|
||||
#include "Engine/Platform/StringUtils.h"
|
||||
#include "Engine/Platform/WindowsManager.h"
|
||||
#include "Engine/Platform/Clipboard.h"
|
||||
#include "Engine/Platform/IGuiData.h"
|
||||
#include "Engine/Platform/Base/PlatformUtils.h"
|
||||
#include "Engine/Utilities/StringConverter.h"
|
||||
#include "Engine/Threading/Threading.h"
|
||||
#include "Engine/Engine/Engine.h"
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
#include <unistd.h>
|
||||
#include <cstdint>
|
||||
#include <stdlib.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/time.h>
|
||||
#include <mach/mach_time.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <SystemConfiguration/SystemConfiguration.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <dlfcn.h>
|
||||
#if CRASH_LOG_ENABLE
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
CPUInfo Cpu;
|
||||
String UserLocale;
|
||||
double SecondsPerCycle;
|
||||
|
||||
float ApplePlatform::ScreenScale = 1.0f;
|
||||
|
||||
String AppleUtils::ToString(CFStringRef str)
|
||||
{
|
||||
if (!str)
|
||||
return String::Empty;
|
||||
String result;
|
||||
const int32 length = CFStringGetLength(str);
|
||||
if (length > 0)
|
||||
{
|
||||
CFRange range = CFRangeMake(0, length);
|
||||
result.ReserveSpace(length);
|
||||
CFStringGetBytes(str, range, kCFStringEncodingUTF16LE, '?', false, (uint8*)result.Get(), length * sizeof(Char), nullptr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CFStringRef AppleUtils::ToString(const StringView& str)
|
||||
{
|
||||
return CFStringCreateWithBytes(nullptr, (const UInt8*)str.GetText(), str.Length() * sizeof(Char), kCFStringEncodingUTF16LE, false);
|
||||
}
|
||||
|
||||
typedef uint16_t offset_t;
|
||||
#define align_mem_up(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
bool ApplePlatform::Is64BitPlatform()
|
||||
{
|
||||
return PLATFORM_64BITS;
|
||||
}
|
||||
|
||||
CPUInfo ApplePlatform::GetCPUInfo()
|
||||
{
|
||||
return Cpu;
|
||||
}
|
||||
|
||||
int32 ApplePlatform::GetCacheLineSize()
|
||||
{
|
||||
return Cpu.CacheLineSize;
|
||||
}
|
||||
|
||||
MemoryStats ApplePlatform::GetMemoryStats()
|
||||
{
|
||||
MemoryStats result;
|
||||
int64 value64;
|
||||
size_t value64Size = sizeof(value64);
|
||||
if (sysctlbyname("hw.memsize", &value64, &value64Size, nullptr, 0) != 0)
|
||||
value64 = 1024 * 1024;
|
||||
result.TotalPhysicalMemory = value64;
|
||||
int id[] = { CTL_HW, HW_MEMSIZE };
|
||||
if (sysctl(id, 2, &value64, &value64Size, nullptr, 0) != 0)
|
||||
value64Size = 1024;
|
||||
result.UsedPhysicalMemory = value64Size;
|
||||
xsw_usage swapusage;
|
||||
size_t swapusageSize = sizeof(swapusage);
|
||||
result.TotalVirtualMemory = result.TotalPhysicalMemory;
|
||||
result.UsedVirtualMemory = result.UsedPhysicalMemory;
|
||||
if (sysctlbyname("vm.swapusage", &swapusage, &swapusageSize, nullptr, 0) == 0)
|
||||
{
|
||||
result.TotalVirtualMemory += swapusage.xsu_total;
|
||||
result.UsedVirtualMemory += swapusage.xsu_used;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ProcessMemoryStats ApplePlatform::GetProcessMemoryStats()
|
||||
{
|
||||
ProcessMemoryStats result;
|
||||
result.UsedPhysicalMemory = 1024;
|
||||
result.UsedVirtualMemory = 1024;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64 ApplePlatform::GetCurrentThreadID()
|
||||
{
|
||||
return (uint64)pthread_mach_thread_np(pthread_self());
|
||||
}
|
||||
|
||||
void ApplePlatform::SetThreadPriority(ThreadPriority priority)
|
||||
{
|
||||
// TODO: impl this
|
||||
}
|
||||
|
||||
void ApplePlatform::SetThreadAffinityMask(uint64 affinityMask)
|
||||
{
|
||||
// TODO: impl this
|
||||
}
|
||||
|
||||
void ApplePlatform::Sleep(int32 milliseconds)
|
||||
{
|
||||
usleep(milliseconds * 1000);
|
||||
}
|
||||
|
||||
double ApplePlatform::GetTimeSeconds()
|
||||
{
|
||||
return SecondsPerCycle * mach_absolute_time();
|
||||
}
|
||||
|
||||
uint64 ApplePlatform::GetTimeCycles()
|
||||
{
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
uint64 ApplePlatform::GetClockFrequency()
|
||||
{
|
||||
return (uint64)(1.0 / SecondsPerCycle);
|
||||
}
|
||||
|
||||
void ApplePlatform::GetSystemTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond)
|
||||
{
|
||||
// Query for calendar time
|
||||
struct timeval time;
|
||||
gettimeofday(&time, nullptr);
|
||||
|
||||
// Convert to local time
|
||||
struct tm localTime;
|
||||
localtime_r(&time.tv_sec, &localTime);
|
||||
|
||||
// Extract time
|
||||
year = localTime.tm_year + 1900;
|
||||
month = localTime.tm_mon + 1;
|
||||
dayOfWeek = localTime.tm_wday;
|
||||
day = localTime.tm_mday;
|
||||
hour = localTime.tm_hour;
|
||||
minute = localTime.tm_min;
|
||||
second = localTime.tm_sec;
|
||||
millisecond = time.tv_usec / 1000;
|
||||
}
|
||||
|
||||
void ApplePlatform::GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond)
|
||||
{
|
||||
// Get the calendar time
|
||||
struct timeval time;
|
||||
gettimeofday(&time, nullptr);
|
||||
|
||||
// Convert to UTC time
|
||||
struct tm localTime;
|
||||
gmtime_r(&time.tv_sec, &localTime);
|
||||
|
||||
// Extract time
|
||||
year = localTime.tm_year + 1900;
|
||||
month = localTime.tm_mon + 1;
|
||||
dayOfWeek = localTime.tm_wday;
|
||||
day = localTime.tm_mday;
|
||||
hour = localTime.tm_hour;
|
||||
minute = localTime.tm_min;
|
||||
second = localTime.tm_sec;
|
||||
millisecond = time.tv_usec / 1000;
|
||||
}
|
||||
|
||||
bool ApplePlatform::Init()
|
||||
{
|
||||
if (UnixPlatform::Init())
|
||||
return true;
|
||||
|
||||
// Init timing
|
||||
{
|
||||
mach_timebase_info_data_t info;
|
||||
mach_timebase_info(&info);
|
||||
SecondsPerCycle = 1e-9 * (double)info.numer / (double)info.denom;
|
||||
}
|
||||
|
||||
// Get CPU info
|
||||
int32 value32;
|
||||
int64 value64;
|
||||
size_t value32Size = sizeof(value32), value64Size = sizeof(value64);
|
||||
if (sysctlbyname("hw.packages", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 1;
|
||||
Cpu.ProcessorPackageCount = value32;
|
||||
if (sysctlbyname("hw.physicalcpu", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 1;
|
||||
Cpu.ProcessorCoreCount = value32;
|
||||
if (sysctlbyname("hw.logicalcpu", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 1;
|
||||
Cpu.LogicalProcessorCount = value32;
|
||||
if (sysctlbyname("hw.l1icachesize", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 0;
|
||||
Cpu.L1CacheSize = value32;
|
||||
if (sysctlbyname("hw.l2cachesize", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 0;
|
||||
Cpu.L2CacheSize = value32;
|
||||
if (sysctlbyname("hw.l3cachesize", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 0;
|
||||
Cpu.L3CacheSize = value32;
|
||||
if (sysctlbyname("hw.pagesize", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = vm_page_size;
|
||||
Cpu.PageSize = value32;
|
||||
if (sysctlbyname("hw.cpufrequency_max", &value64, &value64Size, nullptr, 0) != 0)
|
||||
value64 = GetClockFrequency();
|
||||
Cpu.ClockSpeed = value64;
|
||||
if (sysctlbyname("hw.cachelinesize", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = PLATFORM_CACHE_LINE_SIZE;
|
||||
Cpu.CacheLineSize = value32;
|
||||
|
||||
// Get locale
|
||||
{
|
||||
CFLocaleRef locale = CFLocaleCopyCurrent();
|
||||
CFStringRef localeLang = (CFStringRef)CFLocaleGetValue(locale, kCFLocaleLanguageCode);
|
||||
CFStringRef localeCountry = (CFStringRef)CFLocaleGetValue(locale, kCFLocaleCountryCode);
|
||||
UserLocale = AppleUtils::ToString(localeLang);
|
||||
String localeCountryStr = AppleUtils::ToString(localeCountry);
|
||||
if (localeCountryStr.HasChars())
|
||||
UserLocale += TEXT("-") + localeCountryStr;
|
||||
CFRelease(locale);
|
||||
CFRelease(localeLang);
|
||||
CFRelease(localeCountry);
|
||||
}
|
||||
|
||||
// Init user
|
||||
{
|
||||
String username;
|
||||
GetEnvironmentVariable(TEXT("USER"), username);
|
||||
OnPlatformUserAdd(New<User>(username));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void ApplePlatform::Tick()
|
||||
{
|
||||
}
|
||||
|
||||
void ApplePlatform::BeforeExit()
|
||||
{
|
||||
}
|
||||
|
||||
void ApplePlatform::Exit()
|
||||
{
|
||||
}
|
||||
|
||||
void ApplePlatform::SetHighDpiAwarenessEnabled(bool enable)
|
||||
{
|
||||
// Disable resolution scaling in low dpi mode
|
||||
if (!enable)
|
||||
{
|
||||
CustomDpiScale /= ScreenScale;
|
||||
ScreenScale = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
String ApplePlatform::GetUserLocaleName()
|
||||
{
|
||||
return UserLocale;
|
||||
}
|
||||
|
||||
bool ApplePlatform::GetHasFocus()
|
||||
{
|
||||
// Check if any window is focused
|
||||
ScopeLock lock(WindowsManager::WindowsLocker);
|
||||
for (auto window : WindowsManager::Windows)
|
||||
{
|
||||
if (window->IsFocused())
|
||||
return true;
|
||||
}
|
||||
|
||||
// Default to true if has no windows open
|
||||
return WindowsManager::Windows.IsEmpty();
|
||||
}
|
||||
|
||||
void ApplePlatform::CreateGuid(Guid& result)
|
||||
{
|
||||
uuid_t uuid;
|
||||
uuid_generate(uuid);
|
||||
auto ptr = (uint32*)&uuid;
|
||||
result.A = ptr[0];
|
||||
result.B = ptr[1];
|
||||
result.C = ptr[2];
|
||||
result.D = ptr[3];
|
||||
}
|
||||
|
||||
bool ApplePlatform::CanOpenUrl(const StringView& url)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void ApplePlatform::OpenUrl(const StringView& url)
|
||||
{
|
||||
}
|
||||
|
||||
String ApplePlatform::GetExecutableFilePath()
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
uint32 size = PATH_MAX;
|
||||
String result;
|
||||
if (_NSGetExecutablePath(buf, &size) == 0)
|
||||
result.SetUTF8(buf, StringUtils::Length(buf));
|
||||
return result;
|
||||
}
|
||||
|
||||
String ApplePlatform::GetWorkingDirectory()
|
||||
{
|
||||
char buffer[256];
|
||||
getcwd(buffer, ARRAY_COUNT(buffer));
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
bool ApplePlatform::SetWorkingDirectory(const String& path)
|
||||
{
|
||||
return chdir(StringAsANSI<>(*path).Get()) != 0;
|
||||
}
|
||||
|
||||
bool ApplePlatform::GetEnvironmentVariable(const String& name, String& value)
|
||||
{
|
||||
char* env = getenv(StringAsANSI<>(*name).Get());
|
||||
if (env)
|
||||
{
|
||||
value = String(env);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ApplePlatform::SetEnvironmentVariable(const String& name, const String& value)
|
||||
{
|
||||
return setenv(StringAsANSI<>(*name).Get(), StringAsANSI<>(*value).Get(), true) != 0;
|
||||
}
|
||||
|
||||
void* ApplePlatform::LoadLibrary(const Char* filename)
|
||||
{
|
||||
const StringAsANSI<> filenameANSI(filename);
|
||||
void* result = dlopen(filenameANSI.Get(), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!result)
|
||||
{
|
||||
LOG(Error, "Failed to load {0} because {1}", filename, String(dlerror()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void ApplePlatform::FreeLibrary(void* handle)
|
||||
{
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
void* ApplePlatform::GetProcAddress(void* handle, const char* symbol)
|
||||
{
|
||||
return dlsym(handle, symbol);
|
||||
}
|
||||
|
||||
Array<ApplePlatform::StackFrame> ApplePlatform::GetStackFrames(int32 skipCount, int32 maxDepth, void* context)
|
||||
{
|
||||
Array<StackFrame> result;
|
||||
#if CRASH_LOG_ENABLE
|
||||
void* callstack[120];
|
||||
skipCount = Math::Min<int32>(skipCount, ARRAY_COUNT(callstack));
|
||||
int32 maxCount = Math::Min<int32>(ARRAY_COUNT(callstack), skipCount + maxDepth);
|
||||
int32 count = backtrace(callstack, maxCount);
|
||||
int32 useCount = count - skipCount;
|
||||
if (useCount > 0)
|
||||
{
|
||||
char** names = backtrace_symbols(callstack + skipCount, useCount);
|
||||
result.Resize(useCount);
|
||||
for (int32 i = 0; i < useCount; i++)
|
||||
{
|
||||
char* name = names[i];
|
||||
StackFrame& frame = result[i];
|
||||
frame.ProgramCounter = callstack[skipCount + i];
|
||||
frame.ModuleName[0] = 0;
|
||||
frame.FileName[0] = 0;
|
||||
frame.LineNumber = 0;
|
||||
int32 nameLen = Math::Min<int32>(StringUtils::Length(name), ARRAY_COUNT(frame.FunctionName) - 1);
|
||||
Platform::MemoryCopy(frame.FunctionName, name, nameLen);
|
||||
frame.FunctionName[nameLen] = 0;
|
||||
|
||||
}
|
||||
free(names);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
107
Source/Engine/Platform/Apple/ApplePlatform.h
Normal file
107
Source/Engine/Platform/Apple/ApplePlatform.h
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if PLATFORM_MAC || PLATFORM_IOS
|
||||
|
||||
#include "../Unix/UnixPlatform.h"
|
||||
|
||||
/// <summary>
|
||||
/// The Apple platform implementation and application management utilities.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API ApplePlatform : public UnixPlatform
|
||||
{
|
||||
public:
|
||||
static float ScreenScale;
|
||||
|
||||
public:
|
||||
|
||||
// [UnixPlatform]
|
||||
FORCE_INLINE static void MemoryBarrier()
|
||||
{
|
||||
__sync_synchronize();
|
||||
}
|
||||
FORCE_INLINE static int64 InterlockedExchange(int64 volatile* dst, int64 exchange)
|
||||
{
|
||||
return __sync_lock_test_and_set(dst, exchange);
|
||||
}
|
||||
FORCE_INLINE static int32 InterlockedCompareExchange(int32 volatile* dst, int32 exchange, int32 comperand)
|
||||
{
|
||||
return __sync_val_compare_and_swap(dst, comperand, exchange);
|
||||
}
|
||||
FORCE_INLINE static int64 InterlockedCompareExchange(int64 volatile* dst, int64 exchange, int64 comperand)
|
||||
{
|
||||
return __sync_val_compare_and_swap(dst, comperand, exchange);
|
||||
}
|
||||
FORCE_INLINE static int64 InterlockedIncrement(int64 volatile* dst)
|
||||
{
|
||||
return __sync_add_and_fetch(dst, 1);
|
||||
}
|
||||
FORCE_INLINE static int64 InterlockedDecrement(int64 volatile* dst)
|
||||
{
|
||||
return __sync_sub_and_fetch(dst, 1);
|
||||
}
|
||||
FORCE_INLINE static int64 InterlockedAdd(int64 volatile* dst, int64 value)
|
||||
{
|
||||
return __sync_fetch_and_add(dst, value);
|
||||
}
|
||||
FORCE_INLINE static int32 AtomicRead(int32 volatile* dst)
|
||||
{
|
||||
return __atomic_load_n(dst, __ATOMIC_RELAXED);
|
||||
}
|
||||
FORCE_INLINE static int64 AtomicRead(int64 volatile* dst)
|
||||
{
|
||||
return __atomic_load_n(dst, __ATOMIC_RELAXED);
|
||||
}
|
||||
FORCE_INLINE static void AtomicStore(int32 volatile* dst, int32 value)
|
||||
{
|
||||
__atomic_store(dst, &value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
FORCE_INLINE static void AtomicStore(int64 volatile* dst, int64 value)
|
||||
{
|
||||
__atomic_store(dst, &value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
FORCE_INLINE static void Prefetch(void const* ptr)
|
||||
{
|
||||
__builtin_prefetch(static_cast<char const*>(ptr));
|
||||
}
|
||||
static bool Is64BitPlatform();
|
||||
static CPUInfo GetCPUInfo();
|
||||
static int32 GetCacheLineSize();
|
||||
static MemoryStats GetMemoryStats();
|
||||
static ProcessMemoryStats GetProcessMemoryStats();
|
||||
static uint64 GetCurrentThreadID();
|
||||
static void SetThreadPriority(ThreadPriority priority);
|
||||
static void SetThreadAffinityMask(uint64 affinityMask);
|
||||
static void Sleep(int32 milliseconds);
|
||||
static double GetTimeSeconds();
|
||||
static uint64 GetTimeCycles();
|
||||
static uint64 GetClockFrequency();
|
||||
static void GetSystemTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond);
|
||||
static void GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond);
|
||||
static bool Init();
|
||||
static void Tick();
|
||||
static void BeforeExit();
|
||||
static void Exit();
|
||||
static void SetHighDpiAwarenessEnabled(bool enable);
|
||||
static String GetUserLocaleName();
|
||||
static bool GetHasFocus();
|
||||
static void CreateGuid(Guid& result);
|
||||
static bool CanOpenUrl(const StringView& url);
|
||||
static void OpenUrl(const StringView& url);
|
||||
static Rectangle GetMonitorBounds(const Float2& screenPos);
|
||||
static Float2 GetDesktopSize();
|
||||
static Rectangle GetVirtualDesktopBounds();
|
||||
static String GetMainDirectory();
|
||||
static String GetExecutableFilePath();
|
||||
static String GetWorkingDirectory();
|
||||
static bool SetWorkingDirectory(const String& path);
|
||||
static bool GetEnvironmentVariable(const String& name, String& value);
|
||||
static bool SetEnvironmentVariable(const String& name, const String& value);
|
||||
static void* LoadLibrary(const Char* filename);
|
||||
static void FreeLibrary(void* handle);
|
||||
static void* GetProcAddress(void* handle, const char* symbol);
|
||||
static Array<StackFrame, HeapAllocation> GetStackFrames(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -2,25 +2,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if PLATFORM_MAC
|
||||
#if PLATFORM_MAC || PLATFORM_IOS
|
||||
|
||||
#include "../Unix/UnixThread.h"
|
||||
#include <signal.h>
|
||||
|
||||
/// <summary>
|
||||
/// Thread object for Mac platform.
|
||||
/// Thread object for Apple platform.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API MacThread : public UnixThread
|
||||
class FLAXENGINE_API AppleThread : public UnixThread
|
||||
{
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MacThread"/> class.
|
||||
/// Initializes a new instance of the <see cref="AppleThread"/> class.
|
||||
/// </summary>
|
||||
/// <param name="runnable">The runnable.</param>
|
||||
/// <param name="name">The thread name.</param>
|
||||
/// <param name="priority">The thread priority.</param>
|
||||
MacThread(IRunnable* runnable, const String& name, ThreadPriority priority)
|
||||
AppleThread(IRunnable* runnable, const String& name, ThreadPriority priority)
|
||||
: UnixThread(runnable, name, priority)
|
||||
{
|
||||
}
|
||||
@@ -35,9 +35,9 @@ public:
|
||||
/// <param name="priority">Tells the thread whether it needs to adjust its priority or not. Defaults to normal priority</param>
|
||||
/// <param name="stackSize">The size of the stack to create. 0 means use the current thread's stack size</param>
|
||||
/// <returns>Pointer to the new thread or null if cannot create it</returns>
|
||||
static MacThread* Create(IRunnable* runnable, const String& name, ThreadPriority priority = ThreadPriority::Normal, uint32 stackSize = 0)
|
||||
static AppleThread* Create(IRunnable* runnable, const String& name, ThreadPriority priority = ThreadPriority::Normal, uint32 stackSize = 0)
|
||||
{
|
||||
return (MacThread*)Setup(New<MacThread>(runnable, name, priority), stackSize);
|
||||
return (AppleThread*)Setup(New<AppleThread>(runnable, name, priority), stackSize);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -2,15 +2,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if PLATFORM_MAC || PLATFORM_IOS
|
||||
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
class FLAXENGINE_API MacUtils
|
||||
// Apple platform utilities.
|
||||
class AppleUtils
|
||||
{
|
||||
public:
|
||||
static String ToString(CFStringRef str);
|
||||
static CFStringRef ToString(const StringView& str);
|
||||
#if PLATFORM_MAC
|
||||
static Float2 PosToCoca(const Float2& pos);
|
||||
static Float2 CocaToPos(const Float2& pos);
|
||||
static Float2 GetScreensOrigin();
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -520,6 +520,16 @@ void PlatformBase::CreateGuid(Guid& result)
|
||||
result = Guid(dateThingHigh, randomThing | (sequentialThing << 16), cyclesThing, dateThingLow);
|
||||
}
|
||||
|
||||
Rectangle PlatformBase::GetMonitorBounds(const Float2& screenPos)
|
||||
{
|
||||
return Rectangle(Float2::Zero, Platform::GetDesktopSize());
|
||||
}
|
||||
|
||||
Rectangle PlatformBase::GetVirtualDesktopBounds()
|
||||
{
|
||||
return Rectangle(Float2::Zero, Platform::GetDesktopSize());
|
||||
}
|
||||
|
||||
Float2 PlatformBase::GetVirtualDesktopSize()
|
||||
{
|
||||
return Platform::GetVirtualDesktopBounds().Size;
|
||||
@@ -616,6 +626,8 @@ const Char* ToString(PlatformType type)
|
||||
return TEXT("PlayStation 5");
|
||||
case PlatformType::Mac:
|
||||
return TEXT("Mac");
|
||||
case PlatformType::iOS:
|
||||
return TEXT("iOS");
|
||||
default:
|
||||
return TEXT("");
|
||||
}
|
||||
|
||||
@@ -665,7 +665,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="screenPos">The screen position (in pixels).</param>
|
||||
/// <returns>The monitor bounds.</returns>
|
||||
API_FUNCTION() static Rectangle GetMonitorBounds(const Float2& screenPos) = delete;
|
||||
API_FUNCTION() static Rectangle GetMonitorBounds(const Float2& screenPos);
|
||||
|
||||
/// <summary>
|
||||
/// Gets size of the primary desktop.
|
||||
@@ -677,7 +677,7 @@ public:
|
||||
/// Gets virtual bounds of the desktop made of all the monitors outputs attached.
|
||||
/// </summary>
|
||||
/// <returns>Whole desktop size.</returns>
|
||||
API_PROPERTY() static Rectangle GetVirtualDesktopBounds() = delete;
|
||||
API_PROPERTY() static Rectangle GetVirtualDesktopBounds();
|
||||
|
||||
/// <summary>
|
||||
/// Gets virtual size of the desktop made of all the monitors outputs attached.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#if PLATFORM_WINDOWS || PLATFORM_UWP || PLATFORM_XBOX_ONE || PLATFORM_XBOX_SCARLETT
|
||||
#include "Win32/Win32ConditionVariable.h"
|
||||
#elif PLATFORM_LINUX || PLATFORM_ANDROID || PLATFORM_PS4 || PLATFORM_PS5 || PLATFORM_MAC
|
||||
#elif PLATFORM_LINUX || PLATFORM_ANDROID || PLATFORM_PS4 || PLATFORM_PS5 || PLATFORM_MAC || PLATFORM_IOS
|
||||
#include "Unix/UnixConditionVariable.h"
|
||||
#elif PLATFORM_SWITCH
|
||||
#include "Platforms/Switch/Engine/Platform/SwitchConditionVariable.h"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#if PLATFORM_WINDOWS || PLATFORM_UWP || PLATFORM_XBOX_ONE || PLATFORM_XBOX_SCARLETT
|
||||
#include "Win32/Win32CriticalSection.h"
|
||||
#elif PLATFORM_LINUX || PLATFORM_ANDROID || PLATFORM_PS4 || PLATFORM_PS5 || PLATFORM_MAC
|
||||
#elif PLATFORM_LINUX || PLATFORM_ANDROID || PLATFORM_PS4 || PLATFORM_PS5 || PLATFORM_MAC || PLATFORM_IOS
|
||||
#include "Unix/UnixCriticalSection.h"
|
||||
#elif PLATFORM_SWITCH
|
||||
#include "Platforms/Switch/Engine/Platform/SwitchCriticalSection.h"
|
||||
|
||||
@@ -58,6 +58,11 @@ API_ENUM() enum class PlatformType
|
||||
/// Running on Mac.
|
||||
/// </summary>
|
||||
Mac = 10,
|
||||
|
||||
/// <summary>
|
||||
/// Running on iPhone.
|
||||
/// </summary>
|
||||
iOS = 11,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -152,6 +157,8 @@ API_ENUM() enum class ArchitectureType
|
||||
#include "Platforms/Switch/Engine/Platform/SwitchDefines.h"
|
||||
#elif PLATFORM_MAC
|
||||
#include "Mac/MacDefines.h"
|
||||
#elif PLATFORM_IOS
|
||||
#include "iOS/iOSDefines.h"
|
||||
#else
|
||||
#error Missing Defines implementation!
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#if PLATFORM_WINDOWS || PLATFORM_UWP || PLATFORM_XBOX_ONE || PLATFORM_XBOX_SCARLETT
|
||||
#include "Win32/Win32File.h"
|
||||
#elif PLATFORM_LINUX || PLATFORM_PS4 || PLATFORM_PS5 || PLATFORM_MAC
|
||||
#elif PLATFORM_LINUX || PLATFORM_PS4 || PLATFORM_PS5 || PLATFORM_MAC || PLATFORM_IOS
|
||||
#include "Unix/UnixFile.h"
|
||||
#elif PLATFORM_ANDROID
|
||||
#include "Android/AndroidFile.h"
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "Platforms/Switch/Engine/Platform/SwitchFileSystem.h"
|
||||
#elif PLATFORM_MAC
|
||||
#include "Mac/MacFileSystem.h"
|
||||
#elif PLATFORM_IOS
|
||||
#include "Apple/AppleFileSystem.h"
|
||||
#else
|
||||
#error Missing File System implementation!
|
||||
#endif
|
||||
|
||||
@@ -555,21 +555,11 @@ struct GetMonitorBoundsData
|
||||
}
|
||||
};
|
||||
|
||||
Rectangle GDKPlatform::GetMonitorBounds(const Float2& screenPos)
|
||||
{
|
||||
return Rectangle(Float2::Zero, GetDesktopSize());
|
||||
}
|
||||
|
||||
Float2 GDKPlatform::GetDesktopSize()
|
||||
{
|
||||
return Float2(1920, 1080);
|
||||
}
|
||||
|
||||
Rectangle GDKPlatform::GetVirtualDesktopBounds()
|
||||
{
|
||||
return Rectangle(Float2::Zero, GetDesktopSize());
|
||||
}
|
||||
|
||||
void GDKPlatform::GetEnvironmentVariables(Dictionary<String, String>& result)
|
||||
{
|
||||
const LPWCH environmentStr = GetEnvironmentStringsW();
|
||||
|
||||
@@ -68,9 +68,7 @@ public:
|
||||
static bool GetHasFocus();
|
||||
static bool CanOpenUrl(const StringView& url);
|
||||
static void OpenUrl(const StringView& url);
|
||||
static Rectangle GetMonitorBounds(const Float2& screenPos);
|
||||
static Float2 GetDesktopSize();
|
||||
static Rectangle GetVirtualDesktopBounds();
|
||||
static void GetEnvironmentVariables(Dictionary<String, String, HeapAllocation>& result);
|
||||
static bool GetEnvironmentVariable(const String& name, String& value);
|
||||
static bool SetEnvironmentVariable(const String& name, const String& value);
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
#if PLATFORM_MAC
|
||||
|
||||
#include "MacFileSystem.h"
|
||||
#include "MacUtils.h"
|
||||
#include "Engine/Platform/Apple/AppleUtils.h"
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Types/StringView.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
@@ -22,13 +23,11 @@
|
||||
#include <fcntl.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
const DateTime UnixEpoch(1970, 1, 1);
|
||||
|
||||
void InitMacDialog(NSSavePanel* dialog, const StringView& initialDirectory, const StringView& filter, const StringView& title)
|
||||
{
|
||||
if (initialDirectory.HasChars())
|
||||
{
|
||||
[dialog setDirectoryURL:[NSURL fileURLWithPath:(NSString*)MacUtils::ToString(initialDirectory) isDirectory:YES]];
|
||||
[dialog setDirectoryURL:[NSURL fileURLWithPath:(NSString*)AppleUtils::ToString(initialDirectory) isDirectory:YES]];
|
||||
}
|
||||
if (filter.HasChars())
|
||||
{
|
||||
@@ -41,13 +40,13 @@ void InitMacDialog(NSSavePanel* dialog, const StringView& initialDirectory, cons
|
||||
String extension = entries[i];
|
||||
if (extension.StartsWith(TEXT("*.")))
|
||||
extension = extension.Substring(2);
|
||||
[fileTypes addObject:(NSString*)MacUtils::ToString(extension)];
|
||||
[fileTypes addObject:(NSString*)AppleUtils::ToString(extension)];
|
||||
}
|
||||
[dialog setAllowedFileTypes:fileTypes];*/
|
||||
}
|
||||
if (title.HasChars())
|
||||
{
|
||||
[dialog setMessage:(NSString*)MacUtils::ToString(title)];
|
||||
[dialog setMessage:(NSString*)AppleUtils::ToString(title)];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,12 +68,12 @@ bool MacFileSystem::ShowOpenFileDialog(Window* parentWindow, const StringView& i
|
||||
{
|
||||
const NSArray* urls = [dialog URLs];
|
||||
for (int32 i = 0; i < [urls count]; i++)
|
||||
filenames.Add(MacUtils::ToString((CFStringRef)[[urls objectAtIndex:i] path]));
|
||||
filenames.Add(AppleUtils::ToString((CFStringRef)[[urls objectAtIndex:i] path]));
|
||||
}
|
||||
else
|
||||
{
|
||||
const NSURL* url = [dialog URL];
|
||||
filenames.Add(MacUtils::ToString((CFStringRef)[url path]));
|
||||
filenames.Add(AppleUtils::ToString((CFStringRef)[url path]));
|
||||
}
|
||||
result = false;
|
||||
}
|
||||
@@ -97,7 +96,7 @@ bool MacFileSystem::ShowSaveFileDialog(Window* parentWindow, const StringView& i
|
||||
if ([dialog runModal] == NSModalResponseOK)
|
||||
{
|
||||
const NSURL* url = [dialog URL];
|
||||
filenames.Add(MacUtils::ToString((CFStringRef)[url path]));
|
||||
filenames.Add(AppleUtils::ToString((CFStringRef)[url path]));
|
||||
result = false;
|
||||
}
|
||||
|
||||
@@ -122,7 +121,7 @@ bool MacFileSystem::ShowBrowseFolderDialog(Window* parentWindow, const StringVie
|
||||
if ([dialog runModal] == NSModalResponseOK)
|
||||
{
|
||||
const NSURL* url = [dialog URL];
|
||||
path = MacUtils::ToString((CFStringRef)[url path]);
|
||||
path = AppleUtils::ToString((CFStringRef)[url path]);
|
||||
result = false;
|
||||
}
|
||||
|
||||
@@ -136,510 +135,4 @@ bool MacFileSystem::ShowFileExplorer(const StringView& path)
|
||||
return Platform::StartProcess(TEXT("open"), String::Format(TEXT("\"{0}\""), path), StringView::Empty) != 0;
|
||||
}
|
||||
|
||||
bool MacFileSystem::CreateDirectory(const StringView& path)
|
||||
{
|
||||
const StringAsANSI<> pathAnsi(*path, path.Length());
|
||||
|
||||
// Skip if already exists
|
||||
struct stat fileInfo;
|
||||
if (stat(pathAnsi.Get(), &fileInfo) != -1 && S_ISDIR(fileInfo.st_mode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Recursively do it all again for the parent directory, if any
|
||||
const int32 slashIndex = path.FindLast('/');
|
||||
if (slashIndex > 1)
|
||||
{
|
||||
if (CreateDirectory(path.Substring(0, slashIndex)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the last directory on the path (the recursive calls will have taken care of the parent directories by now)
|
||||
return mkdir(pathAnsi.Get(), 0755) != 0 && errno != EEXIST;
|
||||
}
|
||||
|
||||
bool DeletePathTree(const char* path)
|
||||
{
|
||||
size_t pathLength;
|
||||
DIR* dir;
|
||||
struct stat statPath, statEntry;
|
||||
struct dirent* entry;
|
||||
|
||||
// Stat for the path
|
||||
stat(path, &statPath);
|
||||
|
||||
// If path does not exists or is not dir - exit with status -1
|
||||
if (S_ISDIR(statPath.st_mode) == 0)
|
||||
{
|
||||
// Is not directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not possible to read the directory for this user
|
||||
if ((dir = opendir(path)) == NULL)
|
||||
{
|
||||
// Cannot open directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// The length of the path
|
||||
pathLength = strlen(path);
|
||||
|
||||
// Iteration through entries in the directory
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
// Skip entries "." and ".."
|
||||
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
// Determinate a full path of an entry
|
||||
char full_path[256];
|
||||
ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path));
|
||||
strcpy(full_path, path);
|
||||
strcat(full_path, "/");
|
||||
strcat(full_path, entry->d_name);
|
||||
|
||||
// Stat for the entry
|
||||
stat(full_path, &statEntry);
|
||||
|
||||
// Recursively remove a nested directory
|
||||
if (S_ISDIR(statEntry.st_mode) != 0)
|
||||
{
|
||||
if (DeletePathTree(full_path))
|
||||
return true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Remove a file object
|
||||
if (unlink(full_path) != 0)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove the devastated directory and close the object of it
|
||||
if (rmdir(path) != 0)
|
||||
return true;
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacFileSystem::DeleteDirectory(const String& path, bool deleteContents)
|
||||
{
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (deleteContents)
|
||||
return DeletePathTree(pathANSI.Get());
|
||||
return rmdir(pathANSI.Get()) != 0;
|
||||
}
|
||||
|
||||
bool MacFileSystem::DirectoryExists(const StringView& path)
|
||||
{
|
||||
struct stat fileInfo;
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (stat(pathANSI.Get(), &fileInfo) != -1)
|
||||
{
|
||||
return S_ISDIR(fileInfo.st_mode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacFileSystem::DirectoryGetFiles(Array<String>& results, const String& path, const Char* searchPattern, DirectorySearchOption option)
|
||||
{
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
const StringAsANSI<> searchPatternANSI(searchPattern);
|
||||
|
||||
// Check if use only top directory
|
||||
if (option == DirectorySearchOption::TopDirectoryOnly)
|
||||
return getFilesFromDirectoryTop(results, pathANSI.Get(), searchPatternANSI.Get());
|
||||
return getFilesFromDirectoryAll(results, pathANSI.Get(), searchPatternANSI.Get());
|
||||
}
|
||||
|
||||
bool MacFileSystem::GetChildDirectories(Array<String>& results, const String& directory)
|
||||
{
|
||||
size_t pathLength;
|
||||
DIR* dir;
|
||||
struct stat statPath, statEntry;
|
||||
struct dirent* entry;
|
||||
const StringAsANSI<> pathANSI(*directory, directory.Length());
|
||||
const char* path = pathANSI.Get();
|
||||
|
||||
// Stat for the path
|
||||
stat(path, &statPath);
|
||||
|
||||
// If path does not exists or is not dir - exit with status -1
|
||||
if (S_ISDIR(statPath.st_mode) == 0)
|
||||
{
|
||||
// Is not directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not possible to read the directory for this user
|
||||
if ((dir = opendir(path)) == NULL)
|
||||
{
|
||||
// Cannot open directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// The length of the path
|
||||
pathLength = strlen(path);
|
||||
|
||||
// Iteration through entries in the directory
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
// Skip entries "." and ".."
|
||||
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
// Determinate a full path of an entry
|
||||
char full_path[256];
|
||||
ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path));
|
||||
strcpy(full_path, path);
|
||||
strcat(full_path, "/");
|
||||
strcat(full_path, entry->d_name);
|
||||
|
||||
// Stat for the entry
|
||||
stat(full_path, &statEntry);
|
||||
|
||||
// Check for directory
|
||||
if (S_ISDIR(statEntry.st_mode) != 0)
|
||||
{
|
||||
// Add directory
|
||||
results.Add(String(full_path));
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacFileSystem::FileExists(const StringView& path)
|
||||
{
|
||||
struct stat fileInfo;
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (stat(pathANSI.Get(), &fileInfo) != -1)
|
||||
{
|
||||
return S_ISREG(fileInfo.st_mode);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacFileSystem::DeleteFile(const StringView& path)
|
||||
{
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
return unlink(pathANSI.Get()) == 0;
|
||||
}
|
||||
|
||||
uint64 MacFileSystem::GetFileSize(const StringView& path)
|
||||
{
|
||||
struct stat fileInfo;
|
||||
fileInfo.st_size = -1;
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (stat(pathANSI.Get(), &fileInfo) != -1)
|
||||
{
|
||||
// Check for directories
|
||||
if (S_ISDIR(fileInfo.st_mode))
|
||||
{
|
||||
fileInfo.st_size = -1;
|
||||
}
|
||||
}
|
||||
return fileInfo.st_size;
|
||||
}
|
||||
|
||||
bool MacFileSystem::IsReadOnly(const StringView& path)
|
||||
{
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (access(pathANSI.Get(), W_OK) == -1)
|
||||
{
|
||||
return errno == EACCES;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacFileSystem::SetReadOnly(const StringView& path, bool isReadOnly)
|
||||
{
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
struct stat fileInfo;
|
||||
if (stat(pathANSI.Get(), &fileInfo) != -1)
|
||||
{
|
||||
if (isReadOnly)
|
||||
{
|
||||
fileInfo.st_mode &= ~S_IWUSR;
|
||||
}
|
||||
else
|
||||
{
|
||||
fileInfo.st_mode |= S_IWUSR;
|
||||
}
|
||||
return chmod(pathANSI.Get(), fileInfo.st_mode) == 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacFileSystem::MoveFile(const StringView& dst, const StringView& src, bool overwrite)
|
||||
{
|
||||
if (!overwrite && FileExists(dst))
|
||||
{
|
||||
// Already exists
|
||||
return true;
|
||||
}
|
||||
|
||||
if (overwrite)
|
||||
{
|
||||
unlink(StringAsANSI<>(*dst, dst.Length()).Get());
|
||||
}
|
||||
if (rename(StringAsANSI<>(*src, src.Length()).Get(), StringAsANSI<>(*dst, dst.Length()).Get()) != 0)
|
||||
{
|
||||
if (errno == EXDEV)
|
||||
{
|
||||
if (!CopyFile(dst, src))
|
||||
{
|
||||
unlink(StringAsANSI<>(*src, src.Length()).Get());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacFileSystem::CopyFile(const StringView& dst, const StringView& src)
|
||||
{
|
||||
const StringAsANSI<> srcANSI(*src, src.Length());
|
||||
const StringAsANSI<> dstANSI(*dst, dst.Length());
|
||||
|
||||
int srcFile, dstFile;
|
||||
char buffer[4096];
|
||||
ssize_t readSize;
|
||||
int cachedError;
|
||||
|
||||
srcFile = open(srcANSI.Get(), O_RDONLY);
|
||||
if (srcFile < 0)
|
||||
return true;
|
||||
dstFile = open(dstANSI.Get(), O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
|
||||
if (dstFile < 0)
|
||||
goto out_error;
|
||||
|
||||
while (readSize = read(srcFile, buffer, sizeof(buffer)), readSize > 0)
|
||||
{
|
||||
char* ptr = buffer;
|
||||
ssize_t writeSize;
|
||||
|
||||
do
|
||||
{
|
||||
writeSize = write(dstFile, ptr, readSize);
|
||||
if (writeSize >= 0)
|
||||
{
|
||||
readSize -= writeSize;
|
||||
ptr += writeSize;
|
||||
}
|
||||
else if (errno != EINTR)
|
||||
{
|
||||
goto out_error;
|
||||
}
|
||||
} while (readSize > 0);
|
||||
}
|
||||
|
||||
if (readSize == 0)
|
||||
{
|
||||
if (close(dstFile) < 0)
|
||||
{
|
||||
dstFile = -1;
|
||||
goto out_error;
|
||||
}
|
||||
close(srcFile);
|
||||
|
||||
// Success
|
||||
return false;
|
||||
}
|
||||
|
||||
out_error:
|
||||
cachedError = errno;
|
||||
close(srcFile);
|
||||
if (dstFile >= 0)
|
||||
close(dstFile);
|
||||
errno = cachedError;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacFileSystem::getFilesFromDirectoryTop(Array<String>& results, const char* path, const char* searchPattern)
|
||||
{
|
||||
size_t pathLength;
|
||||
struct stat statPath, statEntry;
|
||||
struct dirent* entry;
|
||||
|
||||
// Stat for the path
|
||||
stat(path, &statPath);
|
||||
|
||||
// If path does not exists or is not dir - exit with status -1
|
||||
if (S_ISDIR(statPath.st_mode) == 0)
|
||||
{
|
||||
// Is not directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not possible to read the directory for this user
|
||||
DIR* dir = opendir(path);
|
||||
if (dir == NULL)
|
||||
{
|
||||
// Cannot open directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// The length of the path
|
||||
pathLength = strlen(path);
|
||||
|
||||
// Iteration through entries in the directory
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
// Skip entries "." and ".."
|
||||
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
// Determinate a full path of an entry
|
||||
char fullPath[256];
|
||||
ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(fullPath));
|
||||
strcpy(fullPath, path);
|
||||
strcat(fullPath, "/");
|
||||
strcat(fullPath, entry->d_name);
|
||||
|
||||
// Stat for the entry
|
||||
stat(fullPath, &statEntry);
|
||||
|
||||
// Check for file
|
||||
if (S_ISREG(statEntry.st_mode) != 0)
|
||||
{
|
||||
// Validate with filter
|
||||
const int32 fullPathLength = StringUtils::Length(fullPath);
|
||||
const int32 searchPatternLength = StringUtils::Length(searchPattern);
|
||||
if (searchPatternLength == 0 || StringUtils::Compare(searchPattern, "*") == 0)
|
||||
{
|
||||
// All files
|
||||
}
|
||||
else if (searchPattern[0] == '*' && searchPatternLength < fullPathLength && StringUtils::Compare(fullPath + fullPathLength - searchPatternLength + 1, searchPattern + 1, searchPatternLength - 1) == 0)
|
||||
{
|
||||
// Path ending
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: implement all cases in a generic way
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add file
|
||||
results.Add(String(fullPath));
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MacFileSystem::getFilesFromDirectoryAll(Array<String>& results, const char* path, const char* searchPattern)
|
||||
{
|
||||
// Find all files in this directory
|
||||
getFilesFromDirectoryTop(results, path, searchPattern);
|
||||
|
||||
size_t pathLength;
|
||||
DIR* dir;
|
||||
struct stat statPath, statEntry;
|
||||
struct dirent* entry;
|
||||
|
||||
// Stat for the path
|
||||
stat(path, &statPath);
|
||||
|
||||
// If path does not exists or is not dir - exit with status -1
|
||||
if (S_ISDIR(statPath.st_mode) == 0)
|
||||
{
|
||||
// Is not directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// If not possible to read the directory for this user
|
||||
if ((dir = opendir(path)) == NULL)
|
||||
{
|
||||
// Cannot open directory
|
||||
return true;
|
||||
}
|
||||
|
||||
// The length of the path
|
||||
pathLength = strlen(path);
|
||||
|
||||
// Iteration through entries in the directory
|
||||
while ((entry = readdir(dir)) != NULL)
|
||||
{
|
||||
// Skip entries "." and ".."
|
||||
if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
|
||||
continue;
|
||||
|
||||
// Determinate a full path of an entry
|
||||
char full_path[256];
|
||||
ASSERT(pathLength + strlen(entry->d_name) < ARRAY_COUNT(full_path));
|
||||
strcpy(full_path, path);
|
||||
strcat(full_path, "/");
|
||||
strcat(full_path, entry->d_name);
|
||||
|
||||
// Stat for the entry
|
||||
stat(full_path, &statEntry);
|
||||
|
||||
// Check for directory
|
||||
if (S_ISDIR(statEntry.st_mode) != 0)
|
||||
{
|
||||
if (getFilesFromDirectoryAll(results, full_path, searchPattern))
|
||||
{
|
||||
closedir(dir);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
DateTime MacFileSystem::GetFileLastEditTime(const StringView& path)
|
||||
{
|
||||
struct stat fileInfo;
|
||||
const StringAsANSI<> pathANSI(*path, path.Length());
|
||||
if (stat(pathANSI.Get(), &fileInfo) == -1)
|
||||
{
|
||||
return DateTime::MinValue();
|
||||
}
|
||||
|
||||
const TimeSpan timeSinceEpoch(0, 0, fileInfo.st_mtime);
|
||||
return UnixEpoch + timeSinceEpoch;
|
||||
}
|
||||
|
||||
void MacFileSystem::GetSpecialFolderPath(const SpecialFolder type, String& result)
|
||||
{
|
||||
String home;
|
||||
Platform::GetEnvironmentVariable(TEXT("HOME"), home);
|
||||
switch (type)
|
||||
{
|
||||
case SpecialFolder::Desktop:
|
||||
result = home / TEXT("/Desktop");
|
||||
break;
|
||||
case SpecialFolder::Documents:
|
||||
result = home / TEXT("/Documents");
|
||||
break;
|
||||
case SpecialFolder::Pictures:
|
||||
result = home / TEXT("/Pictures");
|
||||
break;
|
||||
case SpecialFolder::AppData:
|
||||
case SpecialFolder::LocalAppData:
|
||||
result = home / TEXT("/Library/Caches");
|
||||
break;
|
||||
case SpecialFolder::ProgramData:
|
||||
result = home / TEXT("/Library/Application Support");
|
||||
break;
|
||||
case SpecialFolder::Temporary:
|
||||
Platform::GetEnvironmentVariable(TEXT("TMPDIR"), result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,53 +4,20 @@
|
||||
|
||||
#if PLATFORM_MAC
|
||||
|
||||
#include "Engine/Platform/Base/FileSystemBase.h"
|
||||
#include "../Apple/AppleFileSystem.h"
|
||||
|
||||
/// <summary>
|
||||
/// Mac platform implementation of filesystem service.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API MacFileSystem : public FileSystemBase
|
||||
class FLAXENGINE_API MacFileSystem : public AppleFileSystem
|
||||
{
|
||||
public:
|
||||
|
||||
// [FileSystemBase]
|
||||
// [AppleFileSystem]
|
||||
static bool ShowOpenFileDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& filter, bool multiSelect, const StringView& title, Array<String, HeapAllocation>& filenames);
|
||||
static bool ShowSaveFileDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& filter, bool multiSelect, const StringView& title, Array<String, HeapAllocation>& filenames);
|
||||
static bool ShowBrowseFolderDialog(Window* parentWindow, const StringView& initialDirectory, const StringView& title, String& path);
|
||||
static bool ShowFileExplorer(const StringView& path);
|
||||
static bool CreateDirectory(const StringView& path);
|
||||
static bool DeleteDirectory(const String& path, bool deleteContents = true);
|
||||
static bool DirectoryExists(const StringView& path);
|
||||
static bool DirectoryGetFiles(Array<String, HeapAllocation>& results, const String& path, const Char* searchPattern, DirectorySearchOption option = DirectorySearchOption::AllDirectories);
|
||||
static bool GetChildDirectories(Array<String, HeapAllocation>& results, const String& directory);
|
||||
static bool FileExists(const StringView& path);
|
||||
static bool DeleteFile(const StringView& path);
|
||||
static uint64 GetFileSize(const StringView& path);
|
||||
static bool IsReadOnly(const StringView& path);
|
||||
static bool SetReadOnly(const StringView& path, bool isReadOnly);
|
||||
static bool MoveFile(const StringView& dst, const StringView& src, bool overwrite = false);
|
||||
static bool CopyFile(const StringView& dst, const StringView& src);
|
||||
|
||||
public:
|
||||
|
||||
/// <summary>
|
||||
/// Gets last time when file has been modified (in UTC).
|
||||
/// </summary>
|
||||
/// <param name="path">The file path to check.</param>
|
||||
/// <returns>The last write time or DateTime::MinValue() if cannot get data.</returns>
|
||||
static DateTime GetFileLastEditTime(const StringView& path);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the special folder path.
|
||||
/// </summary>
|
||||
/// <param name="type">The folder type.</param>
|
||||
/// <param name="result">The result full path.</param>
|
||||
static void GetSpecialFolderPath(const SpecialFolder type, String& result);
|
||||
|
||||
private:
|
||||
|
||||
static bool getFilesFromDirectoryTop(Array<String, HeapAllocation>& results, const char* path, const char* searchPattern);
|
||||
static bool getFilesFromDirectoryAll(Array<String, HeapAllocation>& results, const char* path, const char* searchPattern);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "MacPlatform.h"
|
||||
#include "MacWindow.h"
|
||||
#include "MacUtils.h"
|
||||
#include "Engine/Platform/Apple/AppleUtils.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/Guid.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
@@ -17,8 +17,8 @@
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Platform/CPUInfo.h"
|
||||
#include "Engine/Platform/MemoryStats.h"
|
||||
#include "Engine/Platform/StringUtils.h"
|
||||
#include "Engine/Platform/MessageBox.h"
|
||||
#include "Engine/Platform/StringUtils.h"
|
||||
#include "Engine/Platform/WindowsManager.h"
|
||||
#include "Engine/Platform/Clipboard.h"
|
||||
#include "Engine/Platform/IGuiData.h"
|
||||
@@ -48,117 +48,16 @@
|
||||
#include <execinfo.h>
|
||||
#endif
|
||||
|
||||
CPUInfo MacCpu;
|
||||
Guid DeviceId;
|
||||
String UserLocale, ComputerName;
|
||||
double SecondsPerCycle;
|
||||
String ComputerName;
|
||||
NSAutoreleasePool* AutoreleasePool = nullptr;
|
||||
|
||||
float MacPlatform::ScreenScale = 1.0f;
|
||||
|
||||
String MacUtils::ToString(CFStringRef str)
|
||||
{
|
||||
if (!str)
|
||||
return String::Empty;
|
||||
String result;
|
||||
const int32 length = CFStringGetLength(str);
|
||||
if (length > 0)
|
||||
{
|
||||
CFRange range = CFRangeMake(0, length);
|
||||
result.ReserveSpace(length);
|
||||
CFStringGetBytes(str, range, kCFStringEncodingUTF16LE, '?', false, (uint8*)result.Get(), length * sizeof(Char), nullptr);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
CFStringRef MacUtils::ToString(const StringView& str)
|
||||
{
|
||||
return CFStringCreateWithBytes(nullptr, (const UInt8*)str.GetText(), str.Length() * sizeof(Char), kCFStringEncodingUTF16LE, false);
|
||||
}
|
||||
|
||||
Float2 MacUtils::PosToCoca(const Float2& pos)
|
||||
{
|
||||
// MacOS uses y-coordinate starting at the bottom of the screen
|
||||
Float2 result = pos;// / MacPlatform::ScreenScale;
|
||||
result.Y *= -1;
|
||||
result += GetScreensOrigin();
|
||||
return result;
|
||||
}
|
||||
|
||||
Float2 MacUtils::CocaToPos(const Float2& pos)
|
||||
{
|
||||
// MacOS uses y-coordinate starting at the bottom of the screen
|
||||
Float2 result = pos;// * MacPlatform::ScreenScale;
|
||||
result -= GetScreensOrigin();
|
||||
result.Y *= -1;
|
||||
return result;// * MacPlatform::ScreenScale;
|
||||
}
|
||||
|
||||
Float2 MacUtils::GetScreensOrigin()
|
||||
{
|
||||
Float2 result = Float2::Zero;
|
||||
NSArray* screenArray = [NSScreen screens];
|
||||
for (NSUInteger i = 0; i < [screenArray count]; i++)
|
||||
{
|
||||
NSRect rect = [[screenArray objectAtIndex:i] frame];
|
||||
Float2 pos(rect.origin.x, rect.origin.y + rect.size.height);
|
||||
pos *= MacPlatform::ScreenScale;
|
||||
if (pos.X < result.X)
|
||||
result.X = pos.X;
|
||||
if (pos.Y > result.Y)
|
||||
result.Y = pos.Y;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MacClipboard::Clear()
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
[pasteboard clearContents];
|
||||
}
|
||||
|
||||
void MacClipboard::SetText(const StringView& text)
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
[pasteboard clearContents];
|
||||
[pasteboard writeObjects:[NSArray arrayWithObject:(NSString*)MacUtils::ToString(text)]];
|
||||
}
|
||||
|
||||
void MacClipboard::SetRawData(const Span<byte>& data)
|
||||
{
|
||||
}
|
||||
|
||||
void MacClipboard::SetFiles(const Array<String>& files)
|
||||
{
|
||||
}
|
||||
|
||||
String MacClipboard::GetText()
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
NSArray* classes = [NSArray arrayWithObject:[NSString class]];
|
||||
NSDictionary* options = [NSDictionary dictionary];
|
||||
if (![pasteboard canReadObjectForClasses:classes options:options])
|
||||
return String::Empty;
|
||||
NSArray* objects = [pasteboard readObjectsForClasses:classes options:options];
|
||||
return MacUtils::ToString((CFStringRef)[objects objectAtIndex:0]);
|
||||
}
|
||||
|
||||
Array<byte> MacClipboard::GetRawData()
|
||||
{
|
||||
return Array<byte>();
|
||||
}
|
||||
|
||||
Array<String> MacClipboard::GetFiles()
|
||||
{
|
||||
return Array<String>();
|
||||
}
|
||||
|
||||
DialogResult MessageBox::Show(Window* parent, const StringView& text, const StringView& caption, MessageBoxButtons buttons, MessageBoxIcon icon)
|
||||
{
|
||||
if (CommandLine::Options.Headless)
|
||||
return DialogResult::None;
|
||||
CFStringRef textRef = MacUtils::ToString(text);
|
||||
CFStringRef captionRef = MacUtils::ToString(caption);
|
||||
CFStringRef textRef = AppleUtils::ToString(text);
|
||||
CFStringRef captionRef = AppleUtils::ToString(caption);
|
||||
CFOptionFlags flags = 0;
|
||||
switch (buttons)
|
||||
{
|
||||
@@ -189,6 +88,83 @@ DialogResult MessageBox::Show(Window* parent, const StringView& text, const Stri
|
||||
return DialogResult::OK;
|
||||
}
|
||||
|
||||
Float2 AppleUtils::PosToCoca(const Float2& pos)
|
||||
{
|
||||
// MacOS uses y-coordinate starting at the bottom of the screen
|
||||
Float2 result = pos;// / ApplePlatform::ScreenScale;
|
||||
result.Y *= -1;
|
||||
result += GetScreensOrigin();
|
||||
return result;
|
||||
}
|
||||
|
||||
Float2 AppleUtils::CocaToPos(const Float2& pos)
|
||||
{
|
||||
// MacOS uses y-coordinate starting at the bottom of the screen
|
||||
Float2 result = pos;// * ApplePlatform::ScreenScale;
|
||||
result -= GetScreensOrigin();
|
||||
result.Y *= -1;
|
||||
return result;// * ApplePlatform::ScreenScale;
|
||||
}
|
||||
|
||||
Float2 AppleUtils::GetScreensOrigin()
|
||||
{
|
||||
Float2 result = Float2::Zero;
|
||||
NSArray* screenArray = [NSScreen screens];
|
||||
for (NSUInteger i = 0; i < [screenArray count]; i++)
|
||||
{
|
||||
NSRect rect = [[screenArray objectAtIndex:i] frame];
|
||||
Float2 pos(rect.origin.x, rect.origin.y + rect.size.height);
|
||||
pos *= ApplePlatform::ScreenScale;
|
||||
if (pos.X < result.X)
|
||||
result.X = pos.X;
|
||||
if (pos.Y > result.Y)
|
||||
result.Y = pos.Y;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MacClipboard::Clear()
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
[pasteboard clearContents];
|
||||
}
|
||||
|
||||
void MacClipboard::SetText(const StringView& text)
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
[pasteboard clearContents];
|
||||
[pasteboard writeObjects:[NSArray arrayWithObject:(NSString*)AppleUtils::ToString(text)]];
|
||||
}
|
||||
|
||||
void MacClipboard::SetRawData(const Span<byte>& data)
|
||||
{
|
||||
}
|
||||
|
||||
void MacClipboard::SetFiles(const Array<String>& files)
|
||||
{
|
||||
}
|
||||
|
||||
String MacClipboard::GetText()
|
||||
{
|
||||
NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
|
||||
NSArray* classes = [NSArray arrayWithObject:[NSString class]];
|
||||
NSDictionary* options = [NSDictionary dictionary];
|
||||
if (![pasteboard canReadObjectForClasses:classes options:options])
|
||||
return String::Empty;
|
||||
NSArray* objects = [pasteboard readObjectsForClasses:classes options:options];
|
||||
return AppleUtils::ToString((CFStringRef)[objects objectAtIndex:0]);
|
||||
}
|
||||
|
||||
Array<byte> MacClipboard::GetRawData()
|
||||
{
|
||||
return Array<byte>();
|
||||
}
|
||||
|
||||
Array<String> MacClipboard::GetFiles()
|
||||
{
|
||||
return Array<String>();
|
||||
}
|
||||
|
||||
class MacKeyboard : public Keyboard
|
||||
{
|
||||
public:
|
||||
@@ -217,215 +193,28 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
typedef uint16_t offset_t;
|
||||
#define align_mem_up(num, align) (((num) + ((align) - 1)) & ~((align) - 1))
|
||||
|
||||
bool MacPlatform::Is64BitPlatform()
|
||||
{
|
||||
return PLATFORM_64BITS;
|
||||
}
|
||||
|
||||
CPUInfo MacPlatform::GetCPUInfo()
|
||||
{
|
||||
return MacCpu;
|
||||
}
|
||||
|
||||
int32 MacPlatform::GetCacheLineSize()
|
||||
{
|
||||
return MacCpu.CacheLineSize;
|
||||
}
|
||||
|
||||
MemoryStats MacPlatform::GetMemoryStats()
|
||||
{
|
||||
MemoryStats result;
|
||||
int64 value64;
|
||||
size_t value64Size = sizeof(value64);
|
||||
if (sysctlbyname("hw.memsize", &value64, &value64Size, nullptr, 0) != 0)
|
||||
value64 = 1024 * 1024;
|
||||
result.TotalPhysicalMemory = value64;
|
||||
int id[] = { CTL_HW, HW_MEMSIZE };
|
||||
if (sysctl(id, 2, &value64, &value64Size, nullptr, 0) != 0)
|
||||
value64Size = 1024;
|
||||
result.UsedPhysicalMemory = value64Size;
|
||||
xsw_usage swapusage;
|
||||
size_t swapusageSize = sizeof(swapusage);
|
||||
result.TotalVirtualMemory = result.TotalPhysicalMemory;
|
||||
result.UsedVirtualMemory = result.UsedPhysicalMemory;
|
||||
if (sysctlbyname("vm.swapusage", &swapusage, &swapusageSize, nullptr, 0) == 0)
|
||||
{
|
||||
result.TotalVirtualMemory += swapusage.xsu_total;
|
||||
result.UsedVirtualMemory += swapusage.xsu_used;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ProcessMemoryStats MacPlatform::GetProcessMemoryStats()
|
||||
{
|
||||
ProcessMemoryStats result;
|
||||
result.UsedPhysicalMemory = 1024;
|
||||
result.UsedVirtualMemory = 1024;
|
||||
return result;
|
||||
}
|
||||
|
||||
uint64 MacPlatform::GetCurrentThreadID()
|
||||
{
|
||||
return (uint64)pthread_mach_thread_np(pthread_self());
|
||||
}
|
||||
|
||||
void MacPlatform::SetThreadPriority(ThreadPriority priority)
|
||||
{
|
||||
// TODO: impl this
|
||||
}
|
||||
|
||||
void MacPlatform::SetThreadAffinityMask(uint64 affinityMask)
|
||||
{
|
||||
// TODO: impl this
|
||||
}
|
||||
|
||||
void MacPlatform::Sleep(int32 milliseconds)
|
||||
{
|
||||
usleep(milliseconds * 1000);
|
||||
}
|
||||
|
||||
double MacPlatform::GetTimeSeconds()
|
||||
{
|
||||
return SecondsPerCycle * mach_absolute_time();
|
||||
}
|
||||
|
||||
uint64 MacPlatform::GetTimeCycles()
|
||||
{
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
uint64 MacPlatform::GetClockFrequency()
|
||||
{
|
||||
return (uint64)(1.0 / SecondsPerCycle);
|
||||
}
|
||||
|
||||
void MacPlatform::GetSystemTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond)
|
||||
{
|
||||
// Query for calendar time
|
||||
struct timeval time;
|
||||
gettimeofday(&time, nullptr);
|
||||
|
||||
// Convert to local time
|
||||
struct tm localTime;
|
||||
localtime_r(&time.tv_sec, &localTime);
|
||||
|
||||
// Extract time
|
||||
year = localTime.tm_year + 1900;
|
||||
month = localTime.tm_mon + 1;
|
||||
dayOfWeek = localTime.tm_wday;
|
||||
day = localTime.tm_mday;
|
||||
hour = localTime.tm_hour;
|
||||
minute = localTime.tm_min;
|
||||
second = localTime.tm_sec;
|
||||
millisecond = time.tv_usec / 1000;
|
||||
}
|
||||
|
||||
void MacPlatform::GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond)
|
||||
{
|
||||
// Get the calendar time
|
||||
struct timeval time;
|
||||
gettimeofday(&time, nullptr);
|
||||
|
||||
// Convert to UTC time
|
||||
struct tm localTime;
|
||||
gmtime_r(&time.tv_sec, &localTime);
|
||||
|
||||
// Extract time
|
||||
year = localTime.tm_year + 1900;
|
||||
month = localTime.tm_mon + 1;
|
||||
dayOfWeek = localTime.tm_wday;
|
||||
day = localTime.tm_mday;
|
||||
hour = localTime.tm_hour;
|
||||
minute = localTime.tm_min;
|
||||
second = localTime.tm_sec;
|
||||
millisecond = time.tv_usec / 1000;
|
||||
}
|
||||
|
||||
bool MacPlatform::Init()
|
||||
{
|
||||
if (UnixPlatform::Init())
|
||||
if (ApplePlatform::Init())
|
||||
return true;
|
||||
|
||||
// Init timing
|
||||
{
|
||||
mach_timebase_info_data_t info;
|
||||
mach_timebase_info(&info);
|
||||
SecondsPerCycle = 1e-9 * (double)info.numer / (double)info.denom;
|
||||
}
|
||||
|
||||
// Get CPU info
|
||||
int32 value32;
|
||||
int64 value64;
|
||||
size_t value32Size = sizeof(value32), value64Size = sizeof(value64);
|
||||
if (sysctlbyname("hw.packages", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 1;
|
||||
MacCpu.ProcessorPackageCount = value32;
|
||||
if (sysctlbyname("hw.physicalcpu", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 1;
|
||||
MacCpu.ProcessorCoreCount = value32;
|
||||
if (sysctlbyname("hw.logicalcpu", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 1;
|
||||
MacCpu.LogicalProcessorCount = value32;
|
||||
if (sysctlbyname("hw.l1icachesize", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 0;
|
||||
MacCpu.L1CacheSize = value32;
|
||||
if (sysctlbyname("hw.l2cachesize", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 0;
|
||||
MacCpu.L2CacheSize = value32;
|
||||
if (sysctlbyname("hw.l3cachesize", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = 0;
|
||||
MacCpu.L3CacheSize = value32;
|
||||
if (sysctlbyname("hw.pagesize", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = vm_page_size;
|
||||
MacCpu.PageSize = value32;
|
||||
if (sysctlbyname("hw.cpufrequency_max", &value64, &value64Size, nullptr, 0) != 0)
|
||||
value64 = GetClockFrequency();
|
||||
MacCpu.ClockSpeed = value64;
|
||||
if (sysctlbyname("hw.cachelinesize", &value32, &value32Size, nullptr, 0) != 0)
|
||||
value32 = PLATFORM_CACHE_LINE_SIZE;
|
||||
MacCpu.CacheLineSize = value32;
|
||||
|
||||
// Get device id
|
||||
{
|
||||
io_registry_entry_t ioRegistryRoot = IORegistryEntryFromPath(kIOMasterPortDefault, "IOService:/");
|
||||
CFStringRef deviceUuid = (CFStringRef)IORegistryEntryCreateCFProperty(ioRegistryRoot, CFSTR(kIOPlatformUUIDKey), kCFAllocatorDefault, 0);
|
||||
IOObjectRelease(ioRegistryRoot);
|
||||
String uuidStr = MacUtils::ToString(deviceUuid);
|
||||
String uuidStr = AppleUtils::ToString(deviceUuid);
|
||||
Guid::Parse(uuidStr, DeviceId);
|
||||
CFRelease(deviceUuid);
|
||||
}
|
||||
|
||||
// Get locale
|
||||
{
|
||||
CFLocaleRef locale = CFLocaleCopyCurrent();
|
||||
CFStringRef localeLang = (CFStringRef)CFLocaleGetValue(locale, kCFLocaleLanguageCode);
|
||||
CFStringRef localeCountry = (CFStringRef)CFLocaleGetValue(locale, kCFLocaleCountryCode);
|
||||
UserLocale = MacUtils::ToString(localeLang);
|
||||
String localeCountryStr = MacUtils::ToString(localeCountry);
|
||||
if (localeCountryStr.HasChars())
|
||||
UserLocale += TEXT("-") + localeCountryStr;
|
||||
CFRelease(locale);
|
||||
CFRelease(localeLang);
|
||||
CFRelease(localeCountry);
|
||||
}
|
||||
|
||||
// Get computer name
|
||||
{
|
||||
CFStringRef computerName = SCDynamicStoreCopyComputerName(nullptr, nullptr);
|
||||
ComputerName = MacUtils::ToString(computerName);
|
||||
ComputerName = AppleUtils::ToString(computerName);
|
||||
CFRelease(computerName);
|
||||
}
|
||||
|
||||
// Init user
|
||||
{
|
||||
String username;
|
||||
GetEnvironmentVariable(TEXT("USER"), username);
|
||||
OnPlatformUserAdd(New<User>(username));
|
||||
}
|
||||
|
||||
// Find the maximum scale of the display to handle high-dpi displays scaling factor
|
||||
{
|
||||
NSArray* screenArray = [NSScreen screens];
|
||||
@@ -442,10 +231,12 @@ bool MacPlatform::Init()
|
||||
// Init application
|
||||
[NSApplication sharedApplication];
|
||||
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||
AutoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// Init main menu
|
||||
NSMenu* mainMenu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
|
||||
[NSApp setMainMenu:mainMenu];
|
||||
// TODO: expose main menu for app (eg. to be used by Game or Editor on macOS-only)
|
||||
AutoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
Input::Mouse = New<MacMouse>();
|
||||
Input::Keyboard = New<MacKeyboard>();
|
||||
@@ -455,7 +246,7 @@ bool MacPlatform::Init()
|
||||
|
||||
void MacPlatform::LogInfo()
|
||||
{
|
||||
UnixPlatform::LogInfo();
|
||||
ApplePlatform::LogInfo();
|
||||
|
||||
char str[250];
|
||||
size_t strSize = sizeof(str);
|
||||
@@ -488,24 +279,6 @@ void MacPlatform::Tick()
|
||||
AutoreleasePool = [[NSAutoreleasePool alloc] init];
|
||||
}
|
||||
|
||||
void MacPlatform::BeforeExit()
|
||||
{
|
||||
}
|
||||
|
||||
void MacPlatform::Exit()
|
||||
{
|
||||
}
|
||||
|
||||
void MacPlatform::SetHighDpiAwarenessEnabled(bool enable)
|
||||
{
|
||||
// Disable resolution scaling in low dpi mode
|
||||
if (!enable)
|
||||
{
|
||||
CustomDpiScale /= ScreenScale;
|
||||
ScreenScale = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
int32 MacPlatform::GetDpi()
|
||||
{
|
||||
CGDirectDisplayID mainDisplay = CGMainDisplayID();
|
||||
@@ -515,9 +288,9 @@ int32 MacPlatform::GetDpi()
|
||||
return Math::Max(dpi, 72.0f);
|
||||
}
|
||||
|
||||
String MacPlatform::GetUserLocaleName()
|
||||
Guid MacPlatform::GetUniqueDeviceId()
|
||||
{
|
||||
return UserLocale;
|
||||
return DeviceId;
|
||||
}
|
||||
|
||||
String MacPlatform::GetComputerName()
|
||||
@@ -525,40 +298,6 @@ String MacPlatform::GetComputerName()
|
||||
return ComputerName;
|
||||
}
|
||||
|
||||
bool MacPlatform::GetHasFocus()
|
||||
{
|
||||
// Check if any window is focused
|
||||
ScopeLock lock(WindowsManager::WindowsLocker);
|
||||
for (auto window : WindowsManager::Windows)
|
||||
{
|
||||
if (window->IsFocused())
|
||||
return true;
|
||||
}
|
||||
|
||||
// Default to true if has no windows open
|
||||
return WindowsManager::Windows.IsEmpty();
|
||||
}
|
||||
|
||||
void MacPlatform::CreateGuid(Guid& result)
|
||||
{
|
||||
uuid_t uuid;
|
||||
uuid_generate(uuid);
|
||||
auto ptr = (uint32*)&uuid;
|
||||
result.A = ptr[0];
|
||||
result.B = ptr[1];
|
||||
result.C = ptr[2];
|
||||
result.D = ptr[3];
|
||||
}
|
||||
|
||||
bool MacPlatform::CanOpenUrl(const StringView& url)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void MacPlatform::OpenUrl(const StringView& url)
|
||||
{
|
||||
}
|
||||
|
||||
Float2 MacPlatform::GetMousePosition()
|
||||
{
|
||||
CGEventRef event = CGEventCreate(nullptr);
|
||||
@@ -584,7 +323,7 @@ Float2 MacPlatform::GetDesktopSize()
|
||||
Rectangle GetDisplayBounds(CGDirectDisplayID display)
|
||||
{
|
||||
CGRect rect = CGDisplayBounds(display);
|
||||
float screnScale = MacPlatform::ScreenScale;
|
||||
float screnScale = ApplePlatform::ScreenScale;
|
||||
return Rectangle(rect.origin.x * screnScale, rect.origin.y * screnScale, rect.size.width * screnScale, rect.size.height * screnScale);
|
||||
}
|
||||
|
||||
@@ -625,54 +364,11 @@ String MacPlatform::GetMainDirectory()
|
||||
return path;
|
||||
}
|
||||
|
||||
String MacPlatform::GetExecutableFilePath()
|
||||
{
|
||||
char buf[PATH_MAX];
|
||||
uint32 size = PATH_MAX;
|
||||
String result;
|
||||
if (_NSGetExecutablePath(buf, &size) == 0)
|
||||
result.SetUTF8(buf, StringUtils::Length(buf));
|
||||
return result;
|
||||
}
|
||||
|
||||
Guid MacPlatform::GetUniqueDeviceId()
|
||||
{
|
||||
return DeviceId;
|
||||
}
|
||||
|
||||
String MacPlatform::GetWorkingDirectory()
|
||||
{
|
||||
char buffer[256];
|
||||
getcwd(buffer, ARRAY_COUNT(buffer));
|
||||
return String(buffer);
|
||||
}
|
||||
|
||||
bool MacPlatform::SetWorkingDirectory(const String& path)
|
||||
{
|
||||
return chdir(StringAsANSI<>(*path).Get()) != 0;
|
||||
}
|
||||
|
||||
Window* MacPlatform::CreateWindow(const CreateWindowSettings& settings)
|
||||
{
|
||||
return New<MacWindow>(settings);
|
||||
}
|
||||
|
||||
bool MacPlatform::GetEnvironmentVariable(const String& name, String& value)
|
||||
{
|
||||
char* env = getenv(StringAsANSI<>(*name).Get());
|
||||
if (env)
|
||||
{
|
||||
value = String(env);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MacPlatform::SetEnvironmentVariable(const String& name, const String& value)
|
||||
{
|
||||
return setenv(StringAsANSI<>(*name).Get(), StringAsANSI<>(*value).Get(), true) != 0;
|
||||
}
|
||||
|
||||
int32 MacProcess(const StringView& cmdLine, const StringView& workingDir, const Dictionary<String, String>& environment, bool waitForEnd, bool logOutput)
|
||||
{
|
||||
LOG(Info, "Command: {0}", cmdLine);
|
||||
@@ -731,7 +427,7 @@ int32 MacPlatform::StartProcess(const StringView& filename, const StringView& ar
|
||||
// Special case if filename points to the app package (use actual executable)
|
||||
String exePath = filename;
|
||||
{
|
||||
NSString* processPath = (NSString*)MacUtils::ToString(filename);
|
||||
NSString* processPath = (NSString*)AppleUtils::ToString(filename);
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath: processPath])
|
||||
{
|
||||
NSString* appName = [[processPath lastPathComponent] stringByDeletingPathExtension];
|
||||
@@ -746,7 +442,7 @@ int32 MacPlatform::StartProcess(const StringView& filename, const StringView& ar
|
||||
{
|
||||
processPath = [bundle executablePath];
|
||||
if (processPath != nil)
|
||||
exePath = MacUtils::ToString((CFStringRef)processPath);
|
||||
exePath = AppleUtils::ToString((CFStringRef)processPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -766,57 +462,4 @@ int32 MacPlatform::RunProcess(const StringView& cmdLine, const StringView& worki
|
||||
return MacProcess(cmdLine, workingDir, environment, true, true);
|
||||
}
|
||||
|
||||
void* MacPlatform::LoadLibrary(const Char* filename)
|
||||
{
|
||||
const StringAsANSI<> filenameANSI(filename);
|
||||
void* result = dlopen(filenameANSI.Get(), RTLD_LAZY | RTLD_LOCAL);
|
||||
if (!result)
|
||||
{
|
||||
LOG(Error, "Failed to load {0} because {1}", filename, String(dlerror()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MacPlatform::FreeLibrary(void* handle)
|
||||
{
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
void* MacPlatform::GetProcAddress(void* handle, const char* symbol)
|
||||
{
|
||||
return dlsym(handle, symbol);
|
||||
}
|
||||
|
||||
Array<MacPlatform::StackFrame> MacPlatform::GetStackFrames(int32 skipCount, int32 maxDepth, void* context)
|
||||
{
|
||||
Array<StackFrame> result;
|
||||
#if CRASH_LOG_ENABLE
|
||||
void* callstack[120];
|
||||
skipCount = Math::Min<int32>(skipCount, ARRAY_COUNT(callstack));
|
||||
int32 maxCount = Math::Min<int32>(ARRAY_COUNT(callstack), skipCount + maxDepth);
|
||||
int32 count = backtrace(callstack, maxCount);
|
||||
int32 useCount = count - skipCount;
|
||||
if (useCount > 0)
|
||||
{
|
||||
char** names = backtrace_symbols(callstack + skipCount, useCount);
|
||||
result.Resize(useCount);
|
||||
for (int32 i = 0; i < useCount; i++)
|
||||
{
|
||||
char* name = names[i];
|
||||
StackFrame& frame = result[i];
|
||||
frame.ProgramCounter = callstack[skipCount + i];
|
||||
frame.ModuleName[0] = 0;
|
||||
frame.FileName[0] = 0;
|
||||
frame.LineNumber = 0;
|
||||
int32 nameLen = Math::Min<int32>(StringUtils::Length(name), ARRAY_COUNT(frame.FunctionName) - 1);
|
||||
Platform::MemoryCopy(frame.FunctionName, name, nameLen);
|
||||
frame.FunctionName[nameLen] = 0;
|
||||
|
||||
}
|
||||
free(names);
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -4,115 +4,33 @@
|
||||
|
||||
#if PLATFORM_MAC
|
||||
|
||||
#include "../Unix/UnixPlatform.h"
|
||||
#include "../Apple/ApplePlatform.h"
|
||||
|
||||
/// <summary>
|
||||
/// The Mac platform implementation and application management utilities.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API MacPlatform : public UnixPlatform
|
||||
class FLAXENGINE_API MacPlatform : public ApplePlatform
|
||||
{
|
||||
public:
|
||||
static float ScreenScale;
|
||||
|
||||
public:
|
||||
|
||||
// [UnixPlatform]
|
||||
FORCE_INLINE static void MemoryBarrier()
|
||||
{
|
||||
__sync_synchronize();
|
||||
}
|
||||
FORCE_INLINE static int64 InterlockedExchange(int64 volatile* dst, int64 exchange)
|
||||
{
|
||||
return __sync_lock_test_and_set(dst, exchange);
|
||||
}
|
||||
FORCE_INLINE static int32 InterlockedCompareExchange(int32 volatile* dst, int32 exchange, int32 comperand)
|
||||
{
|
||||
return __sync_val_compare_and_swap(dst, comperand, exchange);
|
||||
}
|
||||
FORCE_INLINE static int64 InterlockedCompareExchange(int64 volatile* dst, int64 exchange, int64 comperand)
|
||||
{
|
||||
return __sync_val_compare_and_swap(dst, comperand, exchange);
|
||||
}
|
||||
FORCE_INLINE static int64 InterlockedIncrement(int64 volatile* dst)
|
||||
{
|
||||
return __sync_add_and_fetch(dst, 1);
|
||||
}
|
||||
FORCE_INLINE static int64 InterlockedDecrement(int64 volatile* dst)
|
||||
{
|
||||
return __sync_sub_and_fetch(dst, 1);
|
||||
}
|
||||
FORCE_INLINE static int64 InterlockedAdd(int64 volatile* dst, int64 value)
|
||||
{
|
||||
return __sync_fetch_and_add(dst, value);
|
||||
}
|
||||
FORCE_INLINE static int32 AtomicRead(int32 volatile* dst)
|
||||
{
|
||||
return __atomic_load_n(dst, __ATOMIC_RELAXED);
|
||||
}
|
||||
FORCE_INLINE static int64 AtomicRead(int64 volatile* dst)
|
||||
{
|
||||
return __atomic_load_n(dst, __ATOMIC_RELAXED);
|
||||
}
|
||||
FORCE_INLINE static void AtomicStore(int32 volatile* dst, int32 value)
|
||||
{
|
||||
__atomic_store(dst, &value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
FORCE_INLINE static void AtomicStore(int64 volatile* dst, int64 value)
|
||||
{
|
||||
__atomic_store(dst, &value, __ATOMIC_SEQ_CST);
|
||||
}
|
||||
FORCE_INLINE static void Prefetch(void const* ptr)
|
||||
{
|
||||
__builtin_prefetch(static_cast<char const*>(ptr));
|
||||
}
|
||||
static bool Is64BitPlatform();
|
||||
static CPUInfo GetCPUInfo();
|
||||
static int32 GetCacheLineSize();
|
||||
static MemoryStats GetMemoryStats();
|
||||
static ProcessMemoryStats GetProcessMemoryStats();
|
||||
static uint64 GetCurrentThreadID();
|
||||
static void SetThreadPriority(ThreadPriority priority);
|
||||
static void SetThreadAffinityMask(uint64 affinityMask);
|
||||
static void Sleep(int32 milliseconds);
|
||||
static double GetTimeSeconds();
|
||||
static uint64 GetTimeCycles();
|
||||
static uint64 GetClockFrequency();
|
||||
static void GetSystemTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond);
|
||||
static void GetUTCTime(int32& year, int32& month, int32& dayOfWeek, int32& day, int32& hour, int32& minute, int32& second, int32& millisecond);
|
||||
// [ApplePlatform]
|
||||
static bool Init();
|
||||
static void LogInfo();
|
||||
static void BeforeRun();
|
||||
static void Tick();
|
||||
static void BeforeExit();
|
||||
static void Exit();
|
||||
static void SetHighDpiAwarenessEnabled(bool enable);
|
||||
static int32 GetDpi();
|
||||
static String GetUserLocaleName();
|
||||
static Guid GetUniqueDeviceId();
|
||||
static String GetComputerName();
|
||||
static bool GetHasFocus();
|
||||
static void CreateGuid(Guid& result);
|
||||
static bool CanOpenUrl(const StringView& url);
|
||||
static void OpenUrl(const StringView& url);
|
||||
static Float2 GetMousePosition();
|
||||
static void SetMousePosition(const Float2& pos);
|
||||
static Rectangle GetMonitorBounds(const Float2& screenPos);
|
||||
static Float2 GetDesktopSize();
|
||||
static Rectangle GetVirtualDesktopBounds();
|
||||
static Rectangle GetMonitorBounds(const Float2& screenPos);
|
||||
static Float2 GetDesktopSize();
|
||||
static Rectangle GetVirtualDesktopBounds();
|
||||
static String GetMainDirectory();
|
||||
static String GetExecutableFilePath();
|
||||
static Guid GetUniqueDeviceId();
|
||||
static String GetWorkingDirectory();
|
||||
static bool SetWorkingDirectory(const String& path);
|
||||
static Window* CreateWindow(const CreateWindowSettings& settings);
|
||||
static bool GetEnvironmentVariable(const String& name, String& value);
|
||||
static bool SetEnvironmentVariable(const String& name, const String& value);
|
||||
static int32 StartProcess(const StringView& filename, const StringView& args, const StringView& workingDir, bool hiddenWindow = false, bool waitForEnd = false);
|
||||
static int32 RunProcess(const StringView& cmdLine, const StringView& workingDir, bool hiddenWindow = true);
|
||||
static int32 RunProcess(const StringView& cmdLine, const StringView& workingDir, const Dictionary<String, String, HeapAllocation>& environment, bool hiddenWindow = true);
|
||||
static void* LoadLibrary(const Char* filename);
|
||||
static void FreeLibrary(void* handle);
|
||||
static void* GetProcAddress(void* handle, const char* symbol);
|
||||
static Array<StackFrame, HeapAllocation> GetStackFrames(int32 skipCount = 0, int32 maxDepth = 60, void* context = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#if PLATFORM_MAC
|
||||
|
||||
#include "../Window.h"
|
||||
#include "MacUtils.h"
|
||||
#include "Engine/Platform/Apple/AppleUtils.h"
|
||||
#include "Engine/Platform/IGuiData.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Input/Input.h"
|
||||
@@ -208,7 +208,7 @@ void GetDragDropData(const MacWindow* window, id<NSDraggingInfo> sender, Float2&
|
||||
if ([[pasteboard types] containsObject:NSPasteboardTypeString])
|
||||
{
|
||||
dropData.CurrentType = IGuiData::Type::Text;
|
||||
dropData.AsText = MacUtils::ToString((CFStringRef)[pasteboard stringForType:NSPasteboardTypeString]);
|
||||
dropData.AsText = AppleUtils::ToString((CFStringRef)[pasteboard stringForType:NSPasteboardTypeString]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -218,7 +218,7 @@ void GetDragDropData(const MacWindow* window, id<NSDraggingInfo> sender, Float2&
|
||||
{
|
||||
NSString* url = [[files objectAtIndex:i] path];
|
||||
NSString* file = [NSURL URLWithString:url].path;
|
||||
dropData.AsFiles.Add(MacUtils::ToString((CFStringRef)file));
|
||||
dropData.AsFiles.Add(AppleUtils::ToString((CFStringRef)file));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -572,7 +572,7 @@ MacWindow::MacWindow(const CreateWindowSettings& settings)
|
||||
: WindowBase(settings)
|
||||
{
|
||||
_clientSize = Float2(settings.Size.X, settings.Size.Y);
|
||||
Float2 pos = MacUtils::PosToCoca(settings.Position);
|
||||
Float2 pos = AppleUtils::PosToCoca(settings.Position);
|
||||
NSRect frame = NSMakeRect(pos.X, pos.Y - settings.Size.Y, settings.Size.X, settings.Size.Y);
|
||||
NSUInteger styleMask = NSWindowStyleMaskClosable;
|
||||
if (settings.IsRegularWindow)
|
||||
@@ -606,7 +606,7 @@ MacWindow::MacWindow(const CreateWindowSettings& settings)
|
||||
MacViewImpl* view = [[MacViewImpl alloc] init];
|
||||
view.wantsLayer = YES;
|
||||
[view setWindow:this];
|
||||
window.title = (__bridge NSString*)MacUtils::ToString(settings.Title);
|
||||
window.title = (__bridge NSString*)AppleUtils::ToString(settings.Title);
|
||||
[window setWindow:this];
|
||||
[window setReleasedWhenClosed:NO];
|
||||
[window setMinSize:NSMakeSize(settings.MinimumSize.X, settings.MinimumSize.Y)];
|
||||
@@ -779,7 +779,7 @@ void MacWindow::SetClientBounds(const Rectangle& clientArea)
|
||||
//newRect.origin.x = oldRect.origin.x;
|
||||
//newRect.origin.y = NSMaxY(oldRect) - newRect.size.height;
|
||||
|
||||
Float2 pos = MacUtils::PosToCoca(clientArea.Location);
|
||||
Float2 pos = AppleUtils::PosToCoca(clientArea.Location);
|
||||
Float2 titleSize = GetWindowTitleSize(this);
|
||||
newRect.origin.x = pos.X + titleSize.X;
|
||||
newRect.origin.y = pos.Y - newRect.size.height + titleSize.Y;
|
||||
@@ -792,7 +792,7 @@ void MacWindow::SetPosition(const Float2& position)
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
if (!window)
|
||||
return;
|
||||
Float2 pos = MacUtils::PosToCoca(position) / MacPlatform::ScreenScale;
|
||||
Float2 pos = AppleUtils::PosToCoca(position) / MacPlatform::ScreenScale;
|
||||
NSRect rect = [window frame];
|
||||
[window setFrameOrigin:NSMakePoint(pos.X, pos.Y - rect.size.height)];
|
||||
}
|
||||
@@ -803,7 +803,7 @@ Float2 MacWindow::GetPosition() const
|
||||
if (!window)
|
||||
return Float2::Zero;
|
||||
NSRect rect = [window frame];
|
||||
return MacUtils::CocaToPos(Float2(rect.origin.x, rect.origin.y + rect.size.height) * MacPlatform::ScreenScale);
|
||||
return AppleUtils::CocaToPos(Float2(rect.origin.x, rect.origin.y + rect.size.height) * MacPlatform::ScreenScale);
|
||||
}
|
||||
|
||||
Float2 MacWindow::GetSize() const
|
||||
@@ -868,7 +868,7 @@ void MacWindow::SetTitle(const StringView& title)
|
||||
NSWindow* window = (NSWindow*)_window;
|
||||
if (!window)
|
||||
return;
|
||||
[window setTitle:(__bridge NSString*)MacUtils::ToString(_title)];
|
||||
[window setTitle:(__bridge NSString*)AppleUtils::ToString(_title)];
|
||||
}
|
||||
|
||||
DragDropEffect MacWindow::DoDragDrop(const StringView& data)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#if PLATFORM_WINDOWS || PLATFORM_UWP || PLATFORM_XBOX_ONE || PLATFORM_XBOX_SCARLETT
|
||||
#include "Win32/Win32Network.h"
|
||||
#elif PLATFORM_LINUX || PLATFORM_ANDROID || PLATFORM_MAC
|
||||
#elif PLATFORM_LINUX || PLATFORM_ANDROID || PLATFORM_MAC || PLATFORM_IOS
|
||||
#include "Unix/UnixNetwork.h"
|
||||
#elif PLATFORM_PS4
|
||||
#include "Platforms/PS4/Engine/Platform/PS4Network.h"
|
||||
@@ -12,8 +12,6 @@
|
||||
#include "Platforms/PS5/Engine/Platform/PS5Network.h"
|
||||
#elif PLATFORM_SWITCH
|
||||
#include "Platforms/Switch/Engine/Platform/SwitchNetwork.h"
|
||||
#elif PLATFORM_MAC
|
||||
#include "Mac/MacNetwork.h"
|
||||
#else
|
||||
#error Missing Network implementation!
|
||||
#endif
|
||||
|
||||
@@ -79,8 +79,14 @@ public class Platform : EngineModule
|
||||
break;
|
||||
case TargetPlatform.Mac:
|
||||
options.SourcePaths.Add(Path.Combine(FolderPath, "Unix"));
|
||||
options.SourcePaths.Add(Path.Combine(FolderPath, "Apple"));
|
||||
options.SourcePaths.Add(Path.Combine(FolderPath, "Mac"));
|
||||
break;
|
||||
case TargetPlatform.iOS:
|
||||
options.SourcePaths.Add(Path.Combine(FolderPath, "Unix"));
|
||||
options.SourcePaths.Add(Path.Combine(FolderPath, "Apple"));
|
||||
options.SourcePaths.Add(Path.Combine(FolderPath, "iOS"));
|
||||
break;
|
||||
default: throw new InvalidPlatformException(options.Platform.Target);
|
||||
}
|
||||
if (options.Target.IsEditor)
|
||||
@@ -92,6 +98,7 @@ public class Platform : EngineModule
|
||||
options.SourceFiles.Add(Path.Combine(FolderPath, "Android", "AndroidPlatformSettings.h"));
|
||||
options.SourceFiles.Add(Path.Combine(FolderPath, "GDK", "GDKPlatformSettings.h"));
|
||||
options.SourceFiles.Add(Path.Combine(FolderPath, "Mac", "MacPlatformSettings.h"));
|
||||
options.SourceFiles.Add(Path.Combine(FolderPath, "iOS", "iOSPlatformSettings.h"));
|
||||
AddSourceFileIfExists(options, Path.Combine(Globals.EngineRoot, "Source", "Platforms", "XboxOne", "Engine", "Platform", "XboxOnePlatformSettings.h"));
|
||||
AddSourceFileIfExists(options, Path.Combine(Globals.EngineRoot, "Source", "Platforms", "XboxScarlett", "Engine", "Platform", "XboxScarlettPlatformSettings.h"));
|
||||
AddSourceFileIfExists(options, Path.Combine(Globals.EngineRoot, "Source", "Platforms", "PS4", "Engine", "Platform", "PS4PlatformSettings.h"));
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "Platforms/Switch/Engine/Platform/SwitchPlatform.h"
|
||||
#elif PLATFORM_MAC
|
||||
#include "Mac/MacPlatform.h"
|
||||
#elif PLATFORM_IOS
|
||||
#include "iOS/iOSPlatform.h"
|
||||
#else
|
||||
#error Missing Platform implementation!
|
||||
#endif
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
#include "Android/AndroidThread.h"
|
||||
#elif PLATFORM_SWITCH
|
||||
#include "Platforms/Switch/Engine/Platform/SwitchThread.h"
|
||||
#elif PLATFORM_MAC
|
||||
#include "Mac/MacThread.h"
|
||||
#elif PLATFORM_MAC || PLATFORM_IOS
|
||||
#include "Apple/AppleThread.h"
|
||||
#else
|
||||
#error Missing Thread implementation!
|
||||
#endif
|
||||
|
||||
@@ -243,8 +243,8 @@ class UnixFile;
|
||||
typedef UnixFile File;
|
||||
class MacPlatform;
|
||||
typedef MacPlatform Platform;
|
||||
class MacThread;
|
||||
typedef MacThread Thread;
|
||||
class AppleThread;
|
||||
typedef AppleThread Thread;
|
||||
class MacWindow;
|
||||
typedef MacWindow Window;
|
||||
class UnixNetwork;
|
||||
@@ -252,6 +252,31 @@ typedef UnixNetwork Network;
|
||||
class UserBase;
|
||||
typedef UserBase User;
|
||||
|
||||
#elif PLATFORM_IOS
|
||||
|
||||
class ClipboardBase;
|
||||
typedef ClipboardBase Clipboard;
|
||||
class UnixCriticalSection;
|
||||
typedef UnixCriticalSection CriticalSection;
|
||||
class UnixConditionVariable;
|
||||
typedef UnixConditionVariable ConditionVariable;
|
||||
class AppleFileSystem;
|
||||
typedef AppleFileSystem FileSystem;
|
||||
class FileSystemWatcherBase;
|
||||
typedef FileSystemWatcherBase FileSystemWatcher;
|
||||
class UnixFile;
|
||||
typedef UnixFile File;
|
||||
class iOSPlatform;
|
||||
typedef iOSPlatform Platform;
|
||||
class AppleThread;
|
||||
typedef AppleThread Thread;
|
||||
class iOSWindow;
|
||||
typedef iOSWindow Window;
|
||||
class UnixNetwork;
|
||||
typedef UnixNetwork Network;
|
||||
class UserBase;
|
||||
typedef UserBase User;
|
||||
|
||||
#else
|
||||
|
||||
#error Missing Types implementation!
|
||||
|
||||
@@ -186,18 +186,6 @@ Float2 UWPPlatform::GetDesktopSize()
|
||||
return result;
|
||||
}
|
||||
|
||||
Rectangle UWPPlatform::GetMonitorBounds(const Float2& screenPos)
|
||||
{
|
||||
// TODO: do it in a proper way
|
||||
return Rectangle(Float2::Zero, GetDesktopSize());
|
||||
}
|
||||
|
||||
Rectangle UWPPlatform::GetVirtualDesktopBounds()
|
||||
{
|
||||
// TODO: do it in a proper way
|
||||
return Rectangle(Float2::Zero, GetDesktopSize());
|
||||
}
|
||||
|
||||
Window* UWPPlatform::CreateWindow(const CreateWindowSettings& settings)
|
||||
{
|
||||
// Settings with provided UWPWindowImpl are only valid
|
||||
|
||||
@@ -39,9 +39,7 @@ public:
|
||||
static void OpenUrl(const StringView& url);
|
||||
static Float2 GetMousePosition();
|
||||
static void SetMousePosition(const Float2& pos);
|
||||
static Rectangle GetMonitorBounds(const Float2& screenPos);
|
||||
static Float2 GetDesktopSize();
|
||||
static Rectangle GetVirtualDesktopBounds();
|
||||
static Window* CreateWindow(const CreateWindowSettings& settings);
|
||||
static void* LoadLibrary(const Char* filename);
|
||||
};
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include "Platforms/PS5/Engine/Platform/PS5Window.h"
|
||||
#elif PLATFORM_MAC
|
||||
#include "Mac/MacWindow.h"
|
||||
#elif PLATFORM_IOS
|
||||
#include "iOS/iOSWindow.h"
|
||||
#else
|
||||
#error Missing Window implementation!
|
||||
#endif
|
||||
|
||||
17
Source/Engine/Platform/iOS/iOSDefines.h
Normal file
17
Source/Engine/Platform/iOS/iOSDefines.h
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if PLATFORM_IOS
|
||||
|
||||
#include "../Unix/UnixDefines.h"
|
||||
|
||||
// Platform description
|
||||
#define PLATFORM_TYPE PlatformType::iOS
|
||||
#define PLATFORM_64BITS 1
|
||||
#define PLATFORM_ARCH_ARM64 1
|
||||
#define PLATFORM_ARCH ArchitectureType::ARM64
|
||||
#define PLATFORM_CACHE_LINE_SIZE 128
|
||||
#define PLATFORM_DEBUG_BREAK __builtin_trap()
|
||||
|
||||
#endif
|
||||
91
Source/Engine/Platform/iOS/iOSPlatform.cpp
Normal file
91
Source/Engine/Platform/iOS/iOSPlatform.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_IOS
|
||||
|
||||
#include "iOSPlatform.h"
|
||||
#include "iOSWindow.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Platform/StringUtils.h"
|
||||
#include "Engine/Platform/MessageBox.h"
|
||||
#include <UIKit/UIKit.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
int32 Dpi = 96;
|
||||
Guid DeviceId;
|
||||
|
||||
DialogResult MessageBox::Show(Window* parent, const StringView& text, const StringView& caption, MessageBoxButtons buttons, MessageBoxIcon icon)
|
||||
{
|
||||
// TODO: implement message box popup on iOS
|
||||
return DialogResult::OK;
|
||||
}
|
||||
|
||||
bool iOSPlatform::Init()
|
||||
{
|
||||
if (ApplePlatform::Init())
|
||||
return true;
|
||||
|
||||
ScreenScale = [[UIScreen mainScreen] scale];
|
||||
CustomDpiScale *= ScreenScale;
|
||||
Dpi = 72; // TODO: calculate screen dpi (probably hardcoded map for iPhone model)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void iOSPlatform::LogInfo()
|
||||
{
|
||||
ApplePlatform::LogInfo();
|
||||
|
||||
struct utsname systemInfo;
|
||||
uname(&systemInfo);
|
||||
NSOperatingSystemVersion version = [[NSProcessInfo processInfo] operatingSystemVersion];
|
||||
LOG(Info, "{3}, iOS {0}.{1}.{2}", version.majorVersion, version.minorVersion, version.patchVersion, String(systemInfo.machine));
|
||||
}
|
||||
|
||||
void iOSPlatform::Tick()
|
||||
{
|
||||
// Process system events
|
||||
while (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.0001, true) == kCFRunLoopRunHandledSource)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
int32 iOSPlatform::GetDpi()
|
||||
{
|
||||
return Dpi;
|
||||
}
|
||||
|
||||
Guid iOSPlatform::GetUniqueDeviceId()
|
||||
{
|
||||
return Guid::Empty; // TODO: use MAC address of the iPhone to generate device id (at least within network connection state)
|
||||
}
|
||||
|
||||
String iOSPlatform::GetComputerName()
|
||||
{
|
||||
return TEXT("iPhone");
|
||||
}
|
||||
|
||||
Float2 iOSPlatform::GetDesktopSize()
|
||||
{
|
||||
CGRect frame = [[UIScreen mainScreen] bounds];
|
||||
float scale = [[UIScreen mainScreen] scale];
|
||||
return Float2((float)frame.size.width * scale, (float)frame.size.height * scale);
|
||||
}
|
||||
|
||||
String iOSPlatform::GetMainDirectory()
|
||||
{
|
||||
String path = StringUtils::GetDirectoryName(GetExecutableFilePath());
|
||||
if (path.EndsWith(TEXT("/Contents/iOS")))
|
||||
{
|
||||
// If running from executable in a package, go up to the Contents
|
||||
path = StringUtils::GetDirectoryName(path);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
Window* iOSPlatform::CreateWindow(const CreateWindowSettings& settings)
|
||||
{
|
||||
return New<iOSWindow>(settings);
|
||||
}
|
||||
|
||||
#endif
|
||||
28
Source/Engine/Platform/iOS/iOSPlatform.h
Normal file
28
Source/Engine/Platform/iOS/iOSPlatform.h
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if PLATFORM_IOS
|
||||
|
||||
#include "../Apple/ApplePlatform.h"
|
||||
|
||||
/// <summary>
|
||||
/// The iOS platform implementation and application management utilities.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API iOSPlatform : public ApplePlatform
|
||||
{
|
||||
public:
|
||||
|
||||
// [ApplePlatform]
|
||||
static bool Init();
|
||||
static void LogInfo();
|
||||
static void Tick();
|
||||
static int32 GetDpi();
|
||||
static Guid GetUniqueDeviceId();
|
||||
static String GetComputerName();
|
||||
static Float2 GetDesktopSize();
|
||||
static String GetMainDirectory();
|
||||
static Window* CreateWindow(const CreateWindowSettings& settings);
|
||||
};
|
||||
|
||||
#endif
|
||||
50
Source/Engine/Platform/iOS/iOSPlatformSettings.h
Normal file
50
Source/Engine/Platform/iOS/iOSPlatformSettings.h
Normal file
@@ -0,0 +1,50 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if PLATFORM_IOS || USE_EDITOR
|
||||
|
||||
#include "Engine/Core/Config/PlatformSettingsBase.h"
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Scripting/SoftObjectReference.h"
|
||||
|
||||
class Texture;
|
||||
|
||||
/// <summary>
|
||||
/// iOS platform settings.
|
||||
/// </summary>
|
||||
API_CLASS(sealed, Namespace="FlaxEditor.Content.Settings") class FLAXENGINE_API iOSPlatformSettings : public SettingsBase
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(iOSPlatformSettings);
|
||||
|
||||
/// <summary>
|
||||
/// The app identifier (reversed DNS, eg. com.company.product). Custom tokens: ${PROJECT_NAME}, ${COMPANY_NAME}.
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(0), EditorDisplay(\"General\")")
|
||||
String AppIdentifier = TEXT("com.${COMPANY_NAME}.${PROJECT_NAME}");
|
||||
|
||||
/// <summary>
|
||||
/// Custom icon texture to use for the application (overrides the default one).
|
||||
/// </summary>
|
||||
API_FIELD(Attributes="EditorOrder(1000), EditorDisplay(\"Other\")")
|
||||
SoftObjectReference<Texture> OverrideIcon;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the instance of the settings asset (default value if missing). Object returned by this method is always loaded with valid data to use.
|
||||
/// </summary>
|
||||
static iOSPlatformSettings* Get();
|
||||
|
||||
// [SettingsBase]
|
||||
void Deserialize(DeserializeStream& stream, ISerializeModifier* modifier) final override
|
||||
{
|
||||
DESERIALIZE(AppIdentifier);
|
||||
DESERIALIZE(OverrideIcon);
|
||||
}
|
||||
};
|
||||
|
||||
#if PLATFORM_IOS
|
||||
typedef iOSPlatformSettings PlatformSettings;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
212
Source/Engine/Platform/iOS/iOSWindow.cpp
Normal file
212
Source/Engine/Platform/iOS/iOSWindow.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#if PLATFORM_IOS
|
||||
|
||||
#include "../Window.h"
|
||||
#include "Engine/Platform/Apple/AppleUtils.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Input/Input.h"
|
||||
#include "Engine/Graphics/RenderTask.h"
|
||||
#include <UIKit/UIKit.h>
|
||||
#include <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
@interface iOSUIWindow : UIWindow
|
||||
{
|
||||
}
|
||||
@end
|
||||
|
||||
@implementation iOSUIWindow
|
||||
|
||||
@end
|
||||
|
||||
@interface iOSUIViewController : UIViewController
|
||||
|
||||
@end
|
||||
|
||||
@interface iOSUIView : UIView
|
||||
|
||||
@property iOSWindow* window;
|
||||
|
||||
@end
|
||||
|
||||
@implementation iOSUIView
|
||||
|
||||
+(Class) layerClass { return [CAMetalLayer class]; }
|
||||
|
||||
- (void)setFrame:(CGRect)frame
|
||||
{
|
||||
[super setFrame:frame];
|
||||
if (!_window)
|
||||
return;
|
||||
float scale = [[UIScreen mainScreen] scale];
|
||||
_window->CheckForResize((float)frame.size.width * scale, (float)frame.size.height * scale);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation iOSUIViewController
|
||||
{
|
||||
}
|
||||
|
||||
- (BOOL)prefersHomeIndicatorAutoHidden
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)prefersStatusBarHidden
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(UIStatusBarAnimation)preferredStatusBarUpdateAnimation
|
||||
{
|
||||
return UIStatusBarAnimationSlide;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
iOSWindow::iOSWindow(const CreateWindowSettings& settings)
|
||||
: WindowBase(settings)
|
||||
{
|
||||
// Fullscreen by default
|
||||
CGRect frame = [[UIScreen mainScreen] bounds];
|
||||
float scale = [[UIScreen mainScreen] scale];
|
||||
_clientSize = Float2((float)frame.size.width * scale, (float)frame.size.height * scale);
|
||||
|
||||
// Setup view
|
||||
_view = [[iOSUIView alloc] initWithFrame:frame];
|
||||
iOSUIView* v = (iOSUIView*)_view;
|
||||
[v resignFirstResponder];
|
||||
[v setNeedsDisplay];
|
||||
[v setHidden:NO];
|
||||
[v setOpaque:YES];
|
||||
[v setAutoResizeDrawable:YES];
|
||||
v.backgroundColor = [UIColor clearColor];
|
||||
v.window = this;
|
||||
|
||||
// Setp view controller
|
||||
_viewController = [[iOSUIViewController alloc] init];
|
||||
iOSUIViewController* vc = (iOSUIViewController*)_viewController;
|
||||
[vc setView:v];
|
||||
[vc setNeedsUpdateOfHomeIndicatorAutoHidden];
|
||||
[vc setNeedsStatusBarAppearanceUpdate];
|
||||
|
||||
// Setup window
|
||||
_window = [[iOSUIWindow alloc] initWithFrame:frame];
|
||||
iOSUIWindow* w = (iOSUIWindow*)_window;
|
||||
[w setRootViewController:vc];
|
||||
[w setContentMode:UIViewContentModeScaleToFill];
|
||||
[w makeKeyAndVisible];
|
||||
[w setBounds:frame];
|
||||
w.backgroundColor = [UIColor clearColor];
|
||||
}
|
||||
|
||||
iOSWindow::~iOSWindow()
|
||||
{
|
||||
[(iOSUIWindow*)_window release];
|
||||
[(iOSUIView*)_view release];
|
||||
[(iOSUIViewController*)_viewController release];
|
||||
|
||||
_window = nullptr;
|
||||
_view = nullptr;
|
||||
_layer = nullptr;
|
||||
}
|
||||
|
||||
void iOSWindow::CheckForResize(float width, float height)
|
||||
{
|
||||
const Float2 clientSize(width, height);
|
||||
if (clientSize != _clientSize)
|
||||
{
|
||||
_clientSize = clientSize;
|
||||
OnResize(width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void* iOSWindow::GetNativePtr() const
|
||||
{
|
||||
return _window;
|
||||
}
|
||||
|
||||
void iOSWindow::Show()
|
||||
{
|
||||
if (!_visible)
|
||||
{
|
||||
InitSwapChain();
|
||||
if (_showAfterFirstPaint)
|
||||
{
|
||||
if (RenderTask)
|
||||
RenderTask->Enabled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Show
|
||||
_focused = true;
|
||||
|
||||
// Base
|
||||
WindowBase::Show();
|
||||
}
|
||||
}
|
||||
|
||||
bool iOSWindow::IsClosed() const
|
||||
{
|
||||
return _window != nullptr;
|
||||
}
|
||||
|
||||
bool iOSWindow::IsForegroundWindow() const
|
||||
{
|
||||
return Platform::GetHasFocus() && IsFocused();
|
||||
}
|
||||
|
||||
void iOSWindow::BringToFront(bool force)
|
||||
{
|
||||
Focus();
|
||||
}
|
||||
|
||||
void iOSWindow::SetIsFullscreen(bool isFullscreen)
|
||||
{
|
||||
}
|
||||
|
||||
void iOSWindow::SetClientBounds(const Rectangle& clientArea)
|
||||
{
|
||||
}
|
||||
|
||||
void iOSWindow::SetPosition(const Float2& position)
|
||||
{
|
||||
}
|
||||
|
||||
Float2 iOSWindow::GetPosition() const
|
||||
{
|
||||
return Float2::Zero;
|
||||
}
|
||||
|
||||
Float2 iOSWindow::GetSize() const
|
||||
{
|
||||
return _clientSize;
|
||||
}
|
||||
|
||||
Float2 iOSWindow::GetClientSize() const
|
||||
{
|
||||
return _clientSize;
|
||||
}
|
||||
|
||||
Float2 iOSWindow::ScreenToClient(const Float2& screenPos) const
|
||||
{
|
||||
return screenPos;
|
||||
}
|
||||
|
||||
Float2 iOSWindow::ClientToScreen(const Float2& clientPos) const
|
||||
{
|
||||
return clientPos;
|
||||
}
|
||||
|
||||
void iOSWindow::SetTitle(const StringView& title)
|
||||
{
|
||||
_title = title;
|
||||
}
|
||||
|
||||
#endif
|
||||
49
Source/Engine/Platform/iOS/iOSWindow.h
Normal file
49
Source/Engine/Platform/iOS/iOSWindow.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#if PLATFORM_IOS
|
||||
|
||||
#include "Engine/Platform/Base/WindowBase.h"
|
||||
#include "Engine/Platform/Platform.h"
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of the window class for iOS platform.
|
||||
/// </summary>
|
||||
class FLAXENGINE_API iOSWindow : public WindowBase
|
||||
{
|
||||
private:
|
||||
|
||||
Float2 _clientSize;
|
||||
void* _window;
|
||||
void* _layer;
|
||||
void* _view;
|
||||
void* _viewController;
|
||||
|
||||
public:
|
||||
|
||||
iOSWindow(const CreateWindowSettings& settings);
|
||||
~iOSWindow();
|
||||
|
||||
void CheckForResize(float width, float height);
|
||||
|
||||
public:
|
||||
|
||||
// [Window]
|
||||
void* GetNativePtr() const override;
|
||||
void Show() override;
|
||||
bool IsClosed() const override;
|
||||
bool IsForegroundWindow() const override;
|
||||
void BringToFront(bool force = false) override;
|
||||
void SetClientBounds(const Rectangle& clientArea) override;
|
||||
void SetPosition(const Float2& position) override;
|
||||
Float2 GetPosition() const override;
|
||||
Float2 GetSize() const override;
|
||||
Float2 GetClientSize() const override;
|
||||
Float2 ScreenToClient(const Float2& screenPos) const override;
|
||||
Float2 ClientToScreen(const Float2& clientPos) const override;
|
||||
void SetIsFullscreen(bool isFullscreen) override;
|
||||
void SetTitle(const StringView& title) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user