How do you hide the menu bar in a Cocoa app? - objective-c

How do you programmatically hide the menu bar in a cocoa app? I would like to make full use of the screen area.

There are two good ways I know of to do this.
1
In Cocoa, you can call the NSMenu class method setMenuBarVisible: to show or hide the menu bar.
As of this writing, the documentation for the NSMenu class does not tell you the following additional information.
The menu bar will only be hidden for the app that calls this method.
The Dock will also be hidden at the same time.
(This is true at least in 10.9 and I have not tested any other versions.)
This is useful when you want to use an app in a full screen way where you have a cover window, a borderless window the size of the screen.
The nice feature of this (as opposed to playing with LSUIElement settings) is that your app can continue to be in the application switcher cycling, as well as visible in the Dock when other apps are active.
This allows users to still activate a full screen app through the Dock or application switcher.
That means you can still use your app's Dock menu to access a preferences window for your app or other features.
This is incredibly convenient if your app is indeed a full screen cover window that runs at a window level higher than other apps, but you still want to make preferences and the ability to quit your app available, and you want your app's visual functionality available when other apps are active.
2
Another option is via NSApplication's method setPresentationOptions: with the arguments from NSApplicationPresentationOptions enum, such as option NSApplicationPresentationHideMenuBar
With this approach be very wary of reading the documentation, although it gives you additional options, and is still app-specific only, you need to know that some of the options are mutually exclusive. There are rules you must follow, or you get nothing but exceptions spewed to the console.
3 There is a 3rd and crappy option. If you have a helper app that is a daemon, you can use it to change your app's LSUIElement state and basically relaunch your app. It's dumb and it takes you out of the app switcher completely, which is great if you really are writing something that should not be there, but that is rare.

There is also the NSView enterFullScreenMode:withOptions: method, although most apps for which that would be appropriate prior to 10.7 should probably use the modern full-screen-window API on 10.7 and later.

Related

How can I detect/observe when third party app launches a full screen process?

I would like to build a helper app for gamers, and to build some extra functionality I would like to observe/time certain third party games behaviors, more specifically when the game actually launches the full screen process.
For example: my app is a system tray app, the game has a "launcher" app with lobby and menu screens. Once the game launches the extra process, usually OS X will switch resolutions (optionally) and my App would be notified somehow. Then I can start a timer. Once game match finishes, either the process is closed, or the game is not full screen anymore, my app gets a second notification and I can stop the timer.
Are there official Apple APIs that provide any way to observe/poll for the app going full screen and/or launch additional windows that I can reliably assume it's the actual game screen?
I doubt you're going to find a completely comprehensive solution. There are many ways for apps to achieve a full-screen experience and most don't provide a notification about that fact.
A full-screen app can modify the presentationOptions of NSApplication to hide the Dock and menu bar. Another app can use key-value observing to monitor its application object's currentSystemPresentationOptions property, which will reflect the current system status.
A full-screen app can capture the displays (although Apple discourages this technique). You can try to detect this by calling CGDisplayIsCaptured(), although it's been deprecated since 10.9 with no replacement. It may be possible that, if you register a callback with CGDisplayRegisterReconfigurationCallback(), you'll get called when something captures the display. However, capturing the display is sort of about preventing other processes from noticing such changes, so maybe not. In that case, you'd have to poll. You might also poll for the current display mode; changing the mode is the primary reason why a game would capture the display in the first place.
A full-screen game could also just create a borderless window the size of the screen and set its window level to be in front of the Dock and menu bar (and other apps' windows). There's not really a notification about this. You could detect it using the CGWindowList API, but you would have to poll. For example, you could call CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID) and iterate through the dictionaries looking for one the size of the screen and at a window level above kCGStatusWindowLevel.
(You might be able to use the Accessibility API to get a notification when the frontmost window changes, so you'd only have to poll when that happens.)
You cannot observe a notification if there is none. So firstly you need to know if the app you want to observe is actually sending a notification that is observable. You cannot 'hook' into other apps without their planned consent.

Objective-C Lion Fullscreen use all monitors

We have 4 monitors on a wall for graphing. Looking to put them all into use in fullscreen mode. Right now if I do it it just uses one. Just looking to see if it is possible to create an app that allows me to use all 4 with like a simple uiwebview for each monitor.
Should of mentioned this.. Looking for a simple code sample of how to do this or pointers on where to get answers.
Yes, it is possible.
Standard Lion fullscreen mode allows for one "primary window", which is sized to take up the entire main screen, and as many "auxiliary windows" (inspector panels, etc.) as you want, which are not automatically sized in any way.
Go into Xcode, create a simple project, and edit the xib. For the existing window, go to the Attributes Inspector and make sure that Full Screen is set to "Primary Window". Now in the object browser, drag three Panels into the app. Go through them and make sure each one has "Utility Panel" for Style, "Auxiliary Window" for Full Screen, and either "Inferred Behavior" or "Transient Behavior" for Exposé. Now, when the first window goes into full screen mode (e.g., when you get the appropriate notification or NSWindowDelegate method), size and move the other three windows to take over the other three screens.
This is all documented pretty well in the Implementing the Full-Screen Experience section of the "Mac App Programming Guide" in the 10.7 Core Library.
If you're just looking to put a web view on each screen, it may be easier to use -[NSView enterFullScreenMode:withOptions:]. This isn't Lion's new full-screen mode, it's the earlier technique. It has different behavior in terms of whether the app is in a separate space, etc.

Showing ProgressBar over Desktop (Transparent Window) - Cocoa

Well, it might be hard to describe, but what I want this:
When the application fires up, I want it to load a couple of components and I want to show a progress bar loading upto 100% Complete. But for Interface sake, I just want the progress bar on the desktop. I don't want the Window controls or background. My customized progress bar should appear on the desktop loading upto 100%, followed by showing of window and thereby, the entire app.
Just to mention, I want this in a Mac App being developed in Xcode.
I strongly suggest you think about the visual effect you're considering and the assumptions you're making. I would argue this to be "bad design":
Users can put anything as a Desktop Picture. If my background happens to be blue... and your custom progress bar is blue.. then I won't see the progress bar and will be left wondering why your application isn't responding. "Screw this app, it hangs when I launch it. Delete!"
Chances are that users have more than one application running. Your "floating progress bar" would be lost in a sea of other application windows. (Why is iTunes loading something? Oh wait!! It's this other windowless thing... "Not intuitive! Not cool")
This is not very Mac-like. Don't forget there are rules for each platform as to how to be a good citizen. Metro apps need to adhere to a specific Interface paradigm. Likewise, there's a thing to be said for "Mac-like" and I would argue this behaviour isn't (a floating progress bar).
I would strongly suggest you keep your progress bar within a properly named modal window. Applications go in-and-out of being front-most... so it's important to know what that progress bar relates too.
If you've considered all these, the following question should help you get started :
How to make an NSView transparent and show what's under the NSWindow?
You are probably talking of a borderless NSWindow (NSBorderlessWindowMask), with an opaque background view whose alpha is set to zero and an NSProgressIndicator subview to show the progress. You also probably want to use the -[NSWindow center] method to nicely center your window.
However, I doubt that you want that kind of UI. A progress bar is probably not visible on top of all desktops, and thus aesthetically worthless.
I think a rounded, half-transparant black window will be more suited in your case. Take a look at Matt Gemmell's source code.

Disable application activation on window click

In my Cocoa/Objective-C application I have a utility panel floating "always on top" to be accessible even when my application is not active. I am trying to disable the "switching to my application when a user clicks on that panel".
The behaviour I would like to achieve is similar to OSX's Keyboard Viewer, (which is also a never activating panel), so that some other application remained active after clicking on my app's panel. i.e. Safari stays active when typing an address using Keyboard Viewer. Even third-party onscreen keyboards have this functionality (for example the one from CORALLO Software), which means this behavior is not reserved system-only.
I was messing around with NSApplicationActivationPolicy, but without positive results. In which direction should I go?
You should take a look at the canBecomeKeyWindow and canBecomeMainWindow methods on NSWindow. It sounds like you want your window to maintain key status while not being able to be the main window. Here are some resources to help you:
Window Programming Guide - Explains the difference between main and key windows
NSWindow class reference - Jump to the sections on canBecomeKeyWindow and canBecomeMainWindow

Making a full screen Cocoa app

I want to create a full Screen Cocoa application, however my app is slightly different from a conventional fullscreen app.
This app would be below everything else, so underneath the menu bar and the Dock, etc. It would have a large image covering up the Desktop and icons, with a custom NSView in the middle with a table view, etc. If this concept is hard to understand then here is an image:
http://img10.imageshack.us/img10/6308/mockupo.png
The only part that might be a bit confusing is the background image. This background image is NOT the wallpaper of the computer, but part of the app. So when the app is launched, it goes into full screen mode and puts itself underneath the dock and the menu bar, and underneath all other windows too. So it draws the background image to cover the screen (including Desktop and icons). Then has a custom NSView in the middle containing my controls.
What's the best way to go about doing this?
Thanks
Make a borderless window, the size of the menu-bar screen (screen 0—not [NSScreen mainScreen]), positioned at 0,0, with window level kCGDesktopWindowLevel.
Remember that you will need to observe for screen frame-change notifications (when the user changes the screen dimensions), and that you should correctly handle the case of no screen at all (headless Mac).
I think #Peter Hosey’s solution should work, but to make other windows go on top, you will probably need to change the window level to something else.
But, I implore you, do not do this. This will be the most bugly application the Macintosh has ever seen. There are a lot of really good user interface paradigms that you can use, and "replicating" the main desktop interface of Mac OS X is generally not one of them. That is, unless you are reimplementing Time Machine or something like that.