4

I noticed some weired behaviour under 10.7.3 and higher (also under 10.8).

My app is a little helper app that has an NSStatusItem and a dock icon by default. The user can configure, if he wants to display only the StatusItem, the Dock icon or both. To reailze this I am having LSUIElement=YES in the Info.plist. If the user has configured the Dock-Icon to be displayed I am doing

TransformProcessType(& (ProcessSerialNumber){ 0, kCurrentProcess }, kProcessTransformToForegroundApplication);

in applicationDidFinishLaunching.

This worked fine until 10.7.3. Starting with 10.7.3 the dock icon is sometimes displayed two times (though only one instance of the app is running). In this case the app can be terminated normally, but the second icon remains unresponsive in the dock. Restarting the dock makes the icon dissappear. This mainly happens, if the app is an LoginItem and automatically started on login. Executing TransformProcessType(& (ProcessSerialNumber){ 0, kCurrentProcess }, kProcessTransformToForegroundApplication); with a delay of 1 second or more seems to solve the issue. It's however not a good approach as the user gets no instant feedback, that the application has been started.

Does anyone know anything about this issue and a possible workaround/solution? Some googling revealed that Growl seems to have this issue starting in 10.7.3 as well, but not any solution. Note: Setting LSUIElement=NO and using kProcessTransformToUIElementApplication, if the user has chosen not to display the dock-icon does not work for me as the app needs to be compatible with 10.5 and 10.6.

holtmann
  • 6,043
  • 32
  • 44
  • if you could figure out a runtime check that you're happy with (try http://stackoverflow.com/a/11072974/774691) that would let you know whether the execution environment is 10.7.3 or earlier vs 10.7.4 or later, you might have your solution … perform the test, and conditionally do either what you've been doing or what you propose in the final paragraph. – john.k.doe Aug 22 '12 at 15:43

1 Answers1

3

I save my user's preferences to NSUserDefaults, with that I do two things: first, check at app startup in applicationDidFinishLaunching:

    if ([[[NSUserDefaults standardUserDefaults] objectForKey:@"ShowInDock"] boolValue]) {
    ProcessSerialNumber psn = { 0, kCurrentProcess };
    TransformProcessType(&psn, kProcessTransformToForegroundApplication);
}  else {
    ProcessSerialNumber psn = { 0, kCurrentProcess };
    TransformProcessType(&psn, kProcessTransformToUIElementApplication);
}

The if checks whether the user preference (saved in standardUserDefaults) is yes or no, and sets it accordingly.

Second, if they toggle the show in dock preference I use this:

- (IBAction)toggleShowInDock:(id)sender {
if ([showInDockPreference state] == NSOnState) {
    [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:YES] forKey:@"ShowInDock"];
    ProcessSerialNumber psn = { 0, kCurrentProcess };
    TransformProcessType(&psn, kProcessTransformToForegroundApplication);
}  else {
    [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithBool:NO] forKey:@"ShowInDock"];
    ProcessSerialNumber psn = { 0, kCurrentProcess };
    TransformProcessType(&psn, kProcessTransformToUIElementApplication);
    }
}

I've never had the double icon problem using this. Hope it helps.

Elbimio
  • 1,041
  • 2
  • 10
  • 25
  • This solution is not compatible with OS X 10.5 and 10.6. kProcessTransformToUIElementApplication was introduced in Lion. – holtmann Aug 24 '12 at 10:41
  • Then I would say it might be a problem with how you're saving your user preferences, which might be sending the message to show a dock icon once it launches, and again when it checks the settings. It might help if we could see how you're saving the preferences. – Elbimio Aug 24 '12 at 17:37
  • Nope. It's not the case. The transform TransformProcessType(&psn, kProcessTransformToForegroundApplication) is only executed one time. As I explained it's most likely a bug in the OS starting in 10.7.3. So I am looking for a workaround... – holtmann Aug 25 '12 at 09:40
  • Well, for now maybe check how low of a delay time you can get away with. Maybe you can drop it to something like a tenth of a second, which the user would barely perceive. – Elbimio Aug 25 '12 at 17:59
  • Thanks for your suggestions. Unfortunately it needs at least to be a second or more to reliable, which is not really convenient. – holtmann Aug 25 '12 at 18:53