Window-less Cocoa application - objective-c

I'm a complete beginner in Objective-C and Cocoa.
I would like to create a window-less application, which just shows a NSStatusItem in the system tray. The tray works fine, however, there is one problem.
For some reason my application automatically creates a window for me, which I do not want.
I thought it was caused by the automatic Interface Builder template created when I created the application in Xcode, so I deleted the .nib file from the project. However the window still gets created.
The only lines that contain a reference to the window are in the header:
NSWindow *window;
#property (assign) IBOutlet NSWindow *window;
and in the implementation file:
#synthesize window;
Both were added automatically, I did not write this.
How do I just stop the app from creating a window? I even tried to removing all references to window from the code, including the NSWindow *window, but the window still got created.
My temporary fix right now is to call [window close]; in the application, but surely there is a better way?

My suspicion is that nothing in your code is creating the window. When you create a new Cocoa Xcode application, Xcode sets up an XIB with your interface for you. Open up MainMenu.xib (should be under Resources) in interface builder and delete the window that it throws in by default.

If you don't want to show a window you may consider run your application in background. That will stop the window to appear.
In order to run your application in the background, set YES to "Application is background only" in your app's PLIST file

Return false in your NSDocument subclass' windowNibName method.

Related

NSWindow bind load event for control and logic initialization

I just started working on an OSX application, first time in objective-c. I need to make a window that will display all the network interfaces available on the computer.
So far
I have an AppDelegate that pretty much does nothing
I have set the Main nib file base name to my main window, which is a xib, header and implementation file
I made my xib window inherit from my class and added the outlets I needed using right-click drag (worked well, I assumed I was correct until then)
The issue
I can't seem either override or bind the load event of the window, where I want to load the text in my label.
I've seen some people use a NSWindowController, but I don't think I need this.
My question
Is it required to have a NSWindowController PLUS a NSWindow class? I feel there are too many files for a single window. I have the xib and two .h/.m files... If it's not required, how can I get notified when the window loads?
The question wether you need NSWindowController(s) or not depends on the complexity of your application.
If your app is only a small utility using a single window, you might get away with setting up your UI in MainMenu.xib and connect it to some IBOutlets in your AppDelegate.
But the above approach gets messy soon when your app becomes more complex. To tame that complexity, you can create dedicated NSWindowController classes (e.g. one per window). Those window controllers could manage a hierarchy of child NSViewControllers to further split up your complexity.
If it's not required, how can I get notified when the window loads?
The default Xcode template should have created an AppDelegate.m file. You can add code to initialize your UI in
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
At this point the window has been fully loaded and
#property (weak) IBOutlet NSWindow *window;
should point to your window instance.

What Code in Newly Created Project Call Window?

If I create a new project in xcode, there will be a main xib
In main xib there is an object called window.
I did an experiment where I remove the _window outlet from the automatically generated code.
#interface SDAppDelegate : NSObject <NSApplicationDelegate>
//#property (assign) IBOutlet NSWindow *window;
#end
I run the program and voila, that stupid window is still opened. The only way to make sure it's not opened is by deleting the window.
What part of the code display window? How do the delegate knows which window to open?
I do not want to show any window when application launch. I may want to show some windows when applications select preferences, for example.
NSApp loads your main XIB, and the window in it is set to be visible on launch, so it is. None of your code is involved in this process at all.

NSStatusItem with NSPopover and NSTextField

I have a NSStatusItem that displays a NSPopover which contains a NSTextField but the text field isn't editable although it has been so be so in Xcode. Now this is a known bug and there is apparently a solution someone posted here. I really need to work around this bug.
I'll just quote the answer here for convenience:
The main problem is the way keyboard events works. Although the NSTextField (and all his superviews) receives keyboard events, he doesn't make any action. That happens because the view where the popover is atached, is in a window which can't become a key window. You can't access that window in no way, at least I couldn't. So the solution is override the method canBecomeKeyWindow for every NSWindow in our application using a category.
NSWindow+canBecomeKeyWindow.h
#interface NSWindow (canBecomeKeyWindow)
#end
NSWindow+canBecomeKeyWindow.m
#implementation NSWindow (canBecomeKeyWindow)
//This is to fix a bug with 10.7 where an NSPopover with a text field cannot be edited if its parent window won't become key
//The pragma statements disable the corresponding warning for overriding an already-implemented method
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
- (BOOL)canBecomeKeyWindow
{
return YES;
}
#pragma clang diagnostic pop
#end
That makes the popover fully resposive. If you need another window which must respond NO to canBecomeKeyWindow, you can always make a subclass.
I don't really understand what I am supposed to do. Do I just create these two files NSWindow+canBecomeKeyWindow (.h and .m) and that will do it? Because it doesn't work for me.
I am not sure about this but does this only work if I am actually using an NSWindow that displays the NSPopover? I am not using a NSWindow, how can I get the NSTextField to be editable?
Thanks.
Yes, just add the NSWindow+canBecomeKeyWindow (.h and .m) files to your project, and it should work. I'm using this technique in an app I'm currently developing, and it works fine. Make sure NSWindow+canBecomeKeyWindow.m is listed under "Compile Sources" in your project's Build Phases.
As an aside, I'm having other issues using NSPopover to show a window from an NSStatusItem. I haven't actually tried using it in my project, but this looks promising as an alternative.

Avoid autorelease of a NSWindow which is opening another NSWindow?

When I open an NSWindow which is autoreleased, everything works correctly. The NSWindow is released by my root class only after I've clicked the OK button.
However, when I open an NSWindow and from the opened NSWindow I open a new NSWindow, I get a bad access error. This happens because the first window is not considered active anymore and it is released by the root class.
How can I avoid this issue ?
A simple answer: don't do this, you are relying on undefined behaviour and asking for a crash. You should hold a strong reference to the window and only release it when you're done with the window.
In general, you should use an NSWindowController to manage each window that you open. NSWindowController holds a reference to the window and you can easily call the showWindow: and close: methods of NSWindowController to manage window display.
From your question it seems that you are using NSWindow objects as window controllers. This is not how you should be using NSWindow. Use NSWindowController instead, that's what it's for.

Cocoa Application Template - MainMenu.xib - Main Window

When you create a new application in Xcode, it automatically creates a AppDelegate and a MainMenu.xib. The latter also contains the application main window, which is linked to the AppDelegate as an IBOutlet.
What I tried to do is, use a MainWindow from a different xib-file. However, there's absolutely nothing I can do to prevent Cocoa from showing the first window it created in the first place, even if I remove the IBOutlet link and comment it out in the source file and what not...
Hope someone can explain this, as it has been bugging me for a while now...
Whether or not a window in a XIB is shown at launch is not controlled by an explicit code, but instead controlled by the state of the window "freeze-dried" in the XIB.
More concretely, in an inspector of an NSWindow in the Interface Builder, you have the option called Visible at launch under the heading Behavior.
When the Cocoa system loads a nib and encounters a window with this bit on, it just shows it on the screen. It's independent of whether you have IBOutlet or not. You see, it's also the Cocoa system which sets UI objects to IBOutlets when it loads a nib... it can do whatever it wants.