Are sheet windows not supposed to be modal for their window?


I have a window that I present as a sheet over my main window using:

on showSheetWindow_(aNotification)
   sheetWindow's showOver_(mainWindow)

It is released by :

on hideSheetWindow_(aNotification)
   current application's NSApp's endSheet_(sheetWindow)

But when I pass the command “Close” to the main window, this command gets executed: the main window is closed, with its sheet window still deployed. Then, when the main window is opened with an “open” command, its toolbar stays deactivated, and the handler showSheetWindow_ don’t shows the sheet window, but beeps.

This is a recurrent error in my app, I know that I do something wrong, but what?


You shouldn’t close the window while the sheet is showing.

Ok, I’ve been warned – how do I prevent my innocent users to close the main window? :slight_smile:

It depends on whether you’re a doc-based app or not. You can probably just implement the window delegate method windowShouldClose: and have it check to see if there’s a sheet open. If that doesn’t work, disable closing in your code by temporarily disabling the Close menu item (in validation or directly), and disabling the close button with something like:

mainWindow's standardWindowButton_(current application's NSWindowCloseButton)'s setEnabled_(false)

It looks like you don’t need to disable the close menu item (at least in the app I tried it in), adding the line that Shane suggested disables the menu item as well.


Thanks. I though it might depend on whether the menu item calls a simple close or performClose:.

Could this post from Shane (Run sheets app modal: it can be done) solve my problem or not?

Another solution is : make the Close menu item conditionally enabled in IB with the Model Key Path mainWindow.isKeyWindow

(I’m not sure this is really “cocoa-compliant” but it works.)

I tried Shane’s code in the link you posted, and it didn’t work. I get an error message: unable to set argument 5 because the AppleScript value <NSAppleEventDescriptor: ‘msng’> could not be coerced to type :.

This actually means argument 4, which is the selector. So, I put in “dummy:” as the selector because the docs say that if the delegate parameter is nil, then the selector never gets called – wrong again. It tries to call it any way, and you get another error message. So, I found that you could supply the delegate and the selector, and despite what the docs say, the selector doesn’t have to have the signature that is listed in the docs. I ended up with the following code, which does work to give you an app modal sheet:

on showSheetModal_(sender)
		current application's NSApp's beginSheet_modalForWindow_modalDelegate_didEndSelector_contextInfo_(messageWindow, mainWindow, me, "endSession:", missing value)
		current application's NSApp's runModalForWindow_(messageWindow)
		-- execution pauses here because this code is outside window's control
		messageWindow's orderOut_(me) -- This is necessary to close the sheet
	end showSheetModal_
	on endSession_(sender)
		log sender's |tag|()
		current application's NSApp's stopModal() -- so above code resumes
	end endSession_

You can put as many buttons in the sheet as you want, and get their tags if you need to do different things depending on which button was clicked to close the sheet. I also deleted the line “tell current application’s NSApp to endSheet_(messageWindow)” that Shane had – it’s not necessary, and in fact cause the closeSheet method to be called again (given my code).


I think you’ll find that it still works, despite the error – you just ignore it. There are several apps out there using this method…

You mean, it’s like we had:

   current application's NSApp's runModalForWindow_(messageWindow)
   messageWindow's orderOut_(me) -- This is necessary to close the sheet

as an equivalent, because I suppose the execution makes the first part of the code to be lost, saving only a return address.