Search code examples
macosdelphidelphi-xe2firemonkey

Disabling App Nap with beginActivityWithOptions


I'm attempting to add the new OS X 10.9 (Mavericks) method beginActivityWithOptions method to the NSProcessInfo interface (TNSProcessInfo) in FireMonkey (Delphi XE2).

The function seems to work. It returns an object, however, it's not disabling App Nap for the application. I'm using the Energy tab of Activity Monitor to monitor the App Nap state.

I've added the following code to Macapi.Foundation.pas:

const
  NSActivityBackground = 255;
  NSActivityIdleSystemSleepDisabled = 1048576;
  NSActivityUserInitiated = NSActivityIdleSystemSleepDisabled or 16777215;
  NSActivityLatencyCritical = 1095216660480;

type
  NSActivityOptions = UInt64;

  NSProcessInfo = interface(NSObject)
    ['{B96935F6-3809-4A49-AD4F-CBBAB0F2C961}']
    ...
    // Added following
    function beginActivityWithOptions(options: NSActivityOptions; reason: NSString): NSObject; cdecl;
    ...
  end;

I'm calling it like this:

var
  obj: NSObject;
  reason: NSString;
  options: NSActivityOptions;
begin
  reason := NSSTR('...');
  options := NSActivityUserInitiated or NSActivityLatencyCritical;
  obj := TNSProcessInfo.Wrap(TNSProcessInfo.OCClass.processInfo).beginActivityWithOptions(options, reason);
end;

I've tried various combinations of the options flag, and it's not disabling App Nap. Any ideas? Do you see anything wrong with my implementation?


Solution

  • Thanks! I've been working on this same App Nap related problem but was using the NSProcessInfo disableAutomaticTermination and enableAutomaticTermination with no success. I tried your idea of using beginActivityWithOptions and now it works fine. I believe your only mistake is that you need to create an instance of NSProcessInfo that is assigned to field in the class. The way you are doing it, when TNSProcessInfo.Wrap(TNSProcessInfo.OCClass.processInfo) goes out of scope the modification you made to the activity is lost.

    In my test, I created a form with

    TForm46 = class(TForm)
      procedure FormCreate(Sender: TObject);
    private
      ProcessInfo: NSProcessInfo;
    public
    end;
    

    then in the FormCreate

    procedure TForm46.FormCreate(Sender: TObject);
    begin
      ProcessInfo := TNSProcessInfo.Wrap(TNSProcessInfo.OCClass.processInfo);
      ProcessInfo.beginActivityWithOptions(NSActivityUserInitiated or NSActivityLatencyCritical, NSSTR('Good Reason'));
    end;
    

    Then I deployed it to my mac and ran it, and monitored it with Activity Monitor. It seems to work as expected with the app staying in the App Nap No state for hours at a time.

    BTW the whole App Nap thing seems to get fooled by running the app through PAServer. I had to deploy and then run locally on the Mac.