Disable application activation on window click - objective-c

In my Cocoa/Objective-C application I have a utility panel floating "always on top" to be accessible even when my application is not active. I am trying to disable the "switching to my application when a user clicks on that panel".
The behaviour I would like to achieve is similar to OSX's Keyboard Viewer, (which is also a never activating panel), so that some other application remained active after clicking on my app's panel. i.e. Safari stays active when typing an address using Keyboard Viewer. Even third-party onscreen keyboards have this functionality (for example the one from CORALLO Software), which means this behavior is not reserved system-only.
I was messing around with NSApplicationActivationPolicy, but without positive results. In which direction should I go?

You should take a look at the canBecomeKeyWindow and canBecomeMainWindow methods on NSWindow. It sounds like you want your window to maintain key status while not being able to be the main window. Here are some resources to help you:
Window Programming Guide - Explains the difference between main and key windows
NSWindow class reference - Jump to the sections on canBecomeKeyWindow and canBecomeMainWindow

Related

How do you hide the menu bar in a Cocoa app?

How do you programmatically hide the menu bar in a cocoa app? I would like to make full use of the screen area.
There are two good ways I know of to do this.
1
In Cocoa, you can call the NSMenu class method setMenuBarVisible: to show or hide the menu bar.
As of this writing, the documentation for the NSMenu class does not tell you the following additional information.
The menu bar will only be hidden for the app that calls this method.
The Dock will also be hidden at the same time.
(This is true at least in 10.9 and I have not tested any other versions.)
This is useful when you want to use an app in a full screen way where you have a cover window, a borderless window the size of the screen.
The nice feature of this (as opposed to playing with LSUIElement settings) is that your app can continue to be in the application switcher cycling, as well as visible in the Dock when other apps are active.
This allows users to still activate a full screen app through the Dock or application switcher.
That means you can still use your app's Dock menu to access a preferences window for your app or other features.
This is incredibly convenient if your app is indeed a full screen cover window that runs at a window level higher than other apps, but you still want to make preferences and the ability to quit your app available, and you want your app's visual functionality available when other apps are active.
2
Another option is via NSApplication's method setPresentationOptions: with the arguments from NSApplicationPresentationOptions enum, such as option NSApplicationPresentationHideMenuBar
With this approach be very wary of reading the documentation, although it gives you additional options, and is still app-specific only, you need to know that some of the options are mutually exclusive. There are rules you must follow, or you get nothing but exceptions spewed to the console.
3 There is a 3rd and crappy option. If you have a helper app that is a daemon, you can use it to change your app's LSUIElement state and basically relaunch your app. It's dumb and it takes you out of the app switcher completely, which is great if you really are writing something that should not be there, but that is rare.
There is also the NSView enterFullScreenMode:withOptions: method, although most apps for which that would be appropriate prior to 10.7 should probably use the modern full-screen-window API on 10.7 and later.

NSPanel in "Non-Activating"-Mode does not always show correct cursors

I've created a simple Cocoa-Application in XCode 4.6 with an NSPanel instead of the default NSWindow. When I enable the Non-Activating
option and start the application everything works fine:
The panel is displayed in front of everything else and when
the mouse cursor hovers over the panel's edges it changes from a normal
arrow-cursor to the appropriate resize-cursor, so the user knows that he can resize
the panel.
This works fine as longs as I don't click on any other application
as for example Safari or Finder.
From the moment I once give focus to another application,
I can click on and hover over my panel as much as I want, the
cursor style will not change anymore - it always stays an arrow and it's not possible to return to the normal behavior.
The panel stays selectable and in the front, you still can move and resize it,
but the mouse cursor stays an arrow all the time. You then cannot even change it
manually using something like: [[NSCursor crosshairCursor] set].
So I need to find a way to create a NSPanel that keeps the normal
automatic-change-cursorstyle-when-hovering-over-panel-edges-behaviour
even when you give focus to another application.
I have already tried to use an customized NSPanel-class,
where I have overwritten the canBecomeKeyWindow and
canBecomeMainWindow methods, so that they return YES
but even when I make my Panel KeyWindow and MainWindow...
[myPanel makeKeyAndOrderFront:self];
[myPanel makeMainWindow];
...it doesn't solve the cursor issue.
Would be great if someone could help me here :)
PS.: the Base SDK and the Deployment Target are set to 10.8 in my project
So I found out that the described issue has nothing to to with the panel's window-state. It really doesn't matter if it is set to key or to main, instead the cursor-problem (stays arrow all the time)is related to the application's activation state.
Everything works fine as long as the application that owns the panel is active but if you click on another application my application is deactivated and does not get activated again - even if you click on the panel - because the "non-activating"-option is enabled.
The problem is that i need the "non activating"-option because I am creating a status-bar-screen-capturing app that should be displayed and operate in front of everything else but without deactivating any running application. I could solve the cursor problem by
[NSApp activateIgnoringOtherApps];
but then taking a screenshot of a fullscreen video running in Safari would deactivate Safari and minimize the video, which I don't want.
I don’t think it’s possible through normal APIs to change the cursor when your app isn’t active. I’m pretty sure the window system doesn’t allow it: it’d be a violation of the boundaries between apps—if you try to set a cursor from the background, and the foreground app also tries to set a cursor, who would win?
Of course the system can do it (like when you take a screenshot with ⌘⇧4), because that’s in the window system itself.

how to make an NSWindow blocking other Windows?

i'm looking for a way to have a NSWindow, which is able to block other NSWindows, like the menubar does. I mean: It is not possible to drag a Window over the menubar.
Is that kind of behavior realizable for my own NSWindow?
Thanks in advance
Bijan
NSWindow's dragging behavior automatically keeps windows from going under the menu bar — because they aren't supposed to. If you have some special case, you can override the standard dragging behavior. But think carefully before throwing away standard functionality prescribed by the HIG.
Also, it isn't possible to drag a window over the menu bar (rather than under) unless it's also over everything else, because the menu bar is normally above every other window.
I just stumbled on this question. There they say it is possible to move other windows using the Accessibility API or the Quartz Window Services.
Can't I just read out the other window's positions and move them, so that they do not collide with my window? Maybe triggered by a 0.1 sec. timer?

Keeping window of another application active while still receiving mouse events from another app's window?

Is there a way to have my app's window receive keyboard and/or mouse events (i.e. user clicking on window's buttons) while still retaining focus to another, unrelated app?
I've tried configuring my window at different levels, including [myWindow setLevel:NSPopUpMenuWindowLevel] to no avail.
You should be able to handle mouse clicks without ordering your window front by making your views (at least the ones that handle mouse clicks) respond to acceptsFirstMouse: messages by sending NSApp a preventWindowOrdering message and then returning YES.
You should not make your app handle typing without ordering itself front. The user might not realize where their typing is going if the field where it's appearing is obscured by another window.
Found it. Simple, yet elusive.
Use NSPanel and make sure panel style is Non Activating (NSNonactivatingPanelMask) or tick the same option in IB's inspector.

NSBorderlessWindowMask Window wont show NSPanels if not front most window

I have a window that is set with NSBorderlessWindowMask, and also kCGDesktopWindowLevel. When a NSPanel is supposed to appear from say the selection of a Dock Icon menu or a Status Bar Item menu, the NSPanel will not display if the application is not the front most window.
So this program at this time only has a Status Menu Item (think how QuickSilver is implemented) and when I choose Preferences from my menu it is set to show the Preferences Panel by using Makekeyandorderfront, however unless you have just launched the application and done nothing else, when you select Preferences nothing happens.
I have found that when I choose my menu item for Sparkle's Check for Updates, that the check for update panel will appear and then my preference panel which I told to open will appear.
So it seems like makekeyandorderfront is not really bringing it to the front, perhaps.
Does anyone know how to fix this?
Should I call something besides makekeyandorderfront, or maybe something in conjunction with it?
Thanks in advance
Panels are designed by default to work this way. They're designed as auxiliary windows for your application and always disappear when the application deactivates. You will probably also run into issues with the panel becoming key... but to cure your disappearing panel issue, send this message to your panel:
[panelObject setHidesOnDeactivate:NO];
You should probably be using actual NSWindow objects here instead of NSPanel objects, but since I don't know much about how your application works, you'll have to look into that yourself. For more information on the difference between panels and windows, please review the documentation here: Window Programming Guide