2016-12-08 08:52:44 -05:00
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
# include "Mac/DesktopPlatformMac.h"
2014-03-14 14:13:41 -04:00
# include "MacApplication.h"
2014-05-13 18:23:53 -04:00
# include "FeedbackContextMarkup.h"
2014-05-14 18:56:27 -04:00
# include "MacNativeFeedbackContext.h"
2014-08-19 10:46:30 -04:00
# include "CocoaThread.h"
Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none
==========================
MAJOR FEATURES + CHANGES
==========================
Change 3209340 on 2016/11/23 by Ben.Marsh
Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.
Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.
* Every header now includes everything it needs to compile.
* There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
* There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
* Every .cpp file includes its matching .h file first.
* This helps validate that each header is including everything it needs to compile.
* No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
* You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
* There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
* No engine code explicitly includes a precompiled header any more.
* We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
* PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.
Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.
[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00
# include "Misc/Paths.h"
# include "Misc/ConfigCacheIni.h"
# include "Misc/Guid.h"
# include "HAL/FileManager.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "DesktopPlatform"
2014-09-26 14:32:24 -04:00
class FMacScopedSystemModalMode
{
public :
FMacScopedSystemModalMode ( )
{
MacApplication - > SystemModalMode ( true ) ;
}
~ FMacScopedSystemModalMode ( )
{
MacApplication - > SystemModalMode ( false ) ;
}
private :
FScopedSystemModalMode SystemModalMode ;
} ;
2014-03-14 14:13:41 -04:00
class FCocoaScopeContext
{
public :
FCocoaScopeContext ( void )
{
SCOPED_AUTORELEASE_POOL ;
PreviousContext = [ NSOpenGLContext currentContext ] ;
}
~ FCocoaScopeContext ( void )
{
SCOPED_AUTORELEASE_POOL ;
NSOpenGLContext * NewContext = [ NSOpenGLContext currentContext ] ;
if ( PreviousContext ! = NewContext )
{
if ( PreviousContext )
{
[ PreviousContext makeCurrentContext ] ;
}
else
{
[ NSOpenGLContext clearCurrentContext ] ;
}
}
}
private :
NSOpenGLContext * PreviousContext ;
} ;
/**
* Custom accessory view class to allow choose kind of file extension
*/
@ interface FFileDialogAccessoryView : NSView
{
@ private
NSPopUpButton * PopUpButton ;
NSTextField * TextField ;
NSSavePanel * DialogPanel ;
NSMutableArray * AllowedFileTypes ;
2014-10-30 13:21:40 -04:00
int32 SelectedExtension ;
2014-03-14 14:13:41 -04:00
}
- ( id ) initWithFrame : ( NSRect ) frameRect dialogPanel : ( NSSavePanel * ) panel ;
- ( void ) PopUpButtonAction : ( id ) sender ;
- ( void ) AddAllowedFileTypes : ( NSArray * ) array ;
- ( void ) SetExtensionsAtIndex : ( int32 ) index ;
2014-10-30 13:21:40 -04:00
- ( int32 ) SelectedExtension ;
2014-03-14 14:13:41 -04:00
@ end
@ implementation FFileDialogAccessoryView
- ( id ) initWithFrame : ( NSRect ) frameRect dialogPanel : ( NSSavePanel * ) panel
{
self = [ super initWithFrame : frameRect ] ;
DialogPanel = panel ;
FString FieldText = LOCTEXT ( " FileExtension " , " File extension: " ) . ToString ( ) ;
CFStringRef FieldTextCFString = FPlatformString : : TCHARToCFString ( * FieldText ) ;
TextField = [ [ NSTextField alloc ] initWithFrame : NSMakeRect ( 0.0 , 48.0 , 90.0 , 25.0 ) ] ;
[ TextField setStringValue : ( NSString * ) FieldTextCFString ] ;
[ TextField setEditable : NO ] ;
[ TextField setBordered : NO ] ;
[ TextField setBackgroundColor : [ NSColor controlColor ] ] ;
PopUpButton = [ [ NSPopUpButton alloc ] initWithFrame : NSMakeRect ( 88.0 , 50.0 , 160.0 , 25.0 ) ] ;
[ PopUpButton setTarget : self ] ;
[ PopUpButton setAction : @ selector ( PopUpButtonAction : ) ] ;
[ self addSubview : TextField ] ;
[ self addSubview : PopUpButton ] ;
return self ;
}
- ( void ) AddAllowedFileTypes : ( NSMutableArray * ) array
{
check ( array ) ;
AllowedFileTypes = array ;
int32 ArrayCount = [ AllowedFileTypes count ] ;
if ( ArrayCount )
{
check ( ArrayCount % 2 = = 0 ) ;
[ PopUpButton removeAllItems ] ;
for ( int32 Index = 0 ; Index < ArrayCount ; Index + = 2 )
{
[ PopUpButton addItemWithTitle : [ AllowedFileTypes objectAtIndex : Index ] ] ;
}
// Set allowed extensions
[ self SetExtensionsAtIndex : 0 ] ;
}
else
{
// Allow all file types
[ DialogPanel setAllowedFileTypes : nil ] ;
}
}
- ( void ) PopUpButtonAction : ( id ) sender
{
NSInteger Index = [ PopUpButton indexOfSelectedItem ] ;
[ self SetExtensionsAtIndex : Index ] ;
}
- ( void ) SetExtensionsAtIndex : ( int32 ) index
{
check ( [ AllowedFileTypes count ] > = index * 2 ) ;
2014-10-30 13:21:40 -04:00
SelectedExtension = index ;
2014-03-14 14:13:41 -04:00
NSString * ExtsToParse = [ AllowedFileTypes objectAtIndex : index * 2 + 1 ] ;
if ( [ ExtsToParse compare : @ " *.* " ] = = NSOrderedSame )
{
[ DialogPanel setAllowedFileTypes : nil ] ;
}
else
{
NSArray * ExtensionsWildcards = [ ExtsToParse componentsSeparatedByString : @ " ; " ] ;
NSMutableArray * Extensions = [ NSMutableArray arrayWithCapacity : [ ExtensionsWildcards count ] ] ;
for ( int32 Index = 0 ; Index < [ ExtensionsWildcards count ] ; + + Index )
{
NSString * Temp = [[ExtensionsWildcards objectAtIndex:Index] stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"*."]] ;
[ Extensions addObject : Temp ] ;
}
[ DialogPanel setAllowedFileTypes : Extensions ] ;
}
}
2014-10-30 13:21:40 -04:00
- ( int32 ) SelectedExtension {
return SelectedExtension ;
}
2014-03-14 14:13:41 -04:00
@ end
/**
* Custom accessory view class to allow choose kind of file extension
*/
@ interface FFontDialogAccessoryView : NSView
{
@ private
NSButton * OKButton ;
NSButton * CancelButton ;
bool Result ;
}
- ( id ) initWithFrame : ( NSRect ) frameRect ;
- ( bool ) result ;
- ( IBAction ) onCancel : ( id ) sender ;
- ( IBAction ) onOK : ( id ) sender ;
@ end
@ implementation FFontDialogAccessoryView : NSView
- ( id ) initWithFrame : ( NSRect ) frameRect
{
[ super initWithFrame : frameRect ] ;
CancelButton = [ [ NSButton alloc ] initWithFrame : NSMakeRect ( 10 , 10 , 80 , 24 ) ] ;
[ CancelButton setTitle : @ " Cancel " ] ;
[ CancelButton setBezelStyle : NSRoundedBezelStyle ] ;
[ CancelButton setButtonType : NSMomentaryPushInButton ] ;
[ CancelButton setAction : @ selector ( onCancel : ) ] ;
[ CancelButton setTarget : self ] ;
[ self addSubview : CancelButton ] ;
OKButton = [ [ NSButton alloc ] initWithFrame : NSMakeRect ( 100 , 10 , 80 , 24 ) ] ;
[ OKButton setTitle : @ " OK " ] ;
[ OKButton setBezelStyle : NSRoundedBezelStyle ] ;
[ OKButton setButtonType : NSMomentaryPushInButton ] ;
[ OKButton setAction : @ selector ( onOK : ) ] ;
[ OKButton setTarget : self ] ;
[ self addSubview : OKButton ] ;
Result = false ;
return self ;
}
- ( bool ) result
{
return Result ;
}
- ( IBAction ) onCancel : ( id ) sender
{
Result = false ;
[ NSApp stopModal ] ;
}
- ( IBAction ) onOK : ( id ) sender
{
Result = true ;
[ NSApp stopModal ] ;
}
@ end
bool FDesktopPlatformMac : : OpenFileDialog ( const void * ParentWindowHandle , const FString & DialogTitle , const FString & DefaultPath , const FString & DefaultFile , const FString & FileTypes , uint32 Flags , TArray < FString > & OutFilenames )
{
2014-10-30 13:21:40 -04:00
int32 DummyIdx = 0 ;
return FileDialogShared ( false , ParentWindowHandle , DialogTitle , DefaultPath , DefaultFile , FileTypes , Flags , OutFilenames , DummyIdx ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-17 16:16:40 -04:00
bool FDesktopPlatformMac : : OpenFileDialog ( const void * ParentWindowHandle , const FString & DialogTitle , const FString & DefaultPath , const FString & DefaultFile , const FString & FileTypes , uint32 Flags , TArray < FString > & OutFilenames , int32 & OutFilterIndex )
{
2014-10-30 13:21:40 -04:00
return FileDialogShared ( false , ParentWindowHandle , DialogTitle , DefaultPath , DefaultFile , FileTypes , Flags , OutFilenames , OutFilterIndex ) ;
2014-06-17 16:16:40 -04:00
}
2014-03-14 14:13:41 -04:00
bool FDesktopPlatformMac : : SaveFileDialog ( const void * ParentWindowHandle , const FString & DialogTitle , const FString & DefaultPath , const FString & DefaultFile , const FString & FileTypes , uint32 Flags , TArray < FString > & OutFilenames )
{
2014-10-30 13:21:40 -04:00
int32 DummyIdx = 0 ;
return FileDialogShared ( true , ParentWindowHandle , DialogTitle , DefaultPath , DefaultFile , FileTypes , Flags , OutFilenames , DummyIdx ) ;
2014-03-14 14:13:41 -04:00
}
bool FDesktopPlatformMac : : OpenDirectoryDialog ( const void * ParentWindowHandle , const FString & DialogTitle , const FString & DefaultPath , FString & OutFolderName )
{
MacApplication - > SetCapture ( NULL ) ;
2014-08-19 11:21:24 -04:00
bool bSuccess = false ;
{
2014-09-26 14:32:24 -04:00
FMacScopedSystemModalMode SystemModalScope ;
2014-08-19 11:21:24 -04:00
bSuccess = MainThreadReturn ( ^ {
SCOPED_AUTORELEASE_POOL ;
FCocoaScopeContext ContextGuard ;
2014-03-14 14:13:41 -04:00
2014-08-19 11:21:24 -04:00
NSOpenPanel * Panel = [ NSOpenPanel openPanel ] ;
[ Panel setCanChooseFiles : false ] ;
[ Panel setCanChooseDirectories : true ] ;
[ Panel setAllowsMultipleSelection : false ] ;
[ Panel setCanCreateDirectories : true ] ;
2014-03-14 14:13:41 -04:00
2014-08-19 11:21:24 -04:00
CFStringRef Title = FPlatformString : : TCHARToCFString ( * DialogTitle ) ;
[ Panel setTitle : ( NSString * ) Title ] ;
CFRelease ( Title ) ;
2014-03-14 14:13:41 -04:00
2014-08-19 11:21:24 -04:00
CFStringRef DefaultPathCFString = FPlatformString : : TCHARToCFString ( * DefaultPath ) ;
NSURL * DefaultPathURL = [ NSURL fileURLWithPath : ( NSString * ) DefaultPathCFString ] ;
[ Panel setDirectoryURL : DefaultPathURL ] ;
CFRelease ( DefaultPathCFString ) ;
2014-03-14 14:13:41 -04:00
2015-02-23 16:18:13 -05:00
bool bResult = false ;
2014-03-14 14:13:41 -04:00
2014-08-19 10:46:30 -04:00
NSInteger Result = [ Panel runModal ] ;
2014-03-14 14:13:41 -04:00
2014-08-19 10:46:30 -04:00
if ( Result = = NSFileHandlingPanelOKButton )
{
NSURL * FolderURL = [ [ Panel URLs ] objectAtIndex : 0 ] ;
TCHAR FolderPath [ MAX_PATH ] ;
FPlatformString : : CFStringToTCHAR ( ( CFStringRef ) [ FolderURL path ] , FolderPath ) ;
OutFolderName = FolderPath ;
FPaths : : NormalizeFilename ( OutFolderName ) ;
2015-02-23 16:18:13 -05:00
bResult = true ;
2014-08-19 10:46:30 -04:00
}
2014-03-14 14:13:41 -04:00
2014-08-19 11:21:24 -04:00
[ Panel close ] ;
2014-03-14 14:13:41 -04:00
2015-02-23 16:18:13 -05:00
return bResult ;
2014-08-19 11:21:24 -04:00
} ) ;
}
2014-03-14 14:13:41 -04:00
MacApplication - > ResetModifierKeys ( ) ;
2014-08-19 10:46:30 -04:00
2014-03-14 14:13:41 -04:00
return bSuccess ;
}
2014-08-13 12:53:47 -04:00
bool FDesktopPlatformMac : : OpenFontDialog ( const void * ParentWindowHandle , FString & OutFontName , float & OutHeight , EFontImportFlags & OutFlags )
2014-03-14 14:13:41 -04:00
{
MacApplication - > SetCapture ( NULL ) ;
2014-08-19 10:46:30 -04:00
2014-08-19 11:21:24 -04:00
bool bSuccess = false ;
{
2014-09-26 14:32:24 -04:00
FMacScopedSystemModalMode SystemModalScope ;
2014-08-19 11:21:24 -04:00
bSuccess = MainThreadReturn ( ^ {
SCOPED_AUTORELEASE_POOL ;
FCocoaScopeContext ContextGuard ;
2014-03-14 14:13:41 -04:00
2014-08-19 11:21:24 -04:00
NSFontPanel * Panel = [ NSFontPanel sharedFontPanel ] ;
[ Panel setFloatingPanel : false ] ;
[ [ Panel standardWindowButton : NSWindowCloseButton ] setEnabled : false ] ;
FFontDialogAccessoryView * AccessoryView = [ [ FFontDialogAccessoryView alloc ] initWithFrame : NSMakeRect ( 0.0 , 0.0 , 190.0 , 80.0 ) ] ;
[ Panel setAccessoryView : AccessoryView ] ;
2014-03-14 14:13:41 -04:00
2014-08-19 10:46:30 -04:00
[ NSApp runModalForWindow : Panel ] ;
2014-08-19 11:21:24 -04:00
[ Panel close ] ;
2014-03-14 14:13:41 -04:00
2015-02-23 16:18:13 -05:00
bool bResult = [ AccessoryView result ] ;
2014-03-14 14:13:41 -04:00
2014-08-19 11:21:24 -04:00
[ Panel setAccessoryView : NULL ] ;
[ AccessoryView release ] ;
[ [ Panel standardWindowButton : NSWindowCloseButton ] setEnabled : true ] ;
2014-08-19 10:46:30 -04:00
2015-02-23 16:18:13 -05:00
if ( bResult )
2014-08-19 10:46:30 -04:00
{
2014-08-19 11:21:24 -04:00
NSFont * Font = [ Panel panelConvertFont : [ NSFont userFontOfSize : 0 ] ] ;
TCHAR FontName [ MAX_PATH ] ;
FPlatformString : : CFStringToTCHAR ( ( CFStringRef ) [ Font fontName ] , FontName ) ;
OutFontName = FontName ;
OutHeight = [ Font pointSize ] ;
auto FontFlags = EFontImportFlags : : None ;
if ( [ Font underlineThickness ] > = 1.0 )
{
FontFlags | = EFontImportFlags : : EnableUnderline ;
}
OutFlags = FontFlags ;
2014-08-19 10:46:30 -04:00
}
2015-02-23 16:18:13 -05:00
return bResult ;
2014-08-19 11:21:24 -04:00
} ) ;
}
2014-08-19 10:46:30 -04:00
2014-03-14 14:13:41 -04:00
MacApplication - > ResetModifierKeys ( ) ;
2014-08-19 10:46:30 -04:00
2014-03-14 14:13:41 -04:00
return bSuccess ;
}
2014-08-19 09:54:22 -04:00
bool FDesktopPlatformMac : : CanOpenLauncher ( bool Install )
{
FString Path ;
2015-08-04 14:03:25 -04:00
return IsLauncherInstalled ( ) | | ( Install & & GetLauncherInstallerPath ( Path ) ) ;
2014-08-19 09:54:22 -04:00
}
2016-01-22 08:13:18 -05:00
bool FDesktopPlatformMac : : OpenLauncher ( const FOpenLauncherOptions & Options )
2014-03-14 14:13:41 -04:00
{
2016-01-22 08:13:18 -05:00
FString LauncherUriRequest = Options . GetLauncherUriRequest ( ) ;
2015-09-11 17:47:50 -04:00
2014-04-02 18:09:23 -04:00
// If the launcher is already running, bring it to front
2015-07-31 10:13:42 -04:00
NSArray * RunningLaunchers = [ NSRunningApplication runningApplicationsWithBundleIdentifier : @ " com.epicgames.EpicGamesLauncher " ] ;
if ( [ RunningLaunchers count ] = = 0 )
{
RunningLaunchers = [ NSRunningApplication runningApplicationsWithBundleIdentifier : @ " com.epicgames.UnrealEngineLauncher " ] ;
}
2015-08-04 14:03:25 -04:00
2014-04-02 18:09:23 -04:00
if ( [ RunningLaunchers count ] > 0 )
{
NSRunningApplication * Launcher = [ RunningLaunchers objectAtIndex : 0 ] ;
2016-01-22 08:13:18 -05:00
if ( ! Launcher . hidden | | Options . bInstall ) // If the launcher is running, but hidden, don't activate on editor startup
2014-10-03 08:54:52 -04:00
{
2015-08-04 14:03:25 -04:00
[ Launcher activateWithOptions : NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps ] ;
2015-09-11 17:47:50 -04:00
FString Error ;
2016-01-22 08:13:18 -05:00
FPlatformProcess : : LaunchURL ( * LauncherUriRequest , nullptr , & Error ) ;
2014-10-03 08:54:52 -04:00
}
2015-09-11 17:47:50 -04:00
return true ;
2014-04-02 18:09:23 -04:00
}
2015-08-04 14:03:25 -04:00
if ( IsLauncherInstalled ( ) )
2014-03-14 14:13:41 -04:00
{
2015-08-04 14:03:25 -04:00
FString Error ;
2016-01-22 08:13:18 -05:00
FPlatformProcess : : LaunchURL ( * LauncherUriRequest , nullptr , & Error ) ;
2015-08-04 14:03:25 -04:00
return true ;
2014-03-14 14:13:41 -04:00
}
2014-08-19 09:54:22 -04:00
// Try to install it
FString InstallerPath ;
2015-08-04 14:03:25 -04:00
if ( GetLauncherInstallerPath ( InstallerPath ) )
2014-03-14 14:13:41 -04:00
{
2014-08-19 09:54:22 -04:00
FPlatformProcess : : LaunchFileInDefaultExternalApplication ( * InstallerPath ) ;
return true ;
2014-03-14 14:13:41 -04:00
}
2014-08-19 09:54:22 -04:00
return false ;
2014-03-14 14:13:41 -04:00
}
2014-10-30 13:21:40 -04:00
bool FDesktopPlatformMac : : FileDialogShared ( bool bSave , const void * ParentWindowHandle , const FString & DialogTitle , const FString & DefaultPath , const FString & DefaultFile , const FString & FileTypes , uint32 Flags , TArray < FString > & OutFilenames , int32 & OutFilterIndex )
2014-03-14 14:13:41 -04:00
{
MacApplication - > SetCapture ( NULL ) ;
2014-08-19 11:21:24 -04:00
bool bSuccess = false ;
{
2014-09-26 14:32:24 -04:00
FMacScopedSystemModalMode SystemModalScope ;
2014-08-19 11:21:24 -04:00
bSuccess = MainThreadReturn ( ^ {
SCOPED_AUTORELEASE_POOL ;
FCocoaScopeContext ContextGuard ;
2014-03-14 14:13:41 -04:00
2014-08-19 11:21:24 -04:00
NSSavePanel * Panel = bSave ? [ NSSavePanel savePanel ] : [ NSOpenPanel openPanel ] ;
2014-03-14 14:13:41 -04:00
2014-08-19 11:21:24 -04:00
if ( ! bSave )
2014-03-14 14:13:41 -04:00
{
2014-08-19 11:21:24 -04:00
NSOpenPanel * OpenPanel = ( NSOpenPanel * ) Panel ;
[ OpenPanel setCanChooseFiles : true ] ;
[ OpenPanel setCanChooseDirectories : false ] ;
[ OpenPanel setAllowsMultipleSelection : Flags & EFileDialogFlags : : Multiple ] ;
2014-03-14 14:13:41 -04:00
}
2014-08-19 10:46:30 -04:00
2014-08-19 11:21:24 -04:00
[ Panel setCanCreateDirectories : bSave ] ;
2014-08-19 10:46:30 -04:00
2014-08-19 11:21:24 -04:00
CFStringRef Title = FPlatformString : : TCHARToCFString ( * DialogTitle ) ;
[ Panel setTitle : ( NSString * ) Title ] ;
CFRelease ( Title ) ;
2014-08-19 10:46:30 -04:00
2014-08-19 11:21:24 -04:00
CFStringRef DefaultPathCFString = FPlatformString : : TCHARToCFString ( * DefaultPath ) ;
NSURL * DefaultPathURL = [ NSURL fileURLWithPath : ( NSString * ) DefaultPathCFString ] ;
[ Panel setDirectoryURL : DefaultPathURL ] ;
CFRelease ( DefaultPathCFString ) ;
CFStringRef FileNameCFString = FPlatformString : : TCHARToCFString ( * DefaultFile ) ;
[ Panel setNameFieldStringValue : ( NSString * ) FileNameCFString ] ;
CFRelease ( FileNameCFString ) ;
FFileDialogAccessoryView * AccessoryView = [ [ FFileDialogAccessoryView alloc ] initWithFrame : NSMakeRect ( 0.0 , 0.0 , 250.0 , 85.0 ) dialogPanel : Panel ] ;
[ Panel setAccessoryView : AccessoryView ] ;
TArray < FString > FileTypesArray ;
2015-03-02 15:51:37 -05:00
int32 NumFileTypes = FileTypes . ParseIntoArray ( FileTypesArray , TEXT ( " | " ) , true ) ;
2014-08-19 11:21:24 -04:00
NSMutableArray * AllowedFileTypes = [ NSMutableArray arrayWithCapacity : NumFileTypes ] ;
if ( NumFileTypes > 0 )
{
for ( int32 Index = 0 ; Index < NumFileTypes ; + + Index )
{
CFStringRef Type = FPlatformString : : TCHARToCFString ( * FileTypesArray [ Index ] ) ;
[ AllowedFileTypes addObject : ( NSString * ) Type ] ;
CFRelease ( Type ) ;
}
}
[ AccessoryView AddAllowedFileTypes : AllowedFileTypes ] ;
2015-02-23 16:18:13 -05:00
bool bOkPressed = false ;
2014-08-19 11:21:24 -04:00
NSWindow * FocusWindow = [ [ NSApplication sharedApplication ] keyWindow ] ;
2014-08-19 10:46:30 -04:00
NSInteger Result = [ Panel runModal ] ;
[ AccessoryView release ] ;
if ( Result = = NSFileHandlingPanelOKButton )
2014-03-14 14:13:41 -04:00
{
2014-08-19 10:46:30 -04:00
if ( bSave )
2014-03-14 14:13:41 -04:00
{
TCHAR FilePath [ MAX_PATH ] ;
2014-08-19 10:46:30 -04:00
FPlatformString : : CFStringToTCHAR ( ( CFStringRef ) [ [ Panel URL ] path ] , FilePath ) ;
2014-03-14 14:13:41 -04:00
new ( OutFilenames ) FString ( FilePath ) ;
}
2014-08-19 10:46:30 -04:00
else
{
NSOpenPanel * OpenPanel = ( NSOpenPanel * ) Panel ;
for ( NSURL * FileURL in [ OpenPanel URLs ] )
{
TCHAR FilePath [ MAX_PATH ] ;
FPlatformString : : CFStringToTCHAR ( ( CFStringRef ) [ FileURL path ] , FilePath ) ;
new ( OutFilenames ) FString ( FilePath ) ;
}
2014-10-30 13:21:40 -04:00
OutFilterIndex = [ AccessoryView SelectedExtension ] ;
2014-08-19 10:46:30 -04:00
}
2014-03-14 14:13:41 -04:00
2015-05-26 15:22:25 -04:00
// Make sure all filenames gathered have their paths normalized
2015-05-26 10:51:18 -04:00
for ( auto OutFilenameIt = OutFilenames . CreateIterator ( ) ; OutFilenameIt ; + + OutFilenameIt )
2014-08-19 10:46:30 -04:00
{
2015-05-26 10:51:18 -04:00
FString & OutFilename = * OutFilenameIt ;
OutFilename = IFileManager : : Get ( ) . ConvertToRelativePath ( * OutFilename ) ;
FPaths : : NormalizeFilename ( OutFilename ) ;
2014-08-19 10:46:30 -04:00
}
2014-03-14 14:13:41 -04:00
2015-02-23 16:18:13 -05:00
bOkPressed = true ;
2014-08-19 10:46:30 -04:00
}
2014-03-14 14:13:41 -04:00
2014-08-19 11:21:24 -04:00
[ Panel close ] ;
if ( FocusWindow )
{
[ FocusWindow makeKeyWindow ] ;
}
2014-03-14 14:13:41 -04:00
2015-02-23 16:18:13 -05:00
return bOkPressed ;
2014-08-19 11:21:24 -04:00
} ) ;
}
2014-06-13 11:09:48 -04:00
2014-08-19 10:46:30 -04:00
MacApplication - > ResetModifierKeys ( ) ;
2014-03-14 14:13:41 -04:00
return bSuccess ;
}
2014-05-06 10:27:35 -04:00
bool FDesktopPlatformMac : : RegisterEngineInstallation ( const FString & RootDir , FString & OutIdentifier )
{
2014-05-13 10:10:18 -04:00
bool bRes = false ;
if ( IsValidRootDirectory ( RootDir ) )
{
FConfigFile ConfigFile ;
FString ConfigPath = FString ( FPlatformProcess : : ApplicationSettingsDir ( ) ) / FString ( TEXT ( " UnrealEngine " ) ) / FString ( TEXT ( " Install.ini " ) ) ;
ConfigFile . Read ( ConfigPath ) ;
FConfigSection & Section = ConfigFile . FindOrAdd ( TEXT ( " Installations " ) ) ;
2015-07-28 16:24:16 -04:00
OutIdentifier = FGuid : : NewGuid ( ) . ToString ( EGuidFormats : : DigitsWithHyphensInBraces ) ;
2014-05-13 10:10:18 -04:00
Section . AddUnique ( * OutIdentifier , RootDir ) ;
ConfigFile . Dirty = true ;
ConfigFile . Write ( ConfigPath ) ;
}
return bRes ;
2014-05-06 10:27:35 -04:00
}
2014-04-23 18:32:52 -04:00
void FDesktopPlatformMac : : EnumerateEngineInstallations ( TMap < FString , FString > & OutInstallations )
{
2015-03-13 08:26:18 -04:00
SCOPED_AUTORELEASE_POOL ;
2014-04-23 18:46:48 -04:00
EnumerateLauncherEngineInstallations ( OutInstallations ) ;
2014-04-23 18:59:02 -04:00
// Create temp .uproject file to use with LSCopyApplicationURLsForURL
2014-04-23 20:16:56 -04:00
FString UProjectPath = FString ( FPlatformProcess : : ApplicationSettingsDir ( ) ) / " Unreal.uproject " ;
2014-04-23 18:59:02 -04:00
FArchive * File = IFileManager : : Get ( ) . CreateFileWriter ( * UProjectPath , FILEWRITE_EvenIfReadOnly ) ;
if ( File )
{
File - > Close ( ) ;
delete File ;
}
else
{
2014-07-30 14:51:27 -04:00
FPlatformMisc : : MessageBoxExt ( EAppMsgType : : Ok , * UProjectPath , TEXT ( " Error " ) ) ;
2014-04-23 18:59:02 -04:00
}
FConfigFile ConfigFile ;
FString ConfigPath = FString ( FPlatformProcess : : ApplicationSettingsDir ( ) ) / FString ( TEXT ( " UnrealEngine " ) ) / FString ( TEXT ( " Install.ini " ) ) ;
ConfigFile . Read ( ConfigPath ) ;
FConfigSection & Section = ConfigFile . FindOrAdd ( TEXT ( " Installations " ) ) ;
2014-08-08 11:33:23 -04:00
// Remove invalid entries
TArray < FName > KeysToRemove ;
for ( auto It : Section )
{
2016-03-29 16:33:59 -04:00
const FString & EngineDir = It . Value . GetValue ( ) ;
2014-11-17 14:59:07 -05:00
if ( EngineDir . Contains ( " Unreal Engine.app/Contents/ " ) | | EngineDir . Contains ( " Epic Games Launcher.app/Contents/ " ) | | EngineDir . Contains ( " /Users/Shared/UnrealEngine/Launcher " ) | | ! IFileManager : : Get ( ) . DirectoryExists ( * EngineDir ) )
2014-08-08 11:33:23 -04:00
{
KeysToRemove . Add ( It . Key ) ;
}
}
for ( auto Key : KeysToRemove )
{
Section . Remove ( Key ) ;
}
2014-04-23 18:59:02 -04:00
CFArrayRef AllApps = LSCopyApplicationURLsForURL ( ( __bridge CFURLRef ) [ NSURL fileURLWithPath : UProjectPath . GetNSString ( ) ] , kLSRolesAll ) ;
if ( AllApps )
{
const CFIndex AppsCount = CFArrayGetCount ( AllApps ) ;
for ( CFIndex Index = 0 ; Index < AppsCount ; + + Index )
{
NSURL * AppURL = ( NSURL * ) CFArrayGetValueAtIndex ( AllApps , Index ) ;
NSBundle * AppBundle = [ NSBundle bundleWithURL : AppURL ] ;
FString EngineDir = FString ( [ [ AppBundle bundlePath ] stringByDeletingLastPathComponent ] ) ;
if ( ( [ [ AppBundle bundleIdentifier ] isEqualToString : @ " com.epicgames.UE4Editor " ] | | [ [ AppBundle bundleIdentifier ] isEqualToString : @ " com.epicgames.UE4EditorServices " ] )
2014-11-17 14:59:07 -05:00
& & EngineDir . RemoveFromEnd ( TEXT ( " /Engine/Binaries/Mac " ) ) & & ! EngineDir . Contains ( " Unreal Engine.app/Contents/ " ) & & ! EngineDir . Contains ( " Epic Games Launcher.app/Contents/ " ) & & ! EngineDir . Contains ( " /Users/Shared/UnrealEngine/Launcher " ) )
2014-04-23 18:59:02 -04:00
{
FString EngineId ;
const FName * Key = Section . FindKey ( EngineDir ) ;
if ( Key )
{
2015-07-28 16:24:16 -04:00
FGuid IdGuid ;
FGuid : : Parse ( Key - > ToString ( ) , IdGuid ) ;
EngineId = IdGuid . ToString ( EGuidFormats : : DigitsWithHyphensInBraces ) ; ;
2014-04-23 18:59:02 -04:00
}
else
{
if ( ! OutInstallations . FindKey ( EngineDir ) )
{
2014-08-27 15:29:01 -04:00
EngineId = FGuid : : NewGuid ( ) . ToString ( EGuidFormats : : DigitsWithHyphensInBraces ) ;
2014-04-23 18:59:02 -04:00
Section . AddUnique ( * EngineId , EngineDir ) ;
ConfigFile . Dirty = true ;
}
}
if ( ! EngineId . IsEmpty ( ) & & ! OutInstallations . Find ( EngineId ) )
{
OutInstallations . Add ( EngineId , EngineDir ) ;
}
}
}
ConfigFile . Write ( ConfigPath ) ;
CFRelease ( AllApps ) ;
}
IFileManager : : Get ( ) . Delete ( * UProjectPath ) ;
2014-04-23 18:46:48 -04:00
}
2014-04-23 18:48:24 -04:00
bool FDesktopPlatformMac : : VerifyFileAssociations ( )
2014-04-23 18:46:48 -04:00
{
2014-04-23 18:59:02 -04:00
CFURLRef GlobalDefaultAppURL = NULL ;
OSStatus Status = LSGetApplicationForInfo ( kLSUnknownType , kLSUnknownCreator , CFSTR ( " uproject " ) , kLSRolesAll , NULL , & GlobalDefaultAppURL ) ;
if ( Status = = noErr )
{
NSBundle * GlobalDefaultAppBundle = [ NSBundle bundleWithURL : ( __bridge NSURL * ) GlobalDefaultAppURL ] ;
CFRelease ( GlobalDefaultAppURL ) ;
2014-06-20 13:37:52 -04:00
if ( [ [ GlobalDefaultAppBundle bundleIdentifier ] isEqualToString : @ " com.epicgames.UE4EditorServices " ] )
2014-04-23 18:59:02 -04:00
{
return true ;
}
}
return false ;
2014-04-23 18:46:48 -04:00
}
2014-04-23 18:48:24 -04:00
bool FDesktopPlatformMac : : UpdateFileAssociations ( )
2014-04-23 18:46:48 -04:00
{
2014-04-23 18:59:02 -04:00
OSStatus Status = LSSetDefaultRoleHandlerForContentType ( CFSTR ( " com.epicgames.uproject " ) , kLSRolesAll , CFSTR ( " com.epicgames.UE4EditorServices " ) ) ;
return Status = = noErr ;
2014-04-23 18:32:52 -04:00
}
2014-05-13 18:23:53 -04:00
bool FDesktopPlatformMac : : RunUnrealBuildTool ( const FText & Description , const FString & RootDir , const FString & Arguments , FFeedbackContext * Warn )
{
// Get the path to UBT
FString UnrealBuildToolPath = RootDir / TEXT ( " Engine/Binaries/DotNET/UnrealBuildTool.exe " ) ;
if ( IFileManager : : Get ( ) . FileSize ( * UnrealBuildToolPath ) < 0 )
{
Warn - > Logf ( ELogVerbosity : : Error , TEXT ( " Couldn't find UnrealBuildTool at '%s' " ) , * UnrealBuildToolPath ) ;
return false ;
}
// On Mac we launch UBT with Mono
FString ScriptPath = FPaths : : ConvertRelativePathToFull ( RootDir / TEXT ( " Engine/Build/BatchFiles/Mac/RunMono.sh " ) ) ;
FString CmdLineParams = FString : : Printf ( TEXT ( " \" %s \" \" %s \" %s " ) , * ScriptPath , * UnrealBuildToolPath , * Arguments ) ;
// Spawn it
int32 ExitCode = 0 ;
return FFeedbackContextMarkup : : PipeProcessOutput ( Description , TEXT ( " /bin/sh " ) , CmdLineParams , Warn , & ExitCode ) & & ExitCode = = 0 ;
}
2014-09-18 15:12:13 -04:00
bool FDesktopPlatformMac : : IsUnrealBuildToolRunning ( )
{
// For now assume that if mono application is running, we're running UBT
// @todo: we need to get the commandline for the mono process and check if UBT.exe is in there.
return FPlatformProcess : : IsApplicationRunning ( TEXT ( " mono " ) ) ;
}
2014-08-19 09:54:22 -04:00
2015-08-04 14:03:25 -04:00
bool FDesktopPlatformMac : : IsLauncherInstalled ( ) const
2014-08-19 09:54:22 -04:00
{
// Otherwise search for it...
NSWorkspace * Workspace = [ NSWorkspace sharedWorkspace ] ;
2014-11-17 14:59:07 -05:00
NSString * Path = [ Workspace fullPathForApplication : @ " Epic Games Launcher " ] ;
2014-08-19 09:54:22 -04:00
if ( Path )
{
return true ;
}
2015-01-07 09:26:48 -05:00
// Otherwise search for the old Launcher...
Path = [ Workspace fullPathForApplication : @ " Unreal Engine " ] ;
if ( Path )
{
return true ;
}
2014-08-19 09:54:22 -04:00
return false ;
}
bool FDesktopPlatformMac : : GetLauncherInstallerPath ( FString & OutInstallerPath ) const
{
// Check if the installer exists
2014-11-17 14:59:07 -05:00
FString InstallerPath = FPaths : : ConvertRelativePathToFull ( FPaths : : Combine ( * FPaths : : EngineDir ( ) , TEXT ( " Extras/UnrealEngineLauncher/EpicGamesLauncher.dmg " ) ) ) ;
2014-08-19 09:54:22 -04:00
if ( FPaths : : FileExists ( InstallerPath ) )
{
OutInstallerPath = InstallerPath ;
return true ;
}
2015-01-07 09:26:48 -05:00
InstallerPath = FPaths : : ConvertRelativePathToFull ( FPaths : : Combine ( * FPaths : : EngineDir ( ) , TEXT ( " Extras/UnrealEngineLauncher/UnrealEngine.dmg " ) ) ) ;
if ( FPaths : : FileExists ( InstallerPath ) )
{
OutInstallerPath = InstallerPath ;
return true ;
}
2014-08-19 09:54:22 -04:00
return false ;
}
2014-05-14 14:53:19 -04:00
FFeedbackContext * FDesktopPlatformMac : : GetNativeFeedbackContext ( )
{
2014-05-14 18:56:27 -04:00
static FMacNativeFeedbackContext Warn ;
return & Warn ;
2014-05-14 14:53:19 -04:00
}
2015-01-16 13:29:54 -05:00
FString FDesktopPlatformMac : : GetUserTempPath ( )
{
2015-01-16 16:20:36 -05:00
return FString ( FPlatformProcess : : UserTempDir ( ) ) ;
2015-01-16 13:29:54 -05:00
}
2014-03-14 14:13:41 -04:00
# undef LOCTEXT_NAMESPACE