HOWTO: Is NSWindow In FullScreen Mode (Lion) AND Enabling/Disabling? - objective-c

I spent a great deal of time figuring out how to determine if my NSWindow is in full screen mode or not and also how to enable/disable it from going in or out of full screen mode. This is useful when I am animating a view to another view or doing something where going into or out of full screen mode will mess stuff up. Sort of like locking down a window from being resized.
The answer to this is posted below.

For anyone interested here are some methods you can categorize or use as is. I spent some time looking for how to do this and thought it can help someone else out:
This one will tell you if you are or are not in full screen mode:
#implementation MyWindow
- (void) setStyleMask:(NSUInteger)styleMask {
MyWindowController *wndController = (MyWindowController *)self.windowController;
wndController.fullScreenMode = (styleMask & NSFullScreenWindowMask);
[super setStyleMask:styleMask];
}
#end
I am setting a property in my window controller.
For completeness here is what the category on NSWindow would look like:
#implementation NSWindow (CategoryNSWindow)
#pragma mark - Full Screen Mode:
- (BOOL) inFullScreenMode {
return (self.styleMask & NSFullScreenWindowMask);
}
#end
These two methods will enable / disable the ability to go into or out of full screen mode:
- (void) enableFullScreen {
NSWindowCollectionBehavior behavior = [self.window collectionBehavior];
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
[self.window setCollectionBehavior:behavior];
}
- (void) disableFullScreen {
NSWindowCollectionBehavior behavior = [self.window collectionBehavior];
behavior ^= NSWindowCollectionBehaviorFullScreenPrimary;
[self.window setCollectionBehavior:behavior];
}
Rename methods as you please.

There are two events of NSWindowDelegate
DidWindowEnterFullScreen
DidWindowExitFullScreen
which help you solve your problem.

The two events of NSWindowDelegate are:
– windowDidEnterFullScreen:
– windowDidExitFullScreen:

Related

Set focus of NSWindow on top, even if changing of virtual desk

I'm doing an application which consists of asking a question after a certain time, and the user can't do anything more, unless he answers the question, I've managed to mantain the window always on top by setting a 9999 level:
[_idleWindow setLevel:9999];
I would like to know if there is a way to avoid changing virtual desktop when the window is open, or to focus the window again when you change the virtual desktop.
Look at setCollectionBehavior:
[_idleWindow setCollectionBehavior:NSWindowCollectionBehaviorMoveToActiveSpace|NSWindowCollectionBehaviorTransient|NSWindowCollectionBehaviorFullScreenDisallowsTiling|NSWindowCollectionBehaviorFullScreenAuxiliary];
might do the trick.
Also, if you can use NSPanel instead of NSWindow, you can add the style mask: NSWindowStyleMaskNonactivatingPanel to give your window key status even when your app isn't active. (you'll need to implement canBecomeKeyWindow in the NSPanel subclass)
After a few researches on Google, I have found the solution on another Stackoverflow post.
Solution:
You need to add this code either in your xib / storyboard, either in your NSWindowController subclass -windowDidLoad method, either in your designated initialiser of your NSWindow subclass :
- (void) awakeFromNib {
[self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]; //this was the one that worked for me
}
OR
- (id)initWithContentRect:(NSRect)contentRect
styleMask:(NSUInteger)styleMask
backing:(NSBackingStoreType)bufferingType
defer:(BOOL)flag {
if (self = [super initWithContentRect:contentRect styleMask:styleMask backing:bufferingType defer:flag]) {
[self setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];
}
return self;
}
OR if you have a NSWindowController
- (void)windowDidLoad {
[super windowDidLoad];
[[self window] setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces];
}
OR Edit the nib file and add this behaviour to your window in XCode.
Credits: Stefan Szekeres

How to communicate between two NSView objects?

With Cocoa, I hope to display one image in one image view. Whenever I click on the showed image. A piece of predefined-size of the image around the click point will be shown in another image view in the same window with the first one. So details will be seen.
To do this, I write my own MyImageView inherited from NSImageView. In this class, I implement the mouseUp method. In this method, I do all the image coordinate things. I can do this right so far. And the new piece will be stored as a property.
#import "MyImageView.h"
#implementation MyImageView
#synthesize point;
#synthesize small_img;
#synthesize big_img;
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.point = NSMakePoint(0.0, 0.0);
}
return self;
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
}
- (void)mouseUp:(NSEvent *)theEvent
{
//calculate the small image and stored in small_img
}
#end
Then I initialize an instance in the AppDelegate and do something like
[small_view setImage: myImageView.small_img]
But no small image will show.
It seems a delegate mechanism will work out. However, I am very confused with the View-Controller-Delegate pattern. And I can't find any material explaining the communication between two NSView subclass objects with sample code I can understand. I am totally a novice in this domain.
Hope somebody help me get this done since it's very important to me.Thanks!
You're right about the delegate mechanism could work. But there are other options.
Basically you have two ImageViews (or subclasses) and they can't communicate. The only piece they have in common is the container or owner (usually a ViewController, but it could be the AppDelegate), so let's call this object just the owner.
To communicate, the clicked ImageView would need to notify the owner that something happened, and the owner in turn would forward this notification to the second ImageView. The first notification can be done through a delegate, and the second method is straightforward (calling [mySecondImageView someMethod];)
It would be too long to explain here how to use a delegate, and there are many examples out there. In short, the first ImageView has a delegate property and the owner sets itself as the delegate (something like myFirstImageView.delegate = self];
If this is too complicated, another solution which might fit well here is using Notifications. Again, there are many examples, but in short, a notification would allow communicating your two ImageViews without intervention of the owner. This type of communication is good for loosely coupled objects.
EDIT:
You can of course set the second view as the delegate and it would work perfectly. I personally like to centralize control over all my objects in my ViewController, but this is my personal preference.
What kind of delegate you need? You would need to create a custom delegate (a #protocol).
#protocol imageViewProtocol
- (void)imageClicked:(... arguments...);
#end
Your FirstImageView would have a property declared in the #interface.
#interface FirstImageView ...
#property (...) id<imageViewProtocol> delegate;
...
#end
#implementation FirstImageView ...
- (void)ImageClick:(id)sender
{
// do stuff
[self.delegate imageClicked:(...arguments...)];
}
#end

Redrawing a view in ios

Is it possible to redraw the whole view.
I need it to complete my language settings. The problem is that the language only changes after the views there drawn again. Like you go out of settings and then go in again, then the language is changed. But the moment you save everything, the language stays the same.
So how should i redraw my views, or by best the whole app, after the language change was found?
In ARC:
- (void)setLanguage:(LanguageType)languageType
{
_language = languageType;
//TODO:your settings
[_theWholeView setNeedsDisplay];
}
If that can not work , there is a very troublesome solution , it can reload the whole view.
You can code like this:
In the view.h , you need creat a delegate.
#protocol WholeViewDelegate
- (void)reloadData;
#end
In the view.m
- (void)setLanguage:(LanguageType)languageType
{
_language = languageType;
//TODO:your settings
[_delegate reloadData];
}
In the controller you need to implement the delegate
In the controller.m
- (void)reloadData
{
if(_wholeView)
{
[_wholeView removeFromSuperview];
}
// in the wholeView init method you should refresh your data
_wholeView = [[WholeView alloc] init];
self.view addSubview:_wholeView
}
Yes. Call [UIView setNeedsDisplay] (reference).
Just call setNeedsDisplay.. It will resolve the problem. setNeedsDisplay actually calls the drawRect function in the UIView class by passing the frame of the view as the rectangular parameter. Hope that helps....

Window ordering and XIB

I am setting my first steps in OSX development and I've run into some problems. I have quite some experience with iOS development but the window system for OSX programs is something else.
I am making a client for a social network like twitter and need 2 seperate window controller for first starting the app, one if you are logged in to show your timeline and one for logging in, if you are not yet logged in. In the info.plist you need to give it a main.xib. For this I made an empty xib which I hide, the second the app starts. This is not really a good solutions IMO, what is a better solution for this? I want to keep the windows seperate from the appdelegate because that way I can keep my code seperated.
This gives me a problem, when I open my 'second' window to login it shows up but isn't active. I have tried all the things like, orderFront:, activateIgnoringOtherApps:, makeKeyAndOrderFront: & more. But this all doesn't work..
So: First off, is there a better way to handle the main.xib that is needed in the info.plist and if not, is there a way around the focus problem?
I'm working om osx 10.7
For more than one-offs, you really ought to separate your app delegate from your window controllers. Go ahead and create a new Cocoa application from the template. In MainMenu.xib, delete the window. In AppDelegate.h delete the IBOutlet to the NSWindow. Create a couple new subclasses of NSWindowController complete with XIBs--perhaps LoginWindowController and TimelineWindowController.
For "final" NSWindowController subclasses (i.e. those which won't be subclassed), the best practice for designated initializers is
//for our example class LoginWindowController
- (id)init
{
self = [super initWithWindowNibName:#"LoginWindowController"];
if (self) {
//....
}
return self;
}
Now in your app delegate, you should have #properties for the two different window controller instances:
//Within AppDelegate.m
#import "AppDelegate.h"
#import "LoginWindowController.h"
#import "TimelineWindowController.h"
#interface AppDelegate ()
#property (nonatomic) LoginWindowController *loginWindowController;
#property (nonatomic) TimelineWindowController *timelineWindowController;
//For the sake of this demo, add a property for the loggedIn state:
#property (nonatomic) BOOL loggedIn;
#end
You ought to have some sort of method in your app delegate that presents the correct window controller. Let's call it -updateWindowVisibility:
- (void)updateWindowVisibility
{
BOOL isLoggedIn = self.loggedIn;
BOOL loginWindowVisible = self.loginWindowController.window.isVisible;
BOOL showLoginWindow = !isLoggedIn;
BOOL timelineWindowVisible = self.timelineWindowController.window.isVisible;
BOOL showTimelineWindow = isLoggedIn;
if (!loginWindowVisible && showLoginWindow) {
if (!self.loginWindowController) self.loginWindowController = [[LoginWindowController alloc] init];
[self.loginWindowController showWindow:nil];
} else if (loginWindowVisible && !showLoginWindow) {
[self.loginWindowController close];
self.loginWindowController = nil;
}
if (!timelineWindowVisible && showTimelineWindow) {
if (!self.timelineWindowController) self.timelineWindowController = [[TimelineWindowController alloc] init];
[self.timelineWindowController showWindow:nil];
} else if (timelineWindowVisible && !showTimelineWindow) {
[self.timelineWindowController close];
self.timelineWindowController = nil;
}
}
This method as implemented above does a tiny bit more work than is necessary given the present setup, but should be easier to modify when you need to show/hide other windows. All that's left to do at this point is to call -updateWindowVisibility from -applicationDidFinishLaunching:.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
self.isLoggedIn = NO;
[self updateWindowVisibility];
}
I've posted an example app to github which demonstrates this approach.
In terms of structure (your first question), I would recommend this:
Create a XIB with one blank window and a big NSView (called, say, megaView) covering it. Create an IBOutlet in AppDelegate for your big NSView. Set the app to use this XIB on load.
Create two separate NSView XIBs: one for the state of being logged in, one for the state of being logged out. Put your layout in these.
Create two NSViewController subclasses: one controlling the logic of each NSView you just created. Let's call them LoggedOutViewController and LoggedInViewController.
Jump back to the two NSViews you created. Set the File Owner of your logged in NSView to LoggedInViewController and the File Owner of your logged out NSView to LoggedOutViewController. Hook up each File Owner's view (right-click on File Owner to find it) to the respective NSView.
In your app delegate, determine the user's authentication status in whatever way you need.
If logged in, do this:
NSViewController *loggedInController = [[NSViewController alloc] initWithNibName:#"NibNameGoesHere" bundle:nil];
[[self megaView] addSubview:[loggedInController view]];
Otherwise do the above process with your loggedOutController:
NSViewController *loggedOutController = [[NSViewController alloc] initWithNibName:#"OtherNibNameGoesHere" bundle:nil];
[[self megaView] addSubview:[loggedOutController view]];
That should get you what you want and will likely clear up your second question in the process. The difference between my answer and Nate's is that mine uses the same window. Instantiating view controllers conditionally and loading their views into superviews is probably the most important aspect of Cocoa I learned.

Topbar cannot rotate in landscape view with storyboard

I have just converted from .nib files to storyboard, but suddenly the view wont rotate topbar in landscape view. All the settings are "inferred" in my view, and i have not really made any changes since the conversion.
Is this a common problem when upgrading? I have not found any specific info.
And furthermore i do not force any view rotations in my code.
If any more info is needed i can supply anything!
Thanks in advance.
ViewController:
- (void) viewDidLoad {
[super viewDidLoad];
self.view.autoresizingMask = UIViewAutoresizingNone;
self.view.autoresizesSubviews = UIViewAutoresizingNone;
}
I've taken a look at your code and you seem to be missing a method that allows your view controller to rotate freely.
Subclass UIViewController e.g. like this:
// .h file
#interface OrientationAwareViewController : UIViewController
#end
// m.file
#implementation OrientationAwareViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
#end
Then set OrientationAwareViewController in the storyboard as your main view controller's class name. That said, I have no idea how this worked for you when using nibs :) Documentation says clearly:
By default, this method returns YES for the UIInterfaceOrientationPortrait orientation only. If your view controller supports additional orientations, override this method and return YES for all orientations it supports.