I have come across this Cocoa application (source code) that shows a main Window.
As long as this window is key it is possible to open the Preferences window from the Main menu as well as by hitting Command-, but when the main window is not key and another window from the same app is, the NSMenuItem is grayed out and the keyboard shortcut does not respond.
I've inspected the xib file associated to the Main Menu and that NSMenuItem is sending a openPreferences:(id)sender IBAction to the FirstResponder which sould be the NSApplication.
What am I missing (I am still a newbie at mac cocoa programming)? How can I fix it so that the preferences are reachable from each application window?
Probably the original author implemented - (BOOL)validateMenuItem:(NSMenuItem *)menuItem and returns NO under some circumstances.
NSMenuValidationProtocol documentation.
Update: Another quick guess: Maybe the object that handles the IBAction for the menu item is not in the responder chain anymore after you open the second window. NSMenuItems are only enabled if the action selector can be found in the responder chain.
Related
I am showing a floating NSPanel (separate from the main application window) for inputing data (I should add, this is a UIElement application but not a background one, i.e. it has no main window per say, and responds to global keyboard shortcuts to launch a window). I want certain keyboard shortcuts to work specifically for this NSPanel in addition to the ones the main menu supports for the application window.
How can I set a NSMenu for the floating panel such that keyboard shortcuts are sent to this panel when it's a keyWindow?
The simple solution was to simply implement the menu actions in the NSViewController hosted by the panel. This would then get picked up in the responder chain for all keyboard shortcuts supported.
How can my menubar application achieve the same behaviours as 1Password or Dropbox:
clicking their menu bar icons or popovers does not steal focus, e.g. while I am in for example TextEdit and open 1Password/Dropbox, the blinking cursor disappears but the window itself does not go into the background, yet I can type into 1Password's text field.
even though they didn't take focus in the first place, they disappear when I click back into another application
I figured out how mouse over works in the Dropbox popover table view by using an NSTrackingArea with the options MouseEnteredAndExited, AssumeInside, and ActiveAlways.
I am trying to get the same behaviour to work in an NSPopover that opens from an NSStatusItem.
I found a workaround for now. I am able to get the same behaviour by using non-activating NSPanel with a window level kCGPopUpMenuWindowLevelKey and I had to override canBecomeKeyWindow to return true.
Unfortunately I haven't found a way yet to get a NSPopover to behave this way since it's not a subclass of NSWindow.
To set the kind of behavior you are describing you use:
yourPopover.behavior = .transient
I am making my first OS X application in Xcode, and I have no idea how to make a specified keyboard shortcut trigger some code (e.g. ⌘ Cmd+ C/⌘ Cmd+V). All I can find online is keyboard shortcuts in Xcode itself.
Thanks in advance
This is usually setup for you automatically. The MainMenu.xib by default has an Edit menu with these shortcuts bound, activating [firstResponder copy:] and [firstResponder paste:]. The first responder is item currently having keyboard focus, or it's parent view if it doesn't answer to those actions, up to the window at the top level.
For new shortcuts, Apple recommends that you have menu items associated to all those. If you do, you can set the shortcut in the interface builder using the attributes inspector. You then ctrl-drag from the menu item to the object you want to send the action to, e.g. the app delegate. You will have to create the target method first obviously. You should also use bindings to control when the menu item is enabled or not.
It's not recommended, but if you want to do this programmatically, without a menu item, you override the
- (BOOL)performKeyEquivalent:(NSEvent *)theEvent
method of the view or window in question. It will be called if it's in the responder chain when the key is pressed, and you return YES to indicate you've handled the event.
I have an NSDocument based app which also has a preferences NSPanel window. The preferences panel can then pop an NSFontPanel to configure a default font for my app. Challenge I have is that when the NSFontPanel is displayed, it becomes 'key' - which means the responder chain will direct changeFont: messages to the 'main' window (i.e. my document NOT my preferences panel)
Anyone know how this scenario should be handled? I guess, what I want is for the changeFont: message to goto the 'topmost non-key window' in this situation. I could do a quick check in my main window to check if preferences panel is visible and pass the message on - but that feels hacky...
Any suggestions would be most welcome!
You can use the NSNotiFication by sending your changeFont: messages
The problem I've got is that when the preferences window is opened and then closed, it will not open again. Why is this happening and how can this be fixed?
EDIT: Just noticed also I've got the same problem with Main Window.
The window is being opened via the menu bar and is in a separate NIB file.
It sounds like you forgot to set the 'window' outlet of your window controller (in the Nib, the File's Owner) to point to your window. Once you connect its 'window' outlet the window controller's showWindow: method will work.
Hard to say without seeing the code, but one possibility is that you have "Release When Closed" checked for the window in Interface Builder, and you are loading it once, caching it, then expecting to be able to close and re-open it without loading from the nib again.
For any other noobs like me, having this issue :)
Don't forget to set the file's owner class to be the same as the controller class, then you can connect the 'window' outlet to the panel.
I encountered this same problem while working on the chapter 12 (Nib Files and NSWindowController) exercise in Aaron Hillegass's Cocoa Programming for Mac OS X book. Doug's answer above was the solution - I hadn't linked the window outlet of the Preferences.xib's file owner to the window itself (in this case the Panel (Preferences) window).
I right clicked on the "File's Owner" in the Preferences.xib file then left-mouse-button dragged from the Window outlet to the Panel (Preferences). Once done and rebuilt the application worked as intended. I could close and reopen the custom preference panel and my previous settings were still there (since the preference window is not unloaded just hidden).