Cocoa/Objective-C - Child window with text input without main window becoming inactive - cocoa

I have a need to spawn a window that will hover just above my main window in a cocoa application. I want this main window to allow the user to enter some text in an input box. All is well until the text input box actually gains focus. The main window becomes "deactivated." This window is borderless and is a slightly custom shape -- its more like a hover card than anything else, I suppose.
Basically, I'd like this thing to work almost exactly like Spotlight (Apple + Space) -- you can enter text, but this is such an an ancillary operation that in the context of the greater UX, you don't want the jarring effect of the main window graying out (becoming inactive). You'll notice when you have some application open and in-focus, spotlight will not cause the window of that application to become inactive.
This problem arises because text input seems to REQUIRE that the child window become the key window (it will not let you place the cursor in the text input field). When it becomes key, the main window becomes inactive.
So far I've tried:
Subclassing NSWindow for my main application and overriding isKeyWindow such that it only loses key when the application is no longer the users focus (as opposed to the window). This had the unintended effect of colliding with key status of the child window and having very strange effects on the keyboard input (some keys are not captured, like delete)
Creating a view instead of a window. Doesn't work because of this problem -- you cannot draw over a Webkit WebView these days.
Anybody Cocoa/OSX wizards have any ideas? I've become a little obsessed with this one. An itch I can't scratch.
Edit: have also tried overriding the following on the child window. When clicked, the window makes the main application window become inactive.
- (BOOL)canBecomeKeyWindow {
return YES;
}
- (BOOL)canBecomeMainWindow {
return NO;
}
Edit 2:
After screwing about with NSMenu for a while, I scrapped that approach. It seems I found something, however. In NSPanel there is a window style mask called:
NSNonactivatingPanelMask
The panel can receive keyboard input without activating the owning application.
Valid only for an instance of NSPanel or its subclasses; not valid for a window.
Trying this out now...
Edit 3: NSNonactivatingPanelMask did not do the trick. No ideas.

What you want is a window that can become the key window but which cannot become the main window. You could implement such a class yourself, but this is basically what NSPanel is for, so you might try that first.

I think this can help you:
[self.childWindow makeKeyAndOrderFront:self];

Related

keeping NSPanel controls active

I have an NIB-based NSPanel, style Utility Panel, that I'm making a child window of my NSDocument window. I'd like it to behave like a drawer, in that it appears like part of the window, with controls drawn in their active-window state whenever the document window is main. I'm also planning on customizing the frame, close & minimize buttons.
The panel has becomesKeyOnlyIfNeeded & excludedFromWindowsMenu set to YES, and its subclassed to return YES from canBecomeKeyWindow.
The panel's NIB contains a NSSegmentedControl and a view into which I add a view from another NIB. I'm finding that the segmented control is being drawn in its window-inactive state unless the panel is clicked on to become key.
I tried a trick from OmniGroup's OIInspectorWindow & cocoadev.com's NSWindow page, implementing an _hasActiveControls method that returns YES, but that seemed to have no effect. I then tried then overriding isMainWindow to return YES whenever the parent window is the main window (plus observing the window's state change notification & calling -display). I was hoping that this would fool the control & window frame to draw in the active state. On 10.7 (Lion) it turns out that the control does indeed draw active as I wanted, though the window frame isn't. On 10.8 (Mountian Lion), not even that, the segmented control is still inactive when the window isn't key.
I can live with my trick not affecting the window frame & close button, since I plan on customizing those anyway. Does anyone know either a) why my trick doesn't work on 10.8 and how I can get it to work, or b) another way to ensure my panel's control is always active when its parent window is main.

Make NSView in NSPanel first responder without key window status

Is it possible to give an NSView inside an NSPanel first responder status without giving the NSPanel key window status (making the main application window resign key)?
Thanks.
Well, I ended up figuring this one out, but it took a lot of research so I'll post the details here in case anyone else runs into the same problem. First of all, a few basics:
It's impossible to have 2 windows actually be key at the same time
It's possible to fake a window into thinking it's key by overriding -isKeyWindow but that won't give the views contained in the window first responder status.
My Scenario:
I added a child window containing an NSTableView into my main application window (the reason is irrelavant). The child window was an NSPanel with NSBorderlessWindowMask. I wanted to give the NSTableView first responder status without making the panel the key window because it took away focus from the main window (and the whole point of the child window illusion was to make the child window look like it was part of the main window).
The first thing I tried was fooling the table view into thinking that it was inside the key window by overriding isKeyWindow to return YES. This made the table view draw as if it were the first responder, but still did not give it first responder status.
The Solution:
So by default, NSBorderlessWindowMask will not allow the window to become key. To make the table view first responder, the window had to be key so I overrode canBecomeKeyWindow in the borderless window subclass to return YES. This, of course, took away key status from the main window, which was one of the things I wanted to avoid. To fix this, I subclassed my main window and overrode the following methods:
- (BOOL)isMainWindow
{
return YES;
}
- (BOOL)isKeyWindow
{
return ([NSApp isActive]) ? YES : [super isKeyWindow];
}
This subclass checks if the application is active, and if it is, it always returns YES so that no matter what window is active in your application, the main window will always behave as if it is still key. This sort of gives the illusion that you can have multiple windows be key at the same time and enables you to shift key window status to another window without losing it on your main window. Hope this helps!

Dynamically removing and attaching the border on a nswindow

How do I go about adding/removing the window border after it has been created? the window was already designed in interface builder and I would prefer to avoid writing the window purely in code as I am still a long ways before i can say i am experienced with objective-c/cocoa.
Example Program:
a single window with the border initially, a button on it. If you click the button once it makes the boarder disappear and if you click it again then the boarder reappears.
Thanks
As far as I can tell, you can't. You might be able to fake it by taking the content view out of one window and making it be the content view of another window.

OSX Cocoa: How to check which window is in focus?

Hey all, I'm pretty new to Cocoa and XCode, so I'm sorry if this is a dumb question.
How would I go about checking which window is in focus?
Additionally how would I go about checking if a certain window is in focus, if this is not the same as the previous solution.
Thanks for the help.
There are actually two forms of “focus”:
The window that has the active appearance (colored/dark gray stoplight, black text in title bar, undimmed proxy icon, etc.) is the main window.
The window that receives key events is the key window.
Consider a document window with an Inspector panel. If the user is editing some text in a field in the Inspector, then the document window may be main, but the Inspector panel is key.
To get the key window or the main window, ask the shared NSApplication instance. And, as TechZen noted, you can ask a window both whether it is key and whether it is main.
You looking for 'keyWindow'. It's a property of both NSWindow and NSApplication. It's a bool in the former and a NSWindow instances in the latter.

Programmatically closing an NSWindow when it loses focus

I am making an image picker that will display an n by n grid of selectable button when the picker is popped up. This grid of buttons will be contained within an NSWindow but I would like for the window to be close automatically if the user clicks off the screen. Is there a flag that can be set so that when the window looses focus it will be closed automatically?
There are two notifications that you may be interested in: NSWindowDidResignKeyNotification and NSWindowDidResignMainNotification. You can simply register for the one you're interested in in awakeFromNib (or windowDidLoad if you have a custom controller) and then close or hide the window as appropriate when you receive the notifications.
I won't delve too much into whether or not this is a good idea from UI standpoint. But, it might be a better idea to have either an overlay view or a panel for the functionality you describe.
You might check out NSPanel. It's an NSWindow subclass that will hide itself when the app is in the background, and that behavior sounds very similar to what you are looking for.

Resources