OS X app that works without being active? - macos

Recently i've tried ColorSnapper app, and I've noticed that it works keeping other applications active.
(Check the screen below, as you can see safari window is still active and ColorSnapper keeps being active too).
How can is possible reproduce this effect ?

I believe these types of apps use LSBackgroundOnly or LSUIElement as Launch Services keys in their plist files (reference).
Here's a bit more about it.

I just try it and LSBackgroundOnly is the solution, but you must set the level of the window.
Example :
[mySpecialNSWindow setLevel:NSMainMenuWindowLevel];
This will display the special window above the windows of other applications.

I think the right approach is a mixture of (1) making the app LSBackgroundOnly, (2) using a custom transparent window as described here and set its level to NSFloatingWindowLevel, (3) using something like this in your app delegate to monitor mouse movements though your app is not active and, for example, to let your window follow the mouse position:
[NSEvent addGlobalMonitorForEventsMatchingMask:NSMouseMovedMask handler:^(NSEvent *event) {
[window setFrameOrigin:[NSEvent mouseLocation]];
}];
You can then have views as you like in the (transparent) window, move them around and modify its contents according to the mouse position.

Related

OS X run system application with GUI over all others including fullscreen apps

I'm trying to write an accessibility app based on a "no-click" mouse concept. The idea is to capture mouse gestures that will be interpreted as clicks and pass the events to other apps. I have most of it working, except that I don't know how I could run it on top of fullscreen apps post Lion. Right now the app window is transparent and follows the mouse around, but this approach won't work with other "Desktops" or full screen apps, as the app stays in its current desktop when switching.
Any ideas?
What I needed was to call
[self setCollectionBehavior: NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorFullScreenAuxiliary];
and also (important for the fullscreen apps!) set Application is agent (UIElement) to true in the info.plist file.

Change activationPolicy: from startup

I have the following problem. There is a Cocoa app I have with UI, nib, etc. I need to be able to start the application in background or in foreground. In other words, I need NSApplicationActivationPolicyProhibited in the former and NSApplicationActivationPolicyRegular in the latter. Now...the decision of how to start depends on an argument pass to the startup of the app. So the code looks more or less like:
shouldBeBackground = // read this from argument - argv
if (shouldBeBackground) {
[NSApp setActivationPolicy:NSApplicationActivationPolicyProhibited];
} else {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
[NSApp activateIgnoringOtherApps:YES];
// later on I do the makeKeyAndOrderFront:
}
Now the problem is with the Info.plist. If I put LSBackgroundOnly to 1 everything works as expected. But if I put it to 0 (or do not put the key), when the app starts it shows up the icon of the app in the dock for a couple of miliseconds and a little flash. I guess this is because the app is initialized with the default policy (starting to show the icon) and I switch it to background too late. This is also explained in: Cocoa - go to foreground/background programmatically
I know places WHERE to read the argument and do the previous IF even before I start cocoa or the app (for example, I can hook in MyOwnPrincipalClass +initialize), but even with that (even if I set the policy) it looks like the startup of Cocoa will set the default one. So it doesn't work.
The only solution I found is to put my IF at the beginning (before initialize cocoa) and depending on the argument, I write/modify the Info.plist (LSBackgroundOnly flag). This could work but it is a real hack. I would like to find a cleaner solution.
BTW, if I do the other way around: start up always as background and then make it foreground has a worst result since when going foreground the menubar of the app is not shown up automatically: you need to switch to another app and come back to make it appear....I searched in the internet and indeed it looks like a known bug/limitation.
BTW2: having 2 different binaries is not an option either.
Thanks for any help you can give me,
Just always startup as a background app at launch. Then if at startup you want to be a foreground app you can change the plist value programmatically, and then restart your application programmatically (you send an NSTask to launch your app before you terminate it). At app quit ensure that you are in background mode. Seems simple enough.

NSWindow with NSWindowCollectionBehaviorStationary is visible on the Dashboard. Is this a bug?

I'm trying to get my NSWindow to:
Be visible on all Spaces
Be visible when showing the Desktop (by pressing F11)
Not be visible in Mission Control/Expose
The following does exactly that, but with a side effect:
[self setCollectionBehavior: NSWindowCollectionBehaviorCanJoinAllSpaces
| NSWindowCollectionBehaviorStationary ];
When switching to the Dashboard on Mac OS X Lion, the window remains visible alone with Dashboard items for a second, then it is hidden.
Is this expected behavior or a bug? Users of my app find it confusing to see the window on the Dashboard before they disappear. I would have expected them to only show on Spaces and not the Dashboard.
I looked at http://cocoadev.com/wiki/DontExposeMe searching for workaround
nothing really worked except.
self.window.level = kCGDesktopWindowLevel;
now maybe DETECT changes to expose and set that then :) ...
see How can one detect Mission Control or Command-Tab switcher superseding one's program in OS X? for that :)
maybe an answer will come up there
I was able to reproduce this behaviour and I think it's just a bit of faulty animation on Apple's side.
Just so I can explain this better, create a new project, add these two lines to applicationDidFinishLaunching:, and run it.
[self.window setCollectionBehavior: NSWindowCollectionBehaviorCanJoinAllSpaces | NSWindowCollectionBehaviorStationary ];
[self.window setHidesOnDeactivate: YES];
(self.window is the window that is created automatically when creating a new project. it doesn't really matter here anyway, just as long as it is a window that appears on the screen)
Now notice this behaviour: when changing from one space where you can see your window to another in which there are other windows from other apps (and so your window is supposed to disappear since your app will be deactivated), your window only disappears when the animation finishes. So, what is happening?
Here's what I think it happens: when switching from one space to another, windows that show on all spaces only react to the change after the animation, hence the brief appearence of your window on the dashboard. I think you'll notice it disappears exactly when the slide animation ends.
So, unfortunately, I don't know how to fix your problem. It just seems to happen this way.

Mac OS X Lion: Detect if another application is running in full screen mode?

In a Cocoa app, is there a way to tell if another application currently is in full screen mode?
My application is configured to show up on all Spaces and listens for mouseEntered events to order itself to the front.
Problem is that when another app is in full screen mode and the user happens to move the mouse across the black area where my app's window is located, it is brought to the front (happens with multiple monitors).
I've only seen the above behavior with [self setCollectionBehavior: NSWindowCollectionBehaviorCanJoinAllSpaces]; enabled.
Here the other relevant code for my app.
- (void) mouseEntered:(NSEvent *)theEvent
{
// Don't do this when another app is in full screen mode:
[[self window] orderFront:self];
}
The above mentioned methods of registering for
"NSWindowWillEnterFullScreenNotification"
does not work, they can be used to notify your own app, using them we cannot detect whether any other application is in full screen mode or not.
However After trying out so many options found out FullScreen detector app at github this usefull link ..:):)
https://github.com/shinypb/FullScreenDetector.git
After a great deal of frustration, this worked for me to get a window that floats on all spaces except full-screen ones. I saw the fullScreenNone constant name, and since it described what I wanted, I tried it and found that it worked.
window.level = .floating
window.collectionBehavior = [.canJoinAllSpaces, .fullScreenNone]
window.canHide = false
Hmm, have you ruled out using applescript/scriptingbridge? You can get the size of windows from applescript and compare them to the size of the screen. (or do you not know which screen a given app is on?)
Certain apps which are accessible will have an 'AXFullScreen' attribute on their windows. For example this works for some apps:
tell application "System Events"
tell process "Pages"
repeat with myWin in windows
get value of attribute "AXFullScreen" of myWin
end repeat
end tell
end tell
The real action seems to be down in carbon... MacWindows.h and CarbonEvents.h have references to "FullScreen" in them.
You will need to research this though.
Use notifications. For example:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(willEnterFull:)
name:NSWindowWillEnterFullScreenNotification
object:nil];
Actually, you'll probably want to use NSDistributedNotificationCenter instead, since it goes across processes.
You're adding your object as an observer, so that when something else posts a notification that it will enter full screen, your object will receive that notification.
The selector is the message/method you want called by the notification process.
The name parameter is the actual name of the notification. These are standard, unless you were to create a custom notification for something you would be using.
The object parameter is for specifying which object you want to receive notifications from. Since you want to know when ANY app is going full screen, you'd want to leave this nil.
Remember to remove your object as an observer before it's deallocated!

NSStatusItem menu does not show up in lion full screen app

I have a foreground application that shows a NSStatusItem along with a menu (via NSStatusItem setMenu:(NSMenu *)menu). However, this menu does not display when I am looking at another app in fullscreen mode (say Safari) in Lion.
I know that I can make it work by setting NSBGOnly to true in the Info.plist file (or NSUIElement), but both methods will make my app icon disappear from the task switcher as well as hide the main menu once I manage to focus my app.
Finally, I have tried setting NSUIElement to true and do the following in my app upon startup (see also How to hide the Dock icon):
ProcessSerialNumber psn = { 0, kCurrentProcess };
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
This made the menubar appear again as well as the dock icon but the original problem (status item menu does not show up in another fullscreen app) is visible again. Whatever I try, I can't win.
Any suggestions would be highly appreciated!
Unfortunately I think this is expected behaviour. Your app is considered a foreground app, so all its UI is disabled while another app is in full screen. You should file a bug if you feel that status items in foreground apps should still be available to other apps in full screen mode.
Probably the best solution would be to split your app into two parts, an agent app which has LSUIElement set to true, which creates and manages the status item and its menu, and your main foreground app which does most of the work and which launches and manages the agent app.
There are a variety of inter-process communication methods that you can use to get the two apps talking to each other, such as Distributed Objects or Apple Events.

Resources