how to make a macOS app have two main menu - macos

I know some mac application has two main menu.
main menu means top left menu in macOS screen.
When a windowA show, the main menuA show.
As I click some window (name it windowB) in the application
and another menuB is replaced menuA.
And as I click windowA, the main menuA reappear.
Does someone know how to implement this behavior?

You have to associate a menu to each window. For this, you can copy the MainMenu of the Application and paste it into the appropriate Window Controller Scene. Then select the connections of the window in the scene and link the item "menu" to the new menu of the scene. Repeat this for all your window controllers/windows.
Then you need to add some code. Create a new Window class:
class Window : NSWindow {
override func becomeKey() {
NSLog("become2")
NSApplication.shared().mainMenu = self.menu
super.becomeKey()
}
}
and then set the class property of each window to this Window class.
You can then edit menus accordingly to your needs. Be aware that you need to reconnect each menu item to the appropriate first responder action...
I'm not sure it is the best solution, but it works well for me. In fact I don't really understand why I need to subclass NSWindow this way...

Related

How do I prevent the menu bar from moving down when my popover is open?

I have an app with a popover that appears on a status bar item. The thing is, when you click on the icon while you're in a full screen app, then move the mouse away from the menu bar to click on something in the popup, the menu bar moves up, and so does the popup. It's annoying.
Anyone know of any way to solve this? I've tried attaching an invisible menu to the popup, but I can't get the menu to be invisible.
Screenshot for clarity, the annoying part is where I wave my mouse around:
The popover window is moving because its parent window is the status item window, and when the parent window moves, the child moves with it. (Before I investigated this, I didn't even know Cocoa had parent and child windows.) I solved the problem with this code immediately after showing the popover:
NSWindow *popoverWindow = self.popup.contentViewController.view.window;
[popoverWindow.parentWindow removeChildWindow:popoverWindow];
Now, the menu bar still moves up, but at least the popup stays in the same place.
Either use Carbon events or watch for things happening to the menu bar (window of type NSStatusBarWindow):
Notifications of type
NSWindowDidChangeOcclusionStateNotification
NSWindowDidMoveNotification
NSWindowWillCloseNotification
NSWindowDidCloseNotification
with an object of class NSStatusBarWindow should give you enough information about the menu bar showing or hiding to add proper handling.
Super-hacky approach:
Custom window with some super-high window level to make it appear over the menu bar, then add a transparent custom view to the new window that catches and handles/blocks mouse clicks according to your needs.
Or:
Get the window instance the popover is using to display and track/handle NSWindowWillMoveNotification / NSWindowDidMoveNotification.
I converted #tbodt's answer to Swift 4 and confirmed that is resolves this issue:
let popoverWindow = popup.contentViewController.view.window as? NSWindow
popoverWindow?.parent?.removeChildWindow(popoverWindow!)

How to auto-activate cocoa window so you don't need to click twice?

I have two windows: A main window and an inspector panel. Both have sliders and draggable items.
You have to click twice every time you work in the other window. First click activates the window. Second click allows a drag to start.
Is it possible to have a click in a window automatically activate it AND allow the event to pass through to the controls so you don't need to do it twice all the time when switching between an inspector panel and main window?
The first thing to try is to set the panel's becomesKeyOnlyIfNeeded property to true. That way, you main window will remain key even if the user clicks and drags on controls within the panel.
Otherwise, you have to handle this in each different view class. A view should override -acceptsFirstMouse: to return true if it wants to handle the same mouse event that activates the window. For custom view classes, this is straightforward. If you're using standard controls and they don't already implement -acceptsFirstMouse: to return true, you'll need to subclass them and use those subclasses instead.

Avoid blue flash behavior when reusing submenu of main menu as context menu

I have the following problem: In an Cocoa app, a submenu is defined and attached in the main menu. Now I need the exact same submenu as a context menu for a NSView.
Now, my goal is to avoid creating an exact duplicate of the main menu. I thought that I could reuse the already existing submenu. Indeed, I can just assign the corresponding menu to the NSView with Interface Builder and that seems to work.
But unfortunately, every time I select an item in the context menu now, the corresponding root main menu item flashes blue.
Is there any way to disable this behaviour? Or do you have other suggestions how this problem can be solved without duplicating the existing submenu?

2 Action Connections in IB to one Button

I have an xcode app that I am building using IB for mac. THe app launches with windowA already opened. There is a button on WindowA that when pressed I would like to open WindowB and Consequently close WindowA.
I have found in the tutorials that there can only be 1 sent action connection per object, so all I can do at this point is have windowA close, or call WindowB to open on top.
Can anyone tell me how I can accomplish both using the same button?
Well, actually, you can call a single method. But within this method, you may accomplish several things. For example close a window and open another.
It's not necessary to create a complete class - which would correspond to a .m file. You just add another method
- (IBAction) doIt:(id) sender
to an existing class file. Connect this to your button in IB. Therefore, you set "File's Owner" to the class where your IBAction is (or, better, put the IBAction method in "File's Owner" class file).
In interface builder, select menu item File>Reload all class files
Now, right click "File's Owner" in interface builder. You should see your action there. Drag the round circle on the right of the popup to your button. Now, each time your button is clicked, the method should be called.

How to make a keyboard shortcut to close dialog with Xcode/Interface Builder?

This seems awfully basic but here goes. If you are keyboard-oriented you get used to using Command-W to close windows all the time in OS X. I'd like to add that capability to the dialogs I am creating in Interface Builder for my program. I can see how to add a keyboard equivalent to a button action but what if I don't have a button?
Should I add an invisible button and put the shortcut on that? Seems clunky. Surely there is just some method I can override but what I've tried so far isn't working.
When you press Command + W, it's the exact same as choosing File -> Close from the menu bar. What Close does is send a performClose: message to the first responder. That, in turn, will check if the receiver or if the receiver's delegate implements windowShouldClose:, and the window will close if it returns YES (otherwise, it will call the close method).
So really, it depends on what type of dialog you've got here. If it's non-modal (essentially, if you can access the menu bar while it's running) and is an instance or subclass of NSWindow, then all you need to do is override the windowShouldClose: method in your dialog's delegate (or your dialog class, if you subclassed NSWindow or something) and make it return YES.
However, if the dialog is a modal dialog (you can't access the menu bar, switch windows, etc. while the dialog is running), then you can't do it this way. You could add an invisible button, but in all honesty, a modal dialog should not be closed by hitting Command-W, for that most certainly violates some Apple interface guideline out there. (Especially since, as Ande noted, it's standard practice to have Esc close/cancel a dialog.)
Adding an invisible button works just fine.
Is the dialog an NSWindow? Because by default the File->Close menu option is set to the performClose: action of the first responder, and already wired to command-w
If the dialog isn't a window simply make your dialog first responder and implement the performClose: action.
why don't you try this:
-(void)keyDown:(NSEvent *)theEvent{
//If the key is X or x it just closes the window
if ([theEvent.characters.uppercaseString isEqualToString:#"X"]) {
[self.window performClose:self];
}
}
or if you want to show a window you can instanciate and show it there instead of the performClose
Jasper was right about the code part. For interface builder(storyboard), there is a quick fix:
In your storyboard, hit "CMD+Shift+L" to bring up the components lib, select File Menu Item.
Add the file menu item to the Application Scene's Main Menu Node. (Remove unwanted file menus)
Now you have a keyboard shortcut to close a window.

Resources