If you call TransformProcessType() like this :
ProcessSerialNumber psn = { 0, kCurrentProcess };
(void) TransformProcessType(&psn, kProcessTransformToForegroundApplication);
Then the cocoa app menu doesn't show up unless you call this early enough in your app (eg.开发者_JS百科 in applicationWillFinishLaunching).
I asked Apple for help and they helped me very well. Quote :
The reason why the menu bar isn't show when you call TransformProcessType is that your app is already the active app (that is, [[NSRunningApplication currentApplication] isActive] returns YES) and the menu bar for an app is shown when the app is activated
This is their workaround :
- (void)transformStep1 {
for (NSRunningApplication * app in [NSRunningApplication runningApplicationsWithBundleIdentifier:@"com.apple.finder"]) {
[app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
break;
}
[self performSelector:@selector(transformStep2) withObject:nil afterDelay:0.1];
}
- (void)transformStep2
{
ProcessSerialNumber psn = { 0, kCurrentProcess };
(void) TransformProcessType(&psn, kProcessTransformToForegroundApplication);
[self performSelector:@selector(transformStep3) withObject:nil afterDelay:0.1];
}
- (void)transformStep3
{
[[NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps];
}
Here is how I made it working.
BOOL MakeAppForeground()
{
BOOL bSuccess = TranformAppToState(kProcessTransformToForegroundApplication);
if(bSuccess)
{
bSuccess = (SetSystemUIMode(kUIModeNormal, 0) == 0);
[NSApp activateIgnoringOtherApps:YES];
}
return bSuccess;
}
BOOL MakeAppBackground()
{
return TranformAppToState(kProcessTransformToBackgroundApplication);
}
BOOL TranformAppToState(ProcessApplicationTransformState newState)
{
ProcessSerialNumber psn = { 0, kCurrentProcess };
OSStatus transformStatus = TransformProcessType(&psn, newState);
if((transformStatus != 0))
{
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:transformStatus userInfo:nil];
NSLog(@"TranformAppToState: Unable to transform App state. Error - %@",error);
}
return (transformStatus == 0);
}
Here is my solution, which is triggered on checkbox click in Preferences window. The only side effect is short flashing of the app's windows:
- (void) hideDockIcon:(bool) hide
{
ProcessSerialNumber psn = { 0, kCurrentProcess };
ProcessApplicationTransformState state = hide ? kProcessTransformToUIElementApplication : kProcessTransformToForegroundApplication;
OSStatus err = TransformProcessType(&psn, state);
if (err) {
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:err userInfo:nil];
NSLog(@"TransformProcessType failed: %@", error);
}
}
- (void) toggleDockIcon
{
[NSApp hide:self];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self hideDockIcon:self.preferences.hideDockIcon];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[NSApp activateIgnoringOtherApps:YES];
});
});
}
精彩评论