Re: Opening a NSSavePanel as a Sheet, and blocking like in [panel runModal]
Re: Opening a NSSavePanel as a Sheet, and blocking like in [panel runModal]
- Subject: Re: Opening a NSSavePanel as a Sheet, and blocking like in [panel runModal]
- From: Steve Christensen <email@hidden>
- Date: Wed, 21 Oct 2009 15:23:43 -0700
On Oct 21, 2009, at 4:11 AM, Motti Shneor wrote:
Hello Steve, and thanks a lot. Your category is exactly what I
needed. Although I already figured out myself the use of
[NSApp runModalForWindow:] for blocking and the [NSApp:stopModal]
to release the block, I still enjoyed the way of doing this
seamlessly via a category. In my case I need 2 categories for
NSSavePanel and NSOpenPanel, and some more implementation details.
However... I still have a few questions about your implementation,
another about another implementation I found in an Apple sample,
AND.... this code has TERRIBLY WEIRD and unstable behavior, when
attaching these NSSavePanel sheets to a (Cocoa-wrapper of) Carbon
Window.
So. First, I'd like to know, why you call on [NSApp endSheet:self];
after the modal loop is ended? If I'm not wrong, the "sheetDidEnd"
selector is only called AFTER the sheet has been dismissed, closed,
and released. I tried without calling this, and could see no
difference in behavior. Isn't there a problem in calling this when
no sheet is open?
In the docs for -[NSSavePanel
beginSheetForDirectory:file:modalForWindow:modalDelegate:didEndSelector:
contextInfo:], it says that the selector "method is invoked [...]
after the modal session has ended, but before dismissing the Save
panel. didEndSelector may dismiss the Save panel itself; otherwise it
will be dismissed on return from the method," so the sheet hasn't
actually been dismissed at that point. I believe I included it in
case [NSApp runModalForWindow:self] failed for some reason to make
sure the sheet was always removed.
Second. In another Apple Sample, which does almost the same, using
a newer NSSavePanel 10.6 API's , there's something like
NSSavePanel *navPanel = [NSSavePanel savePanel];
[navPanel beginSheetModalForWindow: [sender window]
completionHandler:^(NSInteger result)
{
NSLog(@"Save panel dismissed - callback block reached.");
if (result == NSOKButton) {
[navPanel orderOut:self]; // close panel before we might present an
error // [self application:NSApp openFile:[openPanel filename]];
}
[NSApp stopModal]; // end modal mode
}]; // this call exists immediately, but I need to block here, so...
[NSApp runModalForWindow: [sender window]];
}
Here, as you can see, there is another call .[navpanel
orderout:self]; Again, isn't the conclusion block called AFTER the
sheet was dismissed, closed and released? (my NSSavePanels are
configured to "releaseWhenClosed"]. Also, what exactly is
"orderout" ? could'nt figure out from the documentation.
-[NSWindow orderOut:]
Last (and most important) - Supposedly I use your nice category
like this:
WindowRef frontWin = ::FrontWindow(); // get Carbon application
front window. Actually, any carbon window.
NSWindow *cocoaFromCarbonWin = [[NSWindow alloc]
initWithWindowRef:frontWin];
NSSavePanel *navPanel = [NSSavePanel savePanel];
[navPanel runModalForDirectory:nil file:nil types:nil
relativeToWindow: cocoaFromCarbonWin];
Then I'm seeing a host of strange and bogus behaviors.
1. The most severe is that the sheet opens BEHIND the application
window, BUT is still the key window. So, the application is dead
--- I can't click on the sheet (it's not front, and not active,
does not respond to clicks). However, the main application window
is blocked for events too! (I have blocked it via
runModalForWindow!). so, I'm dead. User must force-quit the
application.
2. The sheet opens in the wrong place -- just somewhere on the
screen - not always the same place, but "favorably" when a centered
dialog would appear. If then I try to drag the parent carbon window
by its title, the sheet would "jump into place" and be dragged
right. Events seem to be OK.
3. The sheet is invisible --- Although I get no errors from the
application. However, the debugger console would (sometimes!)
contain lines like this:
[Session started at 2009-10-21 11:01:52 +0200.]
GNU gdb 6.3.50-20050815 (Apple version gdb-1346) (Fri Sep 18
20:40:51 UTC 2009)
Wed Oct 21 12:11:53 Moti-Schneors-Mac-Pro.local NavTester[4398]
<Error>: kCGErrorIllegalArgument: _CGSFindSharedWindow: WID 1835
Wed Oct 21 12:11:53 Moti-Schneors-Mac-Pro.local NavTester[4398]
<Error>: kCGErrorFailure: Set a breakpoint @ CGErrorBreakpoint() to
catch errors as they are logged.
Wed Oct 21 12:11:53 Moti-Schneors-Mac-Pro.local NavTester[4398]
<Error>: kCGErrorIllegalArgument: CGSOrderWindowListWithGroups:
invalid window ID (1835)
Wed Oct 21 12:11:53 Moti-Schneors-Mac-Pro.local NavTester[4398]
<Error>: kCGErrorIllegalArgument: CGSOrderWindowList: NULL list
pointer or empty list
Wed Oct 21 12:11:53 Moti-Schneors-Mac-Pro.local NavTester[4398]
<Error>: kCGErrorIllegalArgument: _CGSFindSharedWindow: WID 1836
Wed Oct 21 12:11:53 Moti-Schneors-Mac-Pro.local NavTester[4398]
<Error>: kCGErrorIllegalArgument: CGSOrderWindowListWithGroups:
invalid window ID (1836)
Wed Oct 21 12:11:53 Moti-Schneors-Mac-Pro.local NavTester[4398]
<Error>: kCGErrorIllegalArgument: CGSOrderWindowList: NULL list
pointer or empty list
Any ideas? something I forgot to do? What in general is the state
of opening cocoa-sheets over Carbon-windows? When do I need to
release this NSWindow? I don't wish to close the Carbon window, as
it is coming from my host application!
You may not want to call FrontWindow() since its docs say, "Most
applications should use call ActiveNonFloatingWindow or
FrontNonFloatingWindow instead of FrontWindow because
ActiveNonFloatingWindow and FrontNonFloatingWindow return the active
and frontmost document window, respectively, skipping over other
types of windows that may be in front of the active document, such as
the menubar window, floating windows, help tags and toolbars."
On 15/10/2009, at 21:40, Steve Christensen wrote:
I had written this NSOpenPanel category to work in a plugin
environment, and I think it should do the right thing. Just set up
the NSOpenPanel as you like then call -
runModalForDirectory:file:types:relativeToWindow: and it will return
when the user has selected (or not) a file.
steve
// category on NSOpenPanel that runs the open sheet modally and
returns when done
@interface NSOpenPanel(ModalSheets)
- (NSInteger)runModalForDirectory:(NSString*)path file:(NSString*)
name types:(NSArray*)fileTypes relativeToWindow:(NSWindow*)window;
@end
@implementation NSOpenPanel(ModalSheets)
- (void)__modalOpenPanelDidEnd:(NSOpenPanel*)panel returnCode:(int)
returnCode contextInfo:(void*)contextInfo
{
#pragma unused(panel, contextInfo)
[NSApp stopModalWithCode:returnCode];
}
- (NSInteger)runModalForDirectory:(NSString*)path file:(NSString*)
name types:(NSArray*)fileTypes relativeToWindow:(NSWindow*)window
{
NSInteger result;
if (window != nil)
{
[self beginSheetForDirectory:path file:name modalForWindow:window
modalDelegate:self didEndSelector:@selector
(__modalOpenPanelDidEnd:returnCode:contextInfo:) contextInfo:nil];
result = [NSApp runModalForWindow:self];
[NSApp endSheet:self];
}
else
{
result = [self runModalForDirectory:path file:name types:fileTypes];
}
return result;
}
@end
On Oct 14, 2009, at 6:02 AM, Motti Shneor wrote:
I'm in a strange situation, where I am implementing a plugin
component that runs within a host application which I don't have
access to.
Within this context, The host sometimes calls my plug-in to open an
NSSavePanel (or NSOpenPanel). The host expects that I'm synchronous
--- i.e. I only return when the NSSavePanel is dismissed, and
there's a result.
However, The host also provides me with its own Window, and I need
to open my NSSavePanel as a Sheet-window over the host's window.
Now NSSavePanel (and NSOpenPanel) provide 2 different ways to run them
1. runModal (or a vaiant) that is synchronous --- but it does not
create a sheet window
2 beginSheetFor... (or variants) that are asynchronous (I must
supply with a callback selector to be called as the NSSavePanel is
dismissed) --- these DO create a sheet over the parent window.
Is there a decent way to combine these two requirements?
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden