OS X Menubar application: How to bring window to front - objective-c

I am developing a menubar-only application for OS X and I am struggeling to get a settings window to show up in front of other apps.
App setup
"Menubar-only application" means:
I removed the "Is Initial Controller" from the NSWindowController in the main storyboard file. The main storyboard's window is not used in my app
I added an NSMenu to the "Application Scene" in the main storyboard. This will become my menubar menu
I set LSUIElement to YES to hide the dock icon
I set LSBackgroundOnly to NO (see NSWindow makeKeyAndOrderFront makes window appear, but not Key or Front)
When the app starts, I create an NSStatusItem and add the NSMenu from the storyboard as its menu. This all works fine - the app starts, shows no window and no dock icon but a menubar item that contains the menu from the storyboard.
Settings window
I now wanted to add a settings window that is shown when a menubar entry is clicked. I therefore:
Created a new .xib-file and added an NSWindow to it
Created a custom NSWindowController that connects the outlets and actions
Instantiated the custom NSWindowController using initWithNibNamed: on app launch
When the "Settings"-entry from the menu is clicked, I then try to bring the settings window to front using:
[self.settingsWindowController.window center];
[self.settingsWindowController.window showWindow:self];
[self.settingsWindowController.window makeKeyAndOrderFront:NSApp];
The window is shown, but not brought to the front but rather hidden behind other apps.
Any ideas how to solve this? Thanks!

You need to call:
[NSApp activateIgnoringOtherApps:YES];
(This is one of the rare occasions where it's correct to pass YES to that method.)
For Swift you can use
NSApp.activate(ignoringOtherApps: true)

I know you're asking for obj-c and already received an answer, but just incase anyone is Googling for Swift 4 implementation.
In your class that extends NSWindowController define the function:
func bringToFront() {
self.window?.center()
self.window?.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps: true)
}
Then whenever you wanna bring it up, call bringToFront().

Related

NSPopover crashes on segue triggered programmatically, OSX, Xcode 8.2

I have a simple setup (OSX not iOS):
Two windows A and B. Window A is a splash screen, window B the main screen.
Flow is like this -> Window A on app start, opens window B on "New Project" button click.
Window B contains a button. Button is setup in IB to open a view within a popover (via segue). Segue on button click works as expected.
On some place i trigger that segue programatically (performSegueWithIdentifier) to open the same popover attached to the button. This works as expected.
[self performSegueWithIdentifier:#"showSHImportCSVPrefsViewController" sender:nil];
But: if i close window B which returns to window A and open window B again ("New project") the popover throws an error when triggered programatically even if the manual button click still works... im so confused...
[NSPopover showRelativeToRect:ofView:preferredEdge:]: view has no window. You must supply a view in a window.'
After going through the whole code it turned out it was an observer not killed.
So when i closed window B and re-opened it, the same observer was created again, triggering the programmatically segue call twice, leading to the above described situation.
Solution: removeObserver on - (void)dealloc

How to close window OSX?

I wanted to create an application that mainly only involves the status bar. So far I have created the status bar item using NSMenu and NSStatusBar and I have also removed the dock icon with this bit of code on load:
[NSApp setActivationPolicy: NSApplicationActivationPolicyAccessory];
But what I still have is the NSWindow appearing when opening the app.
How can I prevent this? I also would like to be able to re-open it.
I have come up with a horrible way to close it:
[_mainView setFrame:CGRectMake(0, 0, 0, 0)];
Where _mainView is the main NSView in my viewcontroller that is conected to the nswindow.
I then want to be able to open the window again but with this time a table. But I get the error:
<Warning>: void CGSUpdateManager::log() const: conn 0x18de3 token 0x31fffffffffdafd
When resetting the frame back to the original size.
Also if I close the NSView that then means I can't re-open the view again.
This is a long winded explanation of an application that can control whether the window the viewcontroller is in, is opened or close.
To make a NSStatusBar item app that only shows in the status bar and not in the Dock or Application Tabbing. And not show any of the normal menus. i.e file,edit,view and so on..
You need to add the Application is agent (UIElement) - (Boolean) YES key - value to the application info.plist.
And also make sure that the windows 'visible At Launch' is switch off in the attribute inspector.
Update:
In a none storyboard application (OS X)
Setting the 'visible At Launch' to off in IB for a window, will stop the window appearing at launch.
But with a storyboard application. This will not work.
The 'visible At Launch' is already set to be off. But regardless of that, the window will always show.
(I think this is part of the design of storyboards and Human interface guidelines by apple. Maybe because they stem from iOS and there should always be a window present.)
There are possibly a few ways of changing this behaviour but I found that if you uncheck the initial Controller in the Attributes Inspector for the NSWindowController
This will stop the window showing up at launch. Which makes sense since the app now does not have any instructions to show anything initially.
To open the window you can simply link a menu item to the NSWindowController's Presenting Segue Show: method in IB.
If you want to open the window programmatically, then you have to re point to the controller in the code.
In IB select the NSWindowController again
Go to the Identity Inspector.
Give the Storyboard ID the identity "Main"
Now go to your AppDelegate.h file and add a the Property and IBAction:
#property (strong) IBOutlet NSWindowController *winController;
-(IBAction)showWindow:(id)sender;
Then go to the AppDelegate.m file and add this code in the applicationDidFinishLaunching
NSStoryboard *storyBoard = [NSStoryboard storyboardWithName:#"Main" bundle:nil];
NSWindowController * main = [storyBoard instantiateControllerWithIdentifier:#"Main"];
_winController = main;
(note just adding the controller by linking it directly with a property in the AppDelegate did not work for me)
Now add the IBAction code to the AppDelegate.m
-(IBAction)showWindow:(id)sender {
[_winController showWindow:self];
}
You will need to link the IBAction as normal to which ever menu item you want to open the window via IB.

Cocoa - How to bring particular window to come in foreground from StatusMenu

I am working on an Mac Application. I have set Application is agent (UIElement) = YES in plist, and App have a Window (lets say Popup Window) that acts as custom PopOver for StatusMenu. One more window is there (lets say Window B) that should opened on selecting a Link from StatusMenu that i have made, but Problems that I am facing are as follow:
On Application launch, When I opens status Menu It also showing Window B, that actually should not be Shown. Window B is allocated and initialised in Application Delegate.
Another Issue is When Window B is made Visible by Selecting it from StatusMenu. It appears well, Now i switch to another application so Its window is sent to background that is fine, but Whenever I click on Status Menu, It automatically comes in Front. Ideally It should only open Popup window.
Window B is opening because you might be forgot to un-check "Visible At Launch" window property in attribute inspector of interface builder
2nd issue you can resolve by activateIgnoringOtherApps set to YES before calling your window
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
[windowB showWindow:nil];

set NSWindow focused

I have an app winth one window and one panel, attached to this window.
steps:
deactivate my app (app opened, but without the focus)
click on a button on panel (panel is focused now, but main window is not)
How to set focus to the main window (parent window) from the panel?
Swift 5 version of #BUDDAx2 answer:
NSApplication.shared.activate(ignoringOtherApps: true)
It is not clear what you mean by focus, and whether what you call main window is a main window as defined in Cocoa. Assuming it is a Cocoa main window and focus is the same as key status,
[[NSApp mainWindow] makeKeyWindow];
or
[[NSApp mainWindow] makeKeyAndOrderFront:self];
If it is not a Cocoa main window, you need to have a reference to it and send it -makeKeyWindow or -makeKeyAndOrderFront:.

Xcode Run IBAction when app loads

I would like to hide a window before the app has loaded. Now I know to hide a window you can use this;
[window2 orderOut:nil];
which works fine when you click on a button but what if I wont it to be hidden before or whilst the application has loaded?
So sorta need an IBAction on when the application loads
In Interface Builder, you can uncheck the box (in the window's attributes pane) that says to show the window at startup.
Or you can put that line of code in your app delegate's applicationWillFinishLaunching (or perhaps applicationDidFinishLaunching) method. (Might not work in the first one, I'm not sure.)
But I'd go with the first option, personally.