2

I am having a problem where [NSRunningApplication activateWithOptions:] returns NO when there is no obvious reason that it should fail to activate an application.

This is not a duplicate of -[NSRunningApplication activateWithOptions:] not working

The accepted answer to that question is to use NSApplicationActivateIgnoringOtherApps instead of NSApplicationActivateAllWindows but that is not an acceptable answer as the two options are intended to activate an application in a different manner as the option values imply.

There are places within my code where [NSRunningApplication activateWithOptions:] does work, however when calling it via an EventTap, it almost always returns NO regardless of using NSApplicationActivateAllWindows or NSApplicationActivateIgnoringOtherApps as the option argument. The reason I say "almost" always returns NO is because the very first time it is called, it does work. All 2nd and subsequent calls fail.

I am basically handling a single-click event on an Application icon in the Dock. I am using an EventTap installed on the Dock process that was created with CGEventTapCreateForPSN(). Within the event tap callback, I have successfully determined the process identifier of the icon that was clicked on in the Dock. The process id was obtained using the Accessibility API.

Now I need to activate the application, so I call:

BOOL result = NO;
NSRunningApplication *currentApp = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];

if (currentApp) {
        result = [currentApp activateWithOptions:NSApplicationActivateAllWindows];
}

In the above example, I have verified that currentApp is valid, and that bundleIdentifier, processIdentifier and a few other instance vars in the RunningApplication object are correct.

As mentioned above, regardless of the NSApplicationActivationOptions used, the application does not activate, and the method returns NO. Again, it does occasionally work on the very first click, but fails on all subsequent clicks on any application's dock icon.

Can anyone explain why such a simple method is failing? and possibly why it would work only the first time it is called? and why it always works when not executed from an EventTap?

I have spent several hours trying to resolve the issue, and the only thing that always works is to use the deprecated method SetFrontProcessWithOptions(&psn, 0); instead of [NSRunningApplication activateWithOptions:NSApplicationActivateAllWindows].

I have tried wrapping the call to [NSRunningApplication activateWithOptions:] within dispatch_async, I have also tried using an operation queue from within the EventTap, neither of which solves the problem. Finally, I have tried sending a notification and calling [NSRunningApplication activateWithOptions:] from within the notification callback, which also fails. This is the code in my event tap:

case kCGEventLeftMouseDown:
    if (cgClickCount == 1) {
        NSNumber *pidNumber = [NSNumber numberWithLong:actualPid];
        NSDictionary *userInfo = [NSDictionary dictionaryWithObjectsAndKeys:pidNumber, @"pidNumber", nil];
        [[NSNotificationCenter defaultCenter] postNotificationName:@"DockApplicationClickedNotification" object:self userInfo:userInfo];
        return NULL; /* swallows event */
    }
break;

Any assistance is greatly appreciated! A debug screen grab is attached that shows how the 1st attempt to activate an app by clicking its dock icon is successfully, and how subsequent clicks fail to activate the app.

enter image description here

UPDATE and half-solved: I have determined why [NSRunningApplication activateWithOptions:] works on the 1st attempt and fails on 2nd and subsequent attempts. The first time I click on an application icon in the dock, my application is the active app. On subsequent clicks on an app icon, some other application is active. So the problem here seems to be that [NSRunningApplication activateWithOptions:] will only work if my application is the frontmost process.

If I add [NSApp activateIgnoringOtherApps:YES]; before the call to [NSRunningApplication activateWithOptions:], it consistently works as intended, however, there is a menubar flicker due to activating my app only to then activate a different app. So the question becomes:

Is there any way to get [NSRunningApplication activateWithOptions:] to work when my application is not the frontmost app? and is activateWithOptions: supposed to work this way?

Community
  • 1
  • 1
RGB World
  • 399
  • 1
  • 6
  • 19
  • 2
    From the documentation of `NSApplicationActivateIgnoringOtherApps`: "By default, activation deactivates the calling app (assuming it was active), and then the new app is activated only if there is no currently active application.". Adding `NSApplicationActivateIgnoringOtherApps` works for me. – Willeke Jun 01 '16 at 15:07

0 Answers0