How to use NSPrincipalClass in a Firemonkey app for MacOS?


Chromium requires implementing a protocol to know when NSApplication.sendEvent was called and we have solved this in Lazarus by creating a new class that inherits from NSApplication and then using NSPrincipalClass with the name of the new class but we are having difficulties trying to do the same in Firemonkey.
We have found a workaround in CEF4Delphi but it would be much better if we can implement it correctly.
This is the new unit with a simple NSApplication replacement we tried :
unit uNSApplicationEx;


System.Typinfo, Macapi.ObjectiveC, Macapi.AppKit;

NSApplicationEx = interface(NSApplication)
procedure sendEvent(theEvent: NSEvent); cdecl;

TNSApplicationEx = class(TOCLocal)
constructor Create;
procedure sendEvent(theEvent: NSEvent); cdecl;


constructor TNSApplicationEx.Create;
// This is only used with a breakpoint to see if it’s created.

procedure TNSApplicationEx.sendEvent(theEvent: NSEvent);
// We would add more code here. This is just a minimum code sample.

RegisterObjectiveCClass(TNSApplicationEx, TypeInfo(NSApplicationEx));


After that we added "NSPrincipalClass" key with a "TNSApplicationEx" value in the "Version Info" section of the project options.
It seems to be registered correctly but a breakpoint at the creation procedure isn’t triggered.
Is NSPrincipalClass supported by Delphi?
If so, what changes would be necessary to use TNSApplicationEx with NSPrincipalClass?
Edit : This is what the Lazarus class looks like. Lazarus has a much different Objective-C bridge than Delphi and this unit includes the CrAppProtocol and CrAppControlProtocol protocols required by Chromium. It also has some code to get the native key code used by the browser in off-screen mode. The LPI file of some Lazarus demos set NSPrincipalClass to the new TCrCocoaApplication class.
Edit 2 : The current workaround in Delphi is based on this answer. It’s a IFMXApplicationService replacement that reads the TPlatformCocoa.FDisableClosePopups private field which is set to True when sendEvent is called. The problem is that the sendEvent call inside TPlatformCocoa is not the only place where that method is used. We were getting some AVs when we opened context menus or showed JavaScript dialogs and the call stack indicated that sendEvent was called internally from a non-Delphi binary. The current MacOS FMX demo replaces the context menu with a custom FMX popup menu and the JS dialogs with FMX dialogs.

Comments are closed.