Question

I am currently developing an application in OS X and simply trying to set the app to fullscreen. I did some research and found out that I need to call a function from the sharedApplication object which I placed in the applicationDidFinishLaunching method.

[[NSApplication sharedApplication] setPresentationOptions:NSApplicationPresentationFullScreen];

However, when running the app, I get this message logged to me.

setPresentationOptions called with NSApplicationPresentationFullScreen when there is no visible fullscreen window; this call will be ignored.

I couldn't find a solution, can someone explain how I can resolve this statement? This is what I understood from the message, I cannot set my app to fullscreen if my window is not at fullscreen in the first place, this doesnt make sense to me, as I would need to have a smaller window for me to then want to maximise. Whats happening?

Update 1: Here's a video link of the error being recreated. Please do watch this Its 4 minutes in length.

Was it helpful?

Solution

Ok I hope this is a helpful answer.

First I'm going to discuss a base app development difference between iOS and Mac, and will continue onto how to work with NSWindowController and then try to explain why what you did caused unexpected behavior!

Differences Between iOS and Mac

Nibs

So something that's interesting in Mac development (I as well came from iOS development) is there isn't the same function call UIApplicationMain in AppKit; that is there is a function NSApplicationMain; however their signatures are different. In iOS you can specify the UIApplication subclass and UIApplicationDelegate class for the app to use, but in Mac you cannot specify the NSApplication subclass and the NSApplicationDelegate class. With that said one might be confused how the AppDelegate ever works, or how one would use a custom NSApplication. First in your Info.plist there is a key NSPrincipalClass which tells the system what subclass of NSApplication to use for the app. Unfortunately the delegate isn't as simple. The Info.plist also has another key NSMainNibFile which tells the system what nib to initially use. It loads this nib with the application as the Owner and automatically adds some default connections:

  • App Delegate: Here is where your app delegate is set. If you notice this object has class AppDelegate (or PREFIXAppDelegate). So here the nib will automatically allocate one of these classes and assign the delegate connection to the file owner, thus setting the delegate on the NSApplication.
  • Font Manager: This is going to be representative of the shared NSFontManager on Mac. It adds some connections to the menu items which keep in line with the system UX of choosing fonts.
  • Main Menu: This is the top menu you see. If you ever want to customize this you can do so here in this nib.
Argument for Nibs

So why use nibs? I personally came from iOS as I mentioned, and personally there wasn't TOO fond of nibs all the time. Things simply felt more flexible doing it all in code. Well in a Mac app I don't feel like you lose that flexibility in using nibs. Nibs are generally the standard (as far as I can tell) for creating a mac app (and standards usually exist for a reason). Further, a fairly key aspect of creating a Mac app is setting the NSMainNibFile key which loads a nib!

Programmatically

If now you're along the lines of "ya ya, but still, nibs, ew!" then I'll try to guide you here. A quick caution, it's been a while since I've tried doing this all programmatically so some information might be skewed! With this said let's dive into it!

The least I believe you can get away with is just setting the NSPrincipalClass key in the Info.plist to a custom subclass. Then in that subclass override -init* to set the delegate of the NSApplication to your custom delegate class. Here your delegate will work as normal and your app should run as expected (thus no nib needed). Note also you can simply subclass NSApplication and either set itself to be it's own delegate (which from a design POV is a little weird) or not set a delegate and just override certain methods (in some cases calling super). Not instead of using a delegate all together you could instantiate a notification listener object which just listens to notifications like NSApplicationDidFinishLaunchingNotification and the such.

NSWindowController

A window controller is essentially the base class to a windowed app (sure one can argue otherwise, but this is a pretty good place to start). As you know you just subclass an NSWindowController and then allocate an instance of it and call -showWindow:.

Nibs

As the documentation states, you don't need a nib to work with an NSWindowController, but "the relationship between a window controller and a nib file is important" (quote from the docs). You simply create a nib that has the NSWindowController as the owner and then add a window object and assign the window property of the owner to be said window and you're good to go (note setting the delegate of the window to the owner as well is a pretty good idea too - possibly necessary!)! Of course if you check the "Automatically Create Nib for Me" checkbox when creating the subclass this nib will be created for you.

Argument for nibs

Apple's docs essentially say "use it, it's like electricity; you don't have to use it but it's pretty nice to use".

Programmatically

So you want to be amish eh? (bad joke, sorry). Anywho, to create one of these programmatically you first need to subclass it and then set the window property manually (possibly in -init) or in the calling function/method.

Why didn't your project work?

Well when you deleted the MainMenu.nib you deleted the reference to the delegate. Thus your delegate was never allocated and thus is never called for the delegate messages. This is why your window never shows up - your code is never called. If you delete the window object inside the nib but keep the rest of the connections then the code /should/ work (I just tested, then again I have some tweaks to templates and such so my tests might not be accurate).

How to go Fullscreen

Once you create the window controller call -showWindow: and then [windowController.window toggleFullscreen:nil]. This should cause the window to go full screen (again tested and works for me).

Creating Art

So you're last question was regarding recreating that (IMO great looking) app. I don't personally have a great tutorial off hand to create a flat mac app, but some general principals to go by that I've learned:

  • Lots of Subclasses. In comparison to iOS I've noticed to get a deep level of customization I need to subclass more classes. For example, NSView doesn't inherently have a backgroundColor property, so in order to add this you need to subclass it, add the property, and then implement the -drawRect: method to fill with that color (note this isn't the /only/, which brings us to our next point).
  • Layer Backed or Not? NSViews in Mac apps do not inherently have a CALayer behind the scenes of the view. In order to add layers you need to specify -setWantsLayer:YES on the NSView you want a layer on. Note from my experience simply returning YES from - (BOOL)wantsLayer in a subclass isn't enough, you need to actually send the message. If you're interested in subclassed NSViews with layers also check out - (BOOL)wantsUpdateLayer which tells the system to call - (void)updateLayer instead of - (void)drawrect:(NSRect)r when redrawing your view.
  • Patience. I have noticed I could create a fairly decent looking iOS app pretty quickly. Wether this is from experience, the UIKit or some other form of magic is unknown. However, in working with AppKit on creating Mac apps it's taking me significantly longer to create something that looks and feels nice. My belief is that since you have more screen to work with, more precise controls and in general a larger environment to work with, this enables many more options to explore for creating an app. Thus the base application is fairly plain so one can customize it to their heart's desires!

EDIT: Added some links. In general for Mac development don't forget to read this!

*I remember doing it this way in 10.7/8 but have not tried doing it in 10.9

Note to the folks: if you find an error in this post (since it's long I'm assuming I said something silly) please respectfully correct me below. I encourage corrections, however I wish them to be respectful!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top