I have an Application delegate that holds the reference to a NSWindow and the program (small test program so far) is generally working with Main Menu and views in the window.
However I discovered that if I close the window holding the views it's gone although the program is still running. As far as i can see the window reference is not nil but how do I restore it so it's visible and shown under the Windows menu again?
The program is not document based. All actions are performed in the window in question.
I created the window in the MainMenu.xib that was auto created by Xcode (this was in Xcode7 or 8 but now I've upgraded to 9).
I'm new to windows handling on Mac so I understand this is a very basic question but I'm totally stuck here. Having a window that is supposed to hold all functionality disappear without the user being able to restore it is bad I believe.
If you have a reference to the NSWindow, you just need to show it. For example:
[window makeKeyAndOrderFront:self];
But if the user closed the single window of your app, than the question is: How will the user trigger that code? The simplest answer is that the user will click your app's icon on the dock. To handle that click, implement the following method on you app delegate.
- (BOOL)applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows:(BOOL)hasVisibleWindows
{
if (hasVisibleWindows) {
return YES;
}
[window makeKeyAndOrderFront:self];
return NO;
}
Related
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().
These days, I develop iPad applications. Since I've run out of subjects to work on, I'm working on a simple OS X application to see how far I can go.
Anyway, what I want to do is show a Preferences window (PrefWindowController). It has a separate xib (PrefWindowController.xib) from MainMenu.xib. When it appears, I want the main window to go behind it. The following is what I have.
// AppDelegate.m
- (void)preferencesClicked:(id)sender {
if (!preferencesWindow) {
preferencesWindow = [[PrefWindowController alloc] initWithWindowNibName:#"PrefWindowController"];
}
[preferencesWindow showWindow:self];
}
// PrefWindowController.m
- (void)windowDidLoad {
[super windowDidLoad];
[NSApp runModalForWindow:self.window];
NSLog(#"Hello!?");
}
- (IBAction)closeClicked:(id)sender {
[NSApp stopModal];
[self close];
}
So I've learnt that I can use runModalForWindow to put the current window on top of the main window. The problem that I have is that this preferences window will reopen when I click on the close button (closeClicked). If I click on it again, it will close. If I open Preferences and click on the same button, it won't reopen. An interesting thing is that the application won't read NSLog(#"Hello!?") when the Preferences window first opens. It does when I clicked on the close button. Do you know what I'm doing wrong?
Thank you for your help.
Modal doesn't mean display on top. Modal means stop the user interacting with anything else other than this. It does this by creating a new run loop, which means that anything after runModelForWindow won't happen till after the modal window is closed. Exactly what you are seeing with the NSLog.
You probably don't want to use a modal window for preferences. The convention for OSX is that the main app window stays active when a preferences window is open.
If you just want to bring the window to the front, and don't care if the user later clicks on the main window to bring it to the front, then use -makeKeyAndOrderFront on the window you have. If on the other hand you want this preferences window to always be in front, then make it an NSPanel rather than an NSWindow.
I am having an issue similiar to this SO question. I would like to have a webview in an NSSheet in which I am doing some authentication to retrieve an API token.
I created a new NSWindowController subclass with a corresponding xib file. This is how I am starting the NSSheet:
- (IBAction)startAuthentication:(NSButton *)sender {
self.authController = [[AuthenticationWindowController alloc] initWithWindowNibName:#"AuthenticationWindow"];
[[NSApplication sharedApplication] beginSheet:self.authController.window
modalForWindow:[self.exportManager window]
modalDelegate:self
didEndSelector:#selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo:nil];
}
In the windowDidLoad callback of this authenticationWindowController I am directing the webview to the URL:
- (void)windowDidLoad
{
[super windowDidLoad];
[[self.webView mainFrame]loadRequest:[NSURLRequest requestWithURL:authURL]];
}
It looks great at first sight: if I press the button, the startAuthentication action method is called and the new window is animated into the parent window and the authURL is loaded. The website is displayed correctly with its HTML form containing two input fields (username and password).
The problem is, that I can click on the page and it works, however if I am trying to click into one textfield, so that this field gets focus it does not work. No cursor appears in the text field of the website's form and after each keystroke I hear the NSBeep() sound.
I did some research on this topic and I found two references:
How do I use a WebView in a modal dialog?
Cocoa topics: the case of the modal WebView
What kind of puzzles me is that there is the Facebook Exporter for Aperture Plugin, which shows exactly what I want: a webview in a modal sheet. However I cannot find out what they are making differently . In the Facebook Exporter I have not found any code interacting with the run loops directly.
My questions
Is this a known problem with webviews in modal sheets?
Are the problems explained in the two references still there?
How can I get this working? I do not understand when to switch the runloop mode for example.
there is no general problem with this and I just tried it out again. must be some code besides this? can you narrow it down to the sheet? btw: my sample:
https://dl.dropbox.com/u/3753090/test2.zip
BUT all that said, modal runmode and webviews / timers / networking isnt very waterproof :)
because: when you go modal via one of the convenience methods in NSApp, the runloop is only run in a very limited way. :/
Ok, as simple and silly as that may seem, this is my scenario :
The application window (there is just ONE main window) is minimized
The user clicks something on the dock menu
We want to bring that main window back
Simple?
Not quite.
I've tried accessing my main window via :
[[NSApplication sharedApplication] mainWindow]
[[NSApplication sharedApplication] windows]
and then sending a makeKeyAndOrderFront: message but it's simply NOT showing up.
I've even tried showing all windows (yep, it still sees as "windows" one-or-two (hidden) sheets I'm using...), but still nothing.
Could you suggest a way, I could finally show that window, WITHOUT having to set an outlet anywhere?
I don't know; I'm probably too tired to notice, but this thing is almost nerve-wrecking...
You can un-minimize a window like so:
if([aWindow isMiniaturized])
{
[aWindow deminiaturize:self];
}
However, the problem is that the window will lose main status when it is minimized, so you'll need some other way of identifying the window.
Why can't you just use an outlet?
You can make the app un-minimize all of its minimized windows like so:
for(NSWindow* win in [NSApp windows])
{
if([win isMiniaturized])
{
[win deminiaturize:self];
}
}
When the app launches, you could store a reference to the main window and register for the NSWindowDidMiniaturizeNotification. That will tell you when the main window minimizes, which might also help you.
This question already has answers here:
Make a Cocoa application quit when the main window is closed?
(5 answers)
Closed 9 years ago.
I need to quit Cocoa App when I click the red button on upper left.
I found this page saying
So what you need to do first is have the window you want to close be
connected to an IBOutlet in the nib. For this example i connected the
window to an outlet named "mainWindow".
How can I do this? I found Windows in xib file, but how can I connect it to an IBOutlet in the nib?
Or, is there any way to quit the cocoa app clicking red button?
EDIT
I should have put the code in the automatically generated delegate file.
There is an optional method for the application's delegate which will do this automatically. All you have to do is add this to the implementation. You don't need to create an outlet or anything.
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
return YES;
}
Take a look at the NSApplicationDelegate protocol, especially to the applicationShouldTerminateAfterLastWindowClosed:method...
http://developer.apple.com/library/mac/#documentation/cocoa/reference/NSApplicationDelegate_Protocol/Reference/Reference.html