NSWindow delegate (windowShouldClose) - cocoa

In one of my first Cocoa applications I have just a single window with 2 NSTextField instances - for user text input and of output of text processing.
If my user clicks on the red x on the top left, the window closes but the application is still running and icon stays in the dock - the normal Mac behavior.
When the user double-clicks on the icon in dock or on the desktop, this does not reopen the window - apparently also normal Mac behavior, but confusing to the user.
To get the app back into a running state, the user has to force Quit from the main menu or the context menu, and restart the app by clicking on one of the icons.
I searched Apple doc and forums, and it seemed that the following should prevent the closing of the window (my first preference : hide the widow so it can be reopened later) :
add a delegate to NSApp
delegate implements -applicationShouldHandleReopen which calls [mainWindow makeKeyAndOrderFront:self]; and returns TRUE
delegate implements -windowShouldClose which returns FALSE
However, although -windowShouldClose is called, the window closes.
What am I missing here?
As an alternative (my second preference), I added to the delegate
-applicationShouldTerminateAfterLastWindowClosed which returns YES
This works, i.e. the application closes when the used clicks on the red x,
and the user can restart the app later without further ado.
Clarifications and pointers to specific doc and working code examples would be appreciated.
Rudi

"When the user double-clicks on the icon in dock or on the desktop, this does not reopen the window - apparently also normal Mac behavior, but confusing to the user."
If you want the window to re-open in that case, implement applicationShouldHandleReopen:hasVisibleWindows:. There's nothing un-Mac-like about opening a window when the user clicks the dock icon after closing all the windows; lots of apps do it and the delegate exists specifically to support that behavior.

First of all, your "alternative" behavior of terminating the app on window close is probably the preferred approach for your situation. Users may be confused when they can't close the window.
If you really want to prevent the window from being closed, why not just disable the close control on the window in IB?

Related

Return focus to previous app's window after makeKeyAndOrderFront

I have a status bar menu app - it doesn't run in the Dock (UIElement is YES).
After a user-defined period, it brings one of its window to the front (using makeKeyAndOrderFront). An NSTimer is set up to get rid of it after a few seconds - I close the window and hide the app with:
[NSApp hide];
My question is, how can I bring the previous app's window back to the front? It's visible but not the front/focus window.
EDIT: If it helps to clarify what I'm trying to do, when you invoke the application Dash with the keyboard shortcut and then dismiss it, the app that was previously front, returns to the front.
I was overthinking - as a user, it's possible to hide an app, which automatically restores focus to the window in the app next in line. That's all I had to do in code:
[NSApp hide:nil];
To play nicely with full-screen apps, I also have to close the window in my app, even though it's been hidden - otherwise, when my app's window is next shown, OS X jumps to the Space where my window was last seen, a jarring experience.
[self.theWindow close];

How to close every visible windows with shortcut "Command + W"

Working on a simple App that work with a secondary preferences window i found a behavior that i can't understand.
When i open the preferences window if i press Cmd + W i close only the main window.
Is this a standard behavior ? Which is the best way to implement a way to close every windows ?
[[NSApp windows] makeObjectsPerformSelector:#selector(close)];
is a programmatic way to close all windows, but that's really not good design, because the user doesn't expect Command+W to close all windows of an applications. That's what Command+Option+W is for.
If you have a document-based app, you can change your secondary window to an instance of NSPanel and then check the "Document Modal" attribute. That way when your document window is closed, the secondary window will close as well.
If it's not a document-based app, you could check window's "Hide on Deactivate" attribute, which will hide the window when the app goes into the background.
Other than that, if you want to "bind" the two windows together I think you'd have to set a NSWindowDelegate and manually maintain their relative visibility state. Does that make sense?

NSWindow, how not to be part of a screenshot?

My Cocoa app displays a transparent window on the screen, but when the user tries to take a screenshot using Mac OS X's built-in screen capture key with the option of selecting full windows (Command-Shift-4, then Space Bar), my window gets highlighted as part of the possible windows to capture.
How can I tell my Window or App not to allow this? My Window already refuses to be the Main Window or Key Window through -canBecomeKeyWindow and -canBecomeMainWindow both returning NO, but this still happens.
The Window is also at the NSModalPanelWindowLevel and NSScreenSaverWindowLevel does the same thing.
Notice that every window is eligible for screenshots, even the desktop, dock and menu bar, which are special windows. You can even take a screenshot of the Exposé overlay window itself. This leads me to believe that there is no way to do this.
I suppose you could hook the Command+Shift+4 key event and hide the window, but that key combo is user-definable, so it is subject to change.

Accept mouse clicks without activating the application?

I am working on a utility application that controls other running applications. On certain input event my application displays a window, user can pick some operation from the window, the window disappears and control returns to the previous app. My problem is that clicking in my app’s window activates my application, thus removing focus from the previous application’s window. I can re-activate the previous application when my window closes, but I’d rather keep the original application activated all the time. Is that possible?
It's quite easy to to, just make your window an instance of NSPanel (a subclass of NSWindow), and set it as non-activating in Xcode/IB (or create it programatically, with NSNonactivatingPanelMask in the style mask).
One idea would be: while your app is running, try to keept track of the active window in the system.
After you activate your app and click the command button, restore the previous active window.
This is only an idea, I don't know how to do it on mac.

applicationShouldTerminateAfterLastWindowClosed: does not seem to work when the red x is used to close my Cocoa app

I have a small OSX Cocoa app that just bring up an IKPicutreTaker and saves the picture to a file if one is set. I use applicationShouldTerminateAfterLastWindowClosed: to close the application when the pictureTaker is closed. This all works fine when I either set(this is done when you have picked the picture you want) or when you hit cancel, but when I click on the red arrow in the top left of the windows, the application does not quit when the window is closed this way. Is this intended functionality or am I doing something wrong (not setting some flag?). Also, is there some way to disable this button?
Clicking the red button does not close an application, partly because that verb does not go with that noun. The red button closes the window it's on; it does not quit your application. (An application can and will often have multiple windows on Mac OS X.)
That's where applicationShouldTerminateAfterLastWindowClosed: comes in. Whenever the user closes the last window on the screen (whether by clicking the red button, by choosing Close from the File menu, or by some other means), the NSApplication object will send an applicationShouldTerminateAfterLastWindowClosed: message to its delegate, to ask it whether the application should terminate. If the delegate responds to the message by returning YES, then the application will terminate itself.
You don't say exactly how you're “using” applicationShouldTerminateAfterLastWindowClosed:. If you're just sending it to some object, that's not going to work, because you're asking a question (“should the application terminate after the last window is closed?”) and then ignoring the answer. If you implement the method in an object, but that object isn't the application's delegate, that won't work either—the application object only sends that message to its delegate.
You need to implement the method in your delegate, and return YES when it is appropriate for the application to terminate when the user closes its last window.

Resources