#define COM_GUIDS_MATERIALIZE
#include "common.h"
#include "menu.h"
static NSString* s_appTitle = @"Ferro";
static int disableSetProcessName = 0;
static bool disableAppDelegate = false;
void SetProcessName(NSString* appTitle) {
s_appTitle = appTitle;
CFStringRef process_name = (__bridge CFStringRef)appTitle;
if (!process_name || CFStringGetLength(process_name) == 0) {
return;
}
if (![NSThread isMainThread]) {
return;
}
typedef CFTypeRef PrivateLSASN;
typedef PrivateLSASN (*LSGetCurrentApplicationASNType)();
typedef OSStatus (*LSSetApplicationInformationItemType)(int, PrivateLSASN,
CFStringRef,
CFStringRef,
CFDictionaryRef*);
static LSGetCurrentApplicationASNType ls_get_current_application_asn_func =
NULL;
static LSSetApplicationInformationItemType
ls_set_application_information_item_func = NULL;
static CFStringRef ls_display_name_key = NULL;
static bool did_symbol_lookup = false;
if (!did_symbol_lookup) {
did_symbol_lookup = true;
CFBundleRef launch_services_bundle =
CFBundleGetBundleWithIdentifier(CFSTR("com.apple.LaunchServices"));
if (!launch_services_bundle) {
return;
}
ls_get_current_application_asn_func =
reinterpret_cast<LSGetCurrentApplicationASNType>(
CFBundleGetFunctionPointerForName(
launch_services_bundle, CFSTR("_LSGetCurrentApplicationASN")));
if (!ls_get_current_application_asn_func){}
ls_set_application_information_item_func =
reinterpret_cast<LSSetApplicationInformationItemType>(
CFBundleGetFunctionPointerForName(
launch_services_bundle,
CFSTR("_LSSetApplicationInformationItem")));
if (!ls_set_application_information_item_func){}
CFStringRef* key_pointer = reinterpret_cast<CFStringRef*>(
CFBundleGetDataPointerForName(launch_services_bundle,
CFSTR("_kLSDisplayNameKey")));
ls_display_name_key = key_pointer ? *key_pointer : NULL;
if (!ls_display_name_key){}
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
}
if (!ls_get_current_application_asn_func ||
!ls_set_application_information_item_func ||
!ls_display_name_key) {
return;
}
PrivateLSASN asn = ls_get_current_application_asn_func();
const int magic_session_constant = -2;
ls_set_application_information_item_func(magic_session_constant, asn,
ls_display_name_key,
process_name,
NULL );
}
class MacOptions : public ComSingleObject<IFrnMacOptions, &IID_IFrnMacOptions>
{
public:
FORWARD_IUNKNOWN()
virtual HRESULT SetApplicationTitle(char* utf8String) override
{
START_COM_CALL;
@autoreleasepool
{
auto appTitle = [NSString stringWithUTF8String: utf8String];
if (disableSetProcessName == 0)
{
[[NSProcessInfo processInfo] setProcessName:appTitle];
SetProcessName(appTitle);
}
if (disableSetProcessName == 1)
{
auto rootMenu = [NSApp mainMenu];
[rootMenu setTitle:appTitle];
}
return S_OK;
}
}
virtual HRESULT SetShowInDock(int show) override
{
START_COM_CALL;
@autoreleasepool
{
NSApplication* app = [NSApplication sharedApplication];
NSApplicationActivationPolicy requestedPolicy = show
? NSApplicationActivationPolicyRegular
: NSApplicationActivationPolicyAccessory;
if ([app activationPolicy] != requestedPolicy)
{
[app setActivationPolicy:requestedPolicy];
}
return S_OK;
}
}
virtual HRESULT SetDisableSetProcessName(int disable) override
{
START_COM_CALL;
@autoreleasepool
{
disableSetProcessName = disable;
return S_OK;
}
}
virtual HRESULT SetDisableAppDelegate(int disable) override
{
START_COM_CALL;
@autoreleasepool {
disableAppDelegate = disable;
return S_OK;
}
}
};
@interface ThreadingInitializer : NSObject
- (void) do;
@end
@implementation ThreadingInitializer
{
int _fds[2];
}
- (void) runOnce
{
char buf[]={0};
write(_fds[1], buf, 1);
}
- (void) do
{
pipe(_fds);
[[[NSThread alloc] initWithTarget:self selector:@selector(runOnce) object:nil] start];
char buf[1];
read(_fds[0], buf, 1);
close(_fds[0]);
close(_fds[1]);
}
@end
static ComPtr<IFrnGCHandleDeallocatorCallback> _deallocator;
static ComPtr<IFrnDispatcher> _dispatcher;
class FerroNative : public ComSingleObject<IFerroNativeFactory, &IID_IFerroNativeFactory>
{
public:
FORWARD_IUNKNOWN()
virtual ~FerroNative() override
{
ReleaseFrnAppEvents();
_deallocator = nullptr;
_dispatcher = nullptr;
}
virtual HRESULT Initialize(IFrnGCHandleDeallocatorCallback* deallocator,
IFrnApplicationEvents* events,
IFrnDispatcher* dispatcher) override
{
START_COM_CALL;
_deallocator = deallocator;
_dispatcher = dispatcher;
@autoreleasepool{
[[ThreadingInitializer new] do];
}
InitializeFrnApp(events, disableAppDelegate);
return S_OK;
};
virtual IFrnMacOptions* GetMacOptions() override
{
return (IFrnMacOptions*)new MacOptions();
}
virtual HRESULT CreateTopLevel(IFrnTopLevelEvents* cb,
IFrnTopLevel** ppv) override {
START_COM_CALL;
@autoreleasepool
{
if(cb == nullptr || ppv == nullptr)
return E_POINTER;
*ppv = CreateFrnTopLevel(cb);
return S_OK;
}
}
virtual HRESULT CreateWindow(IFrnWindowEvents* cb, IFrnWindow** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
if(cb == nullptr || ppv == nullptr)
return E_POINTER;
*ppv = CreateFrnWindow(cb);
return S_OK;
}
};
virtual HRESULT CreatePopup(IFrnWindowEvents* cb, IFrnPopup** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
if(cb == nullptr || ppv == nullptr)
return E_POINTER;
*ppv = CreateFrnPopup(cb);
return S_OK;
}
}
virtual HRESULT CreatePlatformThreadingInterface(IFrnPlatformThreadingInterface** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = CreatePlatformThreading();
return S_OK;
}
}
virtual HRESULT CreateStorageProvider(IFrnStorageProvider** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreateStorageProvider();
return S_OK;
}
}
virtual HRESULT CreateScreens (IFrnScreenEvents* cb, IFrnScreens** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreateScreens (cb);
return S_OK;
}
}
virtual HRESULT CreateClipboard(IFrnClipboard** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreateClipboard(nil);
return S_OK;
}
}
virtual HRESULT CreateCursorFactory(IFrnCursorFactory** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreateCursorFactory();
return S_OK;
}
}
virtual HRESULT ObtainGlDisplay(IFrnGlDisplay** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
auto rv = ::GetGlDisplay();
if(rv == NULL)
return E_FAIL;
rv->AddRef();
*ppv = rv;
return S_OK;
}
}
virtual HRESULT ObtainMetalDisplay(IFrnMetalDisplay** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
auto rv = ::GetMetalDisplay();
if(rv == NULL)
return E_FAIL;
rv->AddRef();
*ppv = rv;
return S_OK;
}
}
virtual HRESULT CreateTrayIcon (IFrnTrayIcon** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreateTrayIcon();
return S_OK;
}
}
virtual HRESULT CreateMenu (IFrnMenuEvents* cb, IFrnMenu** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreateAppMenu(cb);
return S_OK;
}
}
virtual HRESULT CreateMenuItem (IFrnMenuItem** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreateAppMenuItem();
return S_OK;
}
}
virtual HRESULT CreateMenuItemSeparator (IFrnMenuItem** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreateAppMenuItemSeparator();
return S_OK;
}
}
virtual HRESULT SetAppMenu (IFrnMenu* appMenu) override
{
START_COM_CALL;
@autoreleasepool
{
::SetAppMenu(appMenu);
return S_OK;
}
}
virtual HRESULT SetServicesMenu (IFrnMenu* servicesMenu) override
{
START_COM_CALL;
@autoreleasepool
{
::SetServicesMenu(servicesMenu);
return S_OK;
}
}
virtual HRESULT CreateApplicationCommands (IFrnApplicationCommands** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreateApplicationCommands();
return S_OK;
}
}
virtual HRESULT CreatePlatformSettings (IFrnPlatformSettings** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreatePlatformSettings();
return S_OK;
}
}
virtual HRESULT CreatePlatformBehaviorInhibition(IFrnPlatformBehaviorInhibition** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreatePlatformBehaviorInhibition();
return S_OK;
}
}
virtual HRESULT CreatePlatformRenderTimer(IFrnPlatformRenderTimer** ppv) override
{
START_COM_CALL;
@autoreleasepool
{
*ppv = ::CreatePlatformRenderTimer();
return S_OK;
}
}
virtual HRESULT ImportMTLSharedEvent(void* event, IFrnMTLSharedEvent** ppv) override
{
START_COM_CALL;
*ppv = ::ImportMTLSharedEvent(event);
return *ppv != nullptr ? S_OK : E_FAIL;
}
HRESULT CreateMemoryManagementHelper(IFrnNativeObjectsMemoryManagement **ppv) override {
START_COM_CALL;
*ppv = ::CreateMemoryManagementHelper();
return S_OK;
}
virtual HRESULT SetDockMenu(IFrnMenu* dockMenu) override
{
START_COM_CALL;
@autoreleasepool
{
auto nativeMenu = dynamic_cast<FrnAppMenu*>(dockMenu);
::SetDockMenu(nativeMenu != nullptr ? nativeMenu->GetNative() : nil);
return S_OK;
}
}
};
extern "C" IFerroNativeFactory* CreateFerroNative()
{
return new FerroNative();
};
extern void FreeFrnGCHandle(void* handle)
{
if(_deallocator != nil)
_deallocator->FreeGCHandle(handle);
}
extern void PostDispatcherCallback(IFrnActionCallback* cb)
{
_dispatcher->Post(cb);
}
NSSize ToNSSize (FrnSize s)
{
NSSize result;
result.width = s.Width;
result.height = s.Height;
return result;
}
FrnSize FromNSSize (NSSize s)
{
FrnSize result;
result.Width = s.width;
result.Height = s.height;
return result;
}
NSPoint ToNSPoint (FrnPoint p)
{
NSPoint result;
result.x = p.X;
result.y = p.Y;
return result;
}
NSRect ToNSRect (FrnRect r)
{
return NSRect
{
NSPoint { r.X, r.Y },
NSSize { r.Width, r.Height }
};
}
FrnPoint ToFrnPoint (NSPoint p)
{
FrnPoint result;
result.X = p.x;
result.Y = p.y;
return result;
}
FrnPoint ConvertPointY (FrnPoint p)
{
auto primaryDisplayHeight = NSMaxY([[[NSScreen screens] firstObject] frame]);
p.Y = primaryDisplayHeight - p.Y;
return p;
}