2
votes

In most systems, the default behaviour for "open a new window" is that it appears at the front. This doesn't happen in Cocoa, and I'm trying to find the "correct" way to make this standard behaviour. Most things I've tried only work for a maximum of one window.

I need to open multiple windows on startup:

  • (N x NSDocuments (one window each)
  • 1 x simple NSWindowController that opens a NIB file.

Things that DON'T work:

  1. Iterate across all the NSDocuments I want to open, and open them.

What happens? ... only the "last" one that call open on comes to the front - the rest are hidden, invisible, nowhere on the screen, until you fast-switch or use the Window menu to find them.

Code:

...documents is an array of NSPersistentDocument's, loaded from CoreData...

[NSDocumentController sharedDocumentController];
[controller openDocumentWithContentsOfURL:[documents objectAtIndex:0] display:YES error:&error]; 
  1. Manually invoking "makeKeyAndOrderFront" on each window, after it's opened

What happens? nothing different. But the only way I can find to get the NSWindow instance is so horribly hacky it seems totally wrong (but is mentioend in several blogs and mailing list posts)

Code:

[NSDocumentController sharedDocumentController];
NSDocument* openedDocument = [controller openDocumentWithContentsOfURL:[documents objectAtIndex:0] display:YES error:&error]; 
[[[[openedDocument windowControllers] objectAtIndex:0] window] makeKeyAndOrderFront:nil];

...I know I'm doing this wrong, but I can't find out why/what to do differently :(.

Something that works, usually, but not always:

  1. As above, but just use "showWindow" instead (I took this from the NSDocument guide).

Bizarrely, this sometimes works ... even though it's the exact code that Apple claims they're calling internally. If they're calling it internally, why does it behave different if I re-invoke it after they've already done so?

[[[openedDocument windowControllers] objectAtIndex:0] showWindow:self];
3
I also tried the third option, but using performSelector:withObject:delay: ... and it still only works randomly maybe 50% of the time, for delays of up to 1 second or so ... so I'm sure that's - somehow - fundamentally wrong, or else it would work?Adam

3 Answers

1
votes

You can just open all the documents without displaying and then tell the documents to show their windows:

NSArray* docs = [NSArray arrayWithObjects:@"doc1.rtf", @"doc2.rtf",@"doc3.rtf",@"doc4.rtf",nil];

for(NSString* doc in docs)
{
    NSURL* url = [NSURL fileURLWithPath:[[NSHomeDirectory() stringByAppendingPathComponent:@"Documents"] stringByAppendingPathComponent:doc]];
    NSError* err;
    [[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:url display:NO error:&err];
}

[[[NSDocumentController sharedDocumentController] documents] makeObjectsPerformSelector:@selector(showWindows)];
1
votes

Won't this work?

For 10.6 or greater

[[NSRunningApplication currentApplication] activateWithOptions:(NSApplicationActivateAllWindows | NSApplicationActivateIgnoringOtherApps)];
0
votes

This often has something to do with the app itself: your other windows are behind other apps (in particular, behind Xcode!), and would have appeared with a Hide Others command.

The solution to that problem would be that after you send showWindow to all of your windows (making sure you do the key one last), you tell the app to come forward, relative to other apps.

NSApp.activateIgnoringOtherApps(true)  // Swift

or

[NSApp activateIgnoringOtherApps:YES];  // Objective-C

See also: How to bring NSWindow to front and to the current Space?