How do stop panels from becomming key window on launch? - cocoa

I have a xib file with a main window and a panel. On awakeFromNib I try to orderFront the main window, but the panel keeps being key window.
- (void)awakeFromNib {
[inspectionPanelOutlet orderBack:self];
[inspectionPanelOutlet orderWindow:NSWindowBelow relativeTo:0];
[window makeKeyAndOrderFront:self];
}
This code has no effect.

Are you sure awakeFromNib is called (add an NSLog message and see if it fires)? If it is called you might want to try:
[self makeMainWindow];
or
[self makeKeyWindow];

Related

Window won't close

I made my own progress window dialog to use in my plugin for an Apple application. But when I try to close it programmatically it stays on screen. The weird thing is that closing the window has been working fine since El Capitan and it's only since Mojave that this issue has arisen.
The window is defined in a XIB file and subclassed as #interface ProgressWindow : NSWindowController.
The window is called in the plugin code with
ProgressWindow *progress = [[ProgressWindow alloc] initWithWindowNibName:#"ProgressWindow"];
[progress showWindow:self];
...
dispatch_async(dispatch_get_global_queue(0, 0), ^{
while(...) {
// do work here
dispatch_async(dispatch_get_main_queue(), ^{
[progress updatePercentage];
});
}
dispatch_async(dispatch_get_main_queue(), ^{
[progress close];
[progress release];
});
});
The progress window stubbornly stays on screen. I traced the code path to close and release the window and it is called.
Something else has taken a reference to it ?

NSWindow beginSheet completionHandler not called

I am showing a sheet within my main window. I present the sheet using this code:
AddContactWindowController *addContact = [[AddContactWindowController alloc] initWithWindowNibName:#"AddContactWindow"];
addContact.currentViewController = myView;
self.addWindowController = addContact;
[self.view.window beginSheet: addContact.window completionHandler:^(NSModalResponse returnCode) {
NSLog(#"completionHandler called");
}];
AddContactWindowController is a NSWindowController subclass. It has a view controller within it. Inside the view is a "close" button which invokes this:
[[[self view] window] close];
This does close the window, but the completionHandler from beginSheet is not invoked. This causes me problems down the road.
Is there any particular way we should close the NSWindow sheet for the completion handler to be successfully called? I've also tried [[[self view] window] orderOut:self] but that doesn't work either.
Thanks.
You will want to call -endSheet:returnCode: on your window, rather than just ordering it out.
You must properly finish the modal session.
I used to call - (void)performClose:(id)sender and stop the modal session in the delegate method.
- (void)windowWillClose:(NSNotification *)notification {
[NSApp stopModal];
}
But for a sheet, endSheet looks more appropriate.
self.addWindowController = addContact;
[self.view.window beginSheet:self.addWindowController.window];
...
...
[self.view.window endSheet:self.addWindowController.window];
self.addWindowController = nil

NSOpenGLView toggle to fullscreen from within the view

I'm trying to create a method that will toggle between fullscreen and a window. I'm trying to do this from within a class inherited from NSOpenGLView, essentially following this blogpost. That works once, going from windowed to fullscreen; trying to go back fails in various ways: the window screen doesn't get updated, or I don't even manage switch to the window but the fullscreen just blanks out. Trying to go back and forth a few times anyway (mapped it to the 'f' key), the program often locks up, and in a worst case, I have to restart my computer.
I've attached the code for the method below; for debugging purposes, I've set the full frame rectangle much smaller, so that if things freeze, the application is never at full screen.
The fullscreen example in the Apple developer examples suggest using a controller, and does not go fullscreen from within the inherited NSOpenGLView.
My questions:
should I use a controller instead, and from there switch between windowed and fullscreen (creating a separate fullscreen view each time)? Or should both methods work?
If both methods should work, which one is preferred?
If both methods can work, what am I doing wrong in the current way of implementing this?
or, is there a third, better, method?
Note that for both references, I'll have to assume that things haven't changed for 10.8 (both references seem to apply to 10.6).
Code follows:
#implementation MyOpenGLView
[...]
- (void)toggleFullscreen
{
mainWindow = [self window];
if (isFullscreen) {
[fullscreenWindow close];
[mainWindow setAcceptsMouseMovedEvents:YES];
[mainWindow setContentView: self];
[mainWindow makeKeyAndOrderFront: self];
[mainWindow makeFirstResponder: self];
isFullscreen = false;
} else {
[mainWindow setAcceptsMouseMovedEvents:NO];
//NSRect fullscreenFrame = [[NSScreen mainScreen] frame];
NSRect fullscreenFrame = { {300, 300}, {300, 300} };
fullscreenWindow = [[NSWindow alloc] initWithContentRect:fullscreenFrame
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
if (fullscreenWindow) {
[fullscreenWindow setAcceptsMouseMovedEvents:YES];
[fullscreenWindow setTitle:#"Full screen"];
[fullscreenWindow setReleasedWhenClosed: YES];
[fullscreenWindow setContentView: self];
[fullscreenWindow makeKeyAndOrderFront: self];
//[fullscreenWindow setOpaque:YES];
//[fullscreenWindow setHidesOnDeactivate:YES];
// Set the window level to be just above the menu bar
//[fullScreenWindow setLevel:NSMainMenuWindowLevel+1];
// Set the window level to be just below the screen saver
[fullscreenWindow setLevel:NSScreenSaverWindowLevel-1];
[fullscreenWindow makeFirstResponder:self];
isFullscreen = true;
} else {
NSLog(#"Error: could not switch to full screen.");
}
}
}
[...]
#end
I now think this can't be done, and should not be done. When windowed, the rendering context is a window, which is a different beast than a screen, when rendering fullscreen.
Thus, when switching between, things have to re-setup everytime you switch.
It is possible to simply use the native fullscreen option that is in the newest OS X variants. This will (presumably) enlarge the containg window to full screen size while removing the frame, borders and buttons. Thus, you're still rendering to a window, though it looks fullscreen.
I'm not sure if this option makes things slower: there's a window layer in between, which could make it a slower than rendering directly to a screen.
For the curious, implementing the native fullscreen is ridiculously easy (at least in 10.8 and 10.9): In XCode, select the .xib file, select the (main) window in the editor's sidebar, then select the attributes selector on the right. You can find a "Full Screen" selection between Unsupported, Primary Window or Auxiliary Window. That will automatically add the full screen toggle to the window.
Even neater, now select the main menu -> view menu in the sidebar, find the "Full Screen Menu Item" in the inspector at the bottom (there's a search bar for it), drag it into the View menu in the editor, and voilĂ , it will have a shortcut and automatically connect to the full screen option for the window (select the new View menu item and look at the Connections inspector to it's already connected for you).
A nice way to test all this is to grab the full screen example I linked in my question, and edit it as suggested above. Using the default control-command F shortcut to toggle back and forth between fullscreen will show the opengl view and the frame with text below it in a full screen. Using the fullscreen option as coded in the example will toggle the openglview to use the fullscreen, without any extra (Cocoa) frames, buttons or text.
I'm curious about this too- specifically your first two bullet point questions.
This doesn't address those questions, but your third one about the bug, I think you can get away with just changing the properties of the same window (works for me):
- (void)toggleFullscreen
{
if (isFullscreen) {
NSRect windowFrame = [[NSScreen mainScreen] visibleFrame];
[mainWindow setStyleMask:NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask | NSResizableWindowMask ];
[mainWindow setFrame:windowFrame display:true];
[mainWindow setAcceptsMouseMovedEvents:YES];
[mainWindow setLevel:NSNormalWindowLevel];
[mainWindow setTitle:#"SimpleOculus"];
[mainWindow makeKeyAndOrderFront:self];
[mainWindow makeFirstResponder:self];
isFullscreen = false;
}
else {
NSRect fullscreenFrame = [[NSScreen mainScreen] frame];
[mainWindow setStyleMask:NSBorderlessWindowMask];
[mainWindow setFrame:fullscreenFrame display:true];
[mainWindow setAcceptsMouseMovedEvents:YES];
[mainWindow setLevel:NSScreenSaverWindowLevel-1];
[mainWindow makeKeyAndOrderFront:self];
[mainWindow makeFirstResponder:self];
isFullscreen = true;
}
}

Modal session requires modal window

I'm trying to open a window like a sheet so that it appears down below the toolbar. I've used the O'Reilly tutorial to do this. However, I can get past this error: Modal session requires modal window.
The window loads as a window if I have "Visible At Launch" checked.
Whether it is checked or not I get the "Modal session requires modal window" error.
I have a Window.xib, ProgressModal.xib.
In the Window implementation file I use:
-(IBAction)loadProgress:(id)sender{
[self progressStatus:progressWindow];
}
- (void)progressStatus:(NSWindow *)window {
[NSApp beginSheet: window
modalForWindow: mainWindow
modalDelegate: nil
didEndSelector: nil
contextInfo: nil];
[NSApp runModalForWindow: window];
[NSApp endSheet: window];
[window orderOut: self];
}
- (IBAction)cancelProgressScrollView:(id)sender {
[NSApp stopModal];
}
I may have the ProgressModal.xib setup wrong. I have an NSObject in it that has "Window" as its class. All the connections are made through that.
But again, it loads the window just won't load it as a modal.
Any ideas?
Put the following in the first line of your progressStatus method:
NSLog(#"%#", window);
If you see the log output is null, that's the reason why.
Steps to create a modal sheet using XIB:
Drag a panel to your MainMenu.xib
Add #property (assign) IBOutlet NSPanel *sheetPanel; in your AppDelegate.h file
#synthesize sheetPanel = _sheetPanel; in the AppDelegate.m file
Link a New Referencing Outlet of the panel in the MainMenu.xib created in the step 1 to the sheetPanel property created in step 2.
Using following code to show the modal sheet:
[NSApp beginSheet:_sheetPanel
modalForWindow:_mainWindow
modalDelegate:self
didEndSelector:#selector(didEndSheet:returnCode:contextInfo:)
contextInfo:nil];
As I stated above, I dragged an object over in the progressModal window and made my connections through that. What I should have done was made the File's owner my Window class. Changing that fixed the problem.
I got this from http://www.youtube.com/watch?v=QBkO6TD-fWA
Edit: I assumed you wanted a modal window. If you want a sheet, don't use runModalForWindow: at all.
Try this:
[NSApp beginSheet: window
modalForWindow: mainWindow
modalDelegate: nil
didEndSelector: nil
contextInfo: nil];
It's a good idea to define a callback just in case you need it though; e.g.
[NSApp beginSheet: window
modalForWindow: mainWindow
modalDelegate: self
didEndSelector: #selector(sheetDidEnd:returnCode:contextInfo:)
contextInfo: nil];

makeKeyAndOrderFront only does the latter

I am trying to open one window from another using makeKeyAndOrderFront. The new window appears, but does not receive focus.
The code for the main window is:
#import "SecondWindowController.h"
#implementation FirstWindowController
-(IBAction)showSecondWindow:(id)sender
{
if (!secondWindowController)
secondWindowController = [[SecondWindowController alloc] init];
[[secondWindowController window] makeKeyAndOrderFront:self];
}
SecondWindowController is a NSWindowController, as follows:
#implementation SecondWindowController
-(id)init
{
if (![super initWithWindowNibName:#"SecondWindow"])
return nil;
return self;
}
I've also tried putting [secondWindowController showWindow:self] before the makeKeyAndOrderFront but it doesn't make a difference.
Did you make sure the window outlet for SecondWindowController is hooked up to the window in your NIB? The window could be displayed just by loading the NIB, even if the outlet is not hooked up.
Are you using a borderless window? If so you need to override canBecomeKeyWindow and return YES
Try this:
if (!secondWindowController)
secondWindowController = [[SecondWindowController alloc] init];
NSApplication *thisApp = [NSApplication sharedApplication];
[thisApp activateIgnoringOtherApps:YES];
[[secondWindowController window] makeKeyAndOrderFront:self];

Resources