Quitting an app using the Red X button? - xcode

I've made my first Mac app and it only has one window and I want it to quit when your press the red button. This button closes the window as opposed to quitting the app at the moment and I cant seem to find a way to edit the behaviour of this button any tips? Note this is in Xcode 4 and is an Applescript based app.

I don't know AppleScriptObjC but here's how you do it in objective-c. I'm sure you can easily convert these.
Basically you don't have to modify anything. Just put this method in your app delegate. It is called automatically by the app when the last window is closed because it's an NSApplication Delegate method. There's many other NSApplication Delegate methods so you should look at those methods to see what else you can do. Good luck.
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication {
return YES;
}
By the way, alternative methods would have been to use NSWindowDelegate methods. You just need to set your AppDelegate (or any other class) as the window's delegate with...
[[self window] setDelegate:self];
Specifically you could have used either of these NSWindowDelegate methods to modify the behavior of the red close button. For example you could issue the terminate: method of NSApp in there to do as you asked but you can do anything in them.
- (BOOL)windowShouldClose:(id)sender
- (void)windowWillClose:(NSNotification *)notification
But applicationShouldTerminateAfterLastWindowClosed: is the one you want. I just want to show there's lots of ways to accomplish tasks.
Congrats on your first app!

The answer provided by #regulus6633 did NOT work for me. The Xcode build failed.
This is because, like the OP, my Xcode app is a "Cocoa-AppleScript" app, and the AppDelegate is written in AppleScript.
So, the solution is:
script AppDelegate
--- YOUR OTHER CODE ---
--- QUIT APP WHEN WINDOW IS CLOSED ---
on applicationShouldTerminateAfterLastWindowClosed_(sender)
return true
end applicationShouldTerminateAfterLastWindowClosed_
end script
I put this handler at the end of the script block, but it probably doesn't matter.
I found this solution at http://www.macscripter.net/viewtopic.php?pid=117933#p117933

Related

Overriding close action in OSX

How do I override the close button action to show a confirm dialog?
Would placing code in the app delegate's
applicationWillTerminate
be the correct place for such code?
I have an app using CloudKit.
It saves way too constantly, where it causes errors trying to save to iCloud.
So I'm trying to show a dialog to confirm if the user wants to sync before quitting.
If you want to block a window from closing, the NSWindow's delegate is where it's at. Be it either the AppDelegate (which is the default for most Xcode templates) or an NSWindowController if that's how you presented your window. The method you want to implement from NSWindowDelegate is -windowShouldClose: or -windowWillClose:. If you want to prevent the closing of the window, simply return NO from -windowShouldClose:.
If you want to stop the app from quitting, you should look into NSApplicationDelegate and override -applicationShouldTerminate: and return NSTerminateCancel to prevent the app from terminating.
In short, the "should" methods allow you to prevent the action from occurring, the "will" methods are just saying that it will happen and you can deal with it.

How to Create a Document-Based OS X App that Launches with "Open..." Dialog

I am used to developing non-document-based applications with a single window, but now I am working on a document based application that I created using the document-based template in Xcode 5. When I run my application, it opens a new untitled document upon launch. Instead of automatically creating a new document, I would like my application to display an "Open..." dialog much like Xcode, TextEdit, and other Apple apps do. How do I go about implementing this? Is there a flag somewhere that I can set to show the dialog instead of a new document, or do I have to create an application delegate that shows the dialog upon launch? Thanks for your advice.
That would be customized behaviour.
In your application controller override applicationShouldOpenUntitledFile: to prevent opening a blank document at startup, then display the file dialog.
This is not hard but not obvious and takes a few steps to get going.
Add a window to your MainMenu.xib
Set the Visible at launch to NO in the inspector.
Now create an NSObject subclass in your project. You might include AppDelegate in the name because you will want to make it the delegate of your app.
In the interface header be sure to declare the protocol right after the word NSObject.
While there, add an IBOutlet property an NSWindow.
Back to the MainMenu.xib ...
Add an NSObject (blue cube) to your xib from the library and set its class to your new app delegate class.
Next connect your window to the property in your app delegate class and connect the window's delegate outlet to your app delegate.
Now the menu.
Locate the View menu in MainMenu and add one NSMenuItem.
Give it a title. "My fancy main window" or whatever.
Now connect it to your app delegate with both an IBOutlet (in case you want to fiddle with its enabled state or title later )
And add an IBAction for this menu item as well. Something like showMyFancyWindow:
This menu item will be persistent.
In your IBAction method call makeKeyAndOrderFront: with your app delegate's property for your window as the argument.
Extra credit
Add a BOOL property to your app delegate.
Something like showsMyFancyWindowAtLaunch
Create a constant NSString as a key above your #implementation line.
Add a checkbox button to your window.
Bind its value to your BOOL.
Add an IBAction method for the checkbox.
Inside that
[[NSUserDefaults sharedDefaults] setBool: self.showsMyFancyWindowAtLaunch forKey: theConstStringKeyYouCreated]
Then in your applicationDidFinishLaunching:
Use the corresponding bool:forKey: method of NSUserDefaults to check whether or not to call showMyFancyWindow: method at launch.
My solution, for MacOS 15 and Xcode 13, after fleshing out some of the hints above:
In your AppDelegate (or equivalent) class, turn off the creation of a New "Untitled" document using:
func applicationShouldOpenUntitledFile(_ sender: NSApplication) -> Bool
{
return false
}
Then, in add the following code to your applicationDidFinishLaunching() delegate method:
NSDocumentController.shared.openDocument(self)
Seems to work, though it's impossible to say whether it's a best solution or not.

- (NSWindow *)window doesn't work to show a window while loadWindow does

I am trying to open a nib file called EasyWindow.xib when a button it pressed in my MainMenu.xib. I have the button connected to this IBAction method, but when I click on the button it doesn't open. When I change the "window" in this init part to "loadWindow" it works perfectly fine, but the Mac Developer Library say "You should never directly invoke this method." How do I make the window method work?
- (IBAction)loadEasyWindow:(id)sender
{
[[[NSWindowController alloc] initWithWindowNibName:#"EasyWindow"] window];
}
- (NSWindow *)window only gives you a reference to the actual window object that the NSWindowController manages. It doesn't actually do anything with that window. It's more of a getter than anything else.
Meanwhile, -loadWindow is a method that's called when your program actually loads the window from the nib file and has little to do with opening it, closing it, and showing it. That's why you shouldn't call it. I'm guessing it works because a side effect is the window showing itself.
What you are looking for is probably NSWindowController's - (IBAction)showWindow:(id)sender. [reference] It should do exactly what you want:
Displays the window associated with the receiver

Mac OS X Lion: Detect if another application is running in full screen mode?

In a Cocoa app, is there a way to tell if another application currently is in full screen mode?
My application is configured to show up on all Spaces and listens for mouseEntered events to order itself to the front.
Problem is that when another app is in full screen mode and the user happens to move the mouse across the black area where my app's window is located, it is brought to the front (happens with multiple monitors).
I've only seen the above behavior with [self setCollectionBehavior: NSWindowCollectionBehaviorCanJoinAllSpaces]; enabled.
Here the other relevant code for my app.
- (void) mouseEntered:(NSEvent *)theEvent
{
// Don't do this when another app is in full screen mode:
[[self window] orderFront:self];
}
The above mentioned methods of registering for
"NSWindowWillEnterFullScreenNotification"
does not work, they can be used to notify your own app, using them we cannot detect whether any other application is in full screen mode or not.
However After trying out so many options found out FullScreen detector app at github this usefull link ..:):)
https://github.com/shinypb/FullScreenDetector.git
After a great deal of frustration, this worked for me to get a window that floats on all spaces except full-screen ones. I saw the fullScreenNone constant name, and since it described what I wanted, I tried it and found that it worked.
window.level = .floating
window.collectionBehavior = [.canJoinAllSpaces, .fullScreenNone]
window.canHide = false
Hmm, have you ruled out using applescript/scriptingbridge? You can get the size of windows from applescript and compare them to the size of the screen. (or do you not know which screen a given app is on?)
Certain apps which are accessible will have an 'AXFullScreen' attribute on their windows. For example this works for some apps:
tell application "System Events"
tell process "Pages"
repeat with myWin in windows
get value of attribute "AXFullScreen" of myWin
end repeat
end tell
end tell
The real action seems to be down in carbon... MacWindows.h and CarbonEvents.h have references to "FullScreen" in them.
You will need to research this though.
Use notifications. For example:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(willEnterFull:)
name:NSWindowWillEnterFullScreenNotification
object:nil];
Actually, you'll probably want to use NSDistributedNotificationCenter instead, since it goes across processes.
You're adding your object as an observer, so that when something else posts a notification that it will enter full screen, your object will receive that notification.
The selector is the message/method you want called by the notification process.
The name parameter is the actual name of the notification. These are standard, unless you were to create a custom notification for something you would be using.
The object parameter is for specifying which object you want to receive notifications from. Since you want to know when ANY app is going full screen, you'd want to leave this nil.
Remember to remove your object as an observer before it's deallocated!

osx and objc - running a second run loop for a plugin?

C programmer here. I'm trying to make a plugin to a running OSX app open its own window, accept a button press, close the window and come back to the plugin - not quit the app.
I've been able to get a window open using NSApp, and I've even got a button in it, but it won't DO anything.
[button setTarget: nil];
[button setAction: #selector(fauxAction:)];
Is how I set it up. Normally, you [button setTarget: self], BUT, this is inside a normal c function, and there is no "self." I don't know how to call an objc method from c, if that's the problem I need to solve. I just want the method fauxAction to be called when the button is pressed.
This is the plugin's window -- not the main application. I can't have them crossing wires. [NSApp run] and putting the quit menu on it quits the main application, I guess because the run loop wraps the executing thread.
Any help would be appreciated. I feel like I'm drowning here.
I got it - NSApp runModalForWindow. That runs just the window loop, leaves the main loop unmolested.

Resources