Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cocoa - go to foreground/background programmatically

Tags:

xcode

macos

cocoa

I have an application with LSUIElement set to 1. It has a built-in editor, so I want the application to appear in Cmd+Tab cycle when the editor is open.

    -(void)stepIntoForeground
    {
        if (NSAppKitVersionNumber < NSAppKitVersionNumber10_7) return;
        if (counter == 0) {
            ProcessSerialNumber psn = {0, kCurrentProcess};
            OSStatus osstatus = TransformProcessType(&psn, kProcessTransformToForegroundApplication);
            if (osstatus == 0) {
                ++counter;
            } else {
                //...
            }
        }
    }
    -(void)stepIntoBackground
    {
        if (NSAppKitVersionNumber < NSAppKitVersionNumber10_7) return;
        if (counter == 0) return;

        if (counter == 1) {
            ProcessSerialNumber psn = {0, kCurrentProcess};
            OSStatus osstatus = TransformProcessType(&psn, kProcessTransformToUIElementApplication);
            if (osstatus == 0) {
                --counter;
            } else {
                //..
            }
        }
    }

The problems are:

  • there's also a Dock icon (not a big deal);
  • there's also Menu, that is not a big deal too, but they appear not always.

Is there any way to disable menu at all or to make it appear always in foreground? Thanks in advance.

like image 481
pAK-76 Avatar asked Oct 18 '12 06:10

pAK-76


People also ask

How to know when app goes to background in Cocoa?

But as the guides in docs there is more information about application lifecycle. When your app goes to background, The Cocoa broadcasts a notification with the message of the app is moving to the background. So, if your app or your UIViewController registered for this notification, you can be aware when your app moves to background:

How to change foreground and background color programmatically in Android?

For other android UI components, it is similar to change foreground and background color like this. 1. Change TextView Foreground Background Color Programmatically Example. Below is this example screenshot. There are one TextView and two Buttons on the above screen. When you click the first button, it will change the text color in the TextView.

What is an app’s transition to the foreground?

An app's transition to the foreground is usually in response to a user action. For example, when the user taps the app’s icon, the system launches the app and brings it to the foreground.

How do I know when my app goes to background?

When your app goes to background, The Cocoa broadcasts a notification with the message of the app is moving to the background. So, if your app or your UIViewController registered for this notification, you can be aware when your app moves to background: As the same, for Moving to Foreground, we have a notification too:


1 Answers

This is how we do it. (Works 10.7+)

  1. DO NOT USE LSBackgroundOnly NOR LSUIElement in the app plist
  2. Add and init your menu and NSStatusBar menu
  3. After app initialized but not yet shown any window take a place where you might want to show the first window if any. We use applicationDidFinishLaunching.

    • If you do not want to show any window yet after app initialized use

      [NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];

      on 10.9 you can use at last the otherwise much correct

      [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];

    • If you should open any window after app init finished than simply show the main window

  4. Maintain your list of windows

  5. If last window closed, call

    [NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];

    on 10.9 you can use at last the otherwise much correct

    [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory];

  6. When your first window shown next time, call

    [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
    [NSApp activateIgnoringOtherApps:YES];
    [[self window] makeKeyAndOrderFront:nil];

This should do the trick, if at least one app window is visible you will have menu, dock icon with state signaled, and cmd+tab element with your app, if last app window closed only your NSStatusBar element stays.

Known issues:

  • The first step is important because without that if a system modal dialog suspends your startup (f.e. your app is downloaded from the net and become quarantined a confirmation dialog might appear at first startup depending on your security settings) your menubar might not be owned by your app after your first app window shown.

    Workaround: Starting as normal app (step 1.) would solve this problem, but will cause another small one, your app icon might appear for a moment in the dock at startup even if you would like to startup without any window shown. (but we can deal with this, not owning the menubar was a bigger problem for us, so we chose this instead)

  • Changing between NSApplicationActivationPolicyRegular and NSApplicationActivationPolicyAccessory (or NSApplicationActivationPolicyProhibited on OSes bellow 10.9) will kill your tooltip of status bar menu element, the tooltip will be shown initially but will not ever after the second call of NSApplicationActivationPolicyAccessory -> NSApplicationActivationPolicyProhibited

    Workaround: We could not find a working workaround for this and reported to Apple as a bug.

  • Changing from NSApplicationActivationPolicyRegular to NSApplicationActivationPolicyAccessory has other problems on some OS versions like there might be no more mouse events in visible app windows sometimes

    Workaround: switch first to NSApplicationActivationPolicyProhibited (take care this leads to unwanted app messages, like NSApplicationWillResignActiveNotification, NSWindowDidResignMainNotification, etc. !)

  • Changing from NSApplicationActivationPolicyAccessory to NSApplicationActivationPolicyRegular is bogus as on some OS versions

    • the app main menu is frozen till the first app front status change
    • the app activated after this policy not always get placed front in the application order

    Workaround: switch first to NSApplicationActivationPolicyProhibited, take care the final switch to the desired NSApplicationActivationPolicyRegular should be made delayed, use f.e. dispatch_async or similar

like image 75
Hofi Avatar answered Sep 21 '22 15:09

Hofi