Mac OS X Application modal window does not close - xcode

I've been trying to submit an application for the Apple App store and the reviewer claims that my initial notice window (which is modal) does not go away when they hit the accept button. Now I've tested it on several machines (even clean 10.7.1 installations) and have not seen this behavior (it works great for me).
My code to display this window:
- (IBAction) doAlert:(id)sender {
if(self.alertVC == nil) {
self.alertVC = [[[AlertVC alloc] initWithWindowNibName:#"AlertVC"] autorelease];
}
[NSApp runModalForWindow:self.alertVC.window];
}
and the code with which I close it looks like this:
-(IBAction)closeWindow:(id)sender {
[self close];
[NSApp stopModal];
}
Anyone have any idea why this works 100% in all my tests but for the Apple testers the window does not go away? (It stays open in the foreground even though the application continues and they can interact with the application as normal again.

The only thing I see, that may cause the error is, that you are not closing the window, but the controller (or who else provides the method closeWindow)
If closeWindow is a method of the same class than doAlert the code should look like:
-(IBAction)closeWindow:(id)sender {
[self.alertVC.window performClose:self];
[NSApp stopModal];
}
I know the answer is late and you probably have found a solution, but I provided the answer for all those stumbling over the snippet and wondering, why it happens to them as well.

Related

NSApplication make window front on app switch

When run my app(OSX, macOS SDK 10.15), it shows the main window, as expected. I then CMD-Tab to another app, but when I CMD-Tab back to my app, it won't show the window. The same happens if I click on it in the dock.
I've tried various suggestions, such as:
[NSApp activateIgnoringOtherApps:YES];
[window makeKeyAndOrderFront:nil];
[window orderFrontRegardless];
and
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:#selector(applicationSwitchedTo) name:NSWorkspaceDidActivateApplicationNotification object:nil];
-(void)applicationSwitchedTo
{
[window makeKeyAndOrderFront:nil];
}
I've set up all the callback methods in both the window and app delegates, but I don't get anything,except the above callback, when I switch to or from my app. I would think it would default behavior to show the apps main window when switched to it from another app. Any help is greatly appreciated!
I figured out a fix, but I'm not sure if it's the proper thing to do.
I noticed that if I called
[NSApp finishLaunching]
then the window ordering functions don't work. I don't need it's functionality, so I removed it.
Furthermore, I'm now handling the event type NSEventTypeAppKitDefined, which is called when you switch on and off the app. I then check the subtype and call the window ordering function:
case NSEventTypeAppKitDefined:
{
if([theEvent subtype] == NSEventSubtypeApplicationActivated) {
[window makeKeyAndOrderFront:nil];
}
}
Hope this helps someone down the line!

mac application, terminate on close

I'm new too Xcode (5.1.1) and Mac's (OS X) and I'm trying to get my app to close when the red close button is pressed. I am using the below code to try and do it in AppDelegate.m
- (void)windowWillClose:(NSNotification *)aNotification {
[NSApp terminate:self];
}
But all this seems to do is close the window, the app itself is still running and the icon remains in the dock. Though clicking the icon does nothing and neither does launching the app again (it seems to think it is still running). I have to force shut down in order to launch the app again.
Any help would be great thanks.
If shutting down the application when the last window closes is acceptable you can use the following method in your app delegate.
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return YES;
}
if you don't want to quit the application, you should do this :
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
return NO;
}

Quitting an app using the Red X button?

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

Hide Dock icon without closing window

I am creating an app in which I want to give the user the ability to show or hide the dock icon at run time. I have a preferences window with a checkbox, setting a user default value, which fires the following code using KVO:
if (!hideDockIcon) {
TransformProcessType(&psn, kProcessTransformToForegroundApplication);
} else {
TransformProcessType(&psn, kProcessTransformToUIElementApplication);
}
This works, but when hiding, the preferences window is closed directly (which makes sense as it is now a background app). However, I noticed that MS's SkyDrive client manages to hide the icon while keeping the Preferences window open. I have not been able to find out how one would do that, anybody has an idea?
I also tried using [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular] and NSApplicationActivationPolicyAccessory/NSApplicationActivationPolicyProhibited but that doesn't work for me; Accessory doesn't hide the dock icon, Prohibited closes the window as well and seems to make [NSApp activateIgnoringOtherApps:YES] being ignored.
I stumbled upon this thread where the following is suggested to prevent a window from being hidden:
[window setCanHide:NO];
This just covers hiding. If your window gets closed, you might try to use the window delegate?
There's a call that let's you prevent the window from being closed
- (BOOL)windowShouldClose:(id)sender
I solved this problem by not activating the app in the same run loop turn:
dispatch_async(dispatch_get_main_queue(), ^{
[NSApp activateIgnoringOtherApps:YES];
});
Swift:
dispatch_async(dispatch_get_main_queue()) {
NSApp.activateIgnoringOtherApps(true)
}
I'm calling dispatch_async to schedule the block for execution in one of the next run loop turns a few nanoseconds later. This gives the process the chance to finish hiding itself.

Snow Leopard & LSUIElement -> application not activating properly, window not "active" despite being "key"

I'm running into a few problem with a background application that uses LSUIElement=1 to hide its dock item, menu bar and prevent it from appearing in the Command-Tab application switcher.
It seems to be a Snow Leopard only problem.
The application places an NSStatusItem in the menu bar and pops up a menu when clicked on. Selecting "Preferences..." should bring up an NSWindow with the preferences.
The first thing that doesn't seem to work is that the Window does not get ordered in at the front, but appears behind all other application windows.
I tried to fix this by calling
[[NSApplication sharedApplication] activateIgnoringOtherApps: YES]
but that didn't work.
After a while I figured out that the menu is blocking the message to the run loop from being sent, so I wrote another method on the MainController and sent the message with a delay:
[self performSelector:#selector(setFront:)
withObject: [preferencesController window] afterDelay:1.0];
-(void)setFront: (id) theWindow {
[[NSApplication sharedApplication]activateIgnoringOtherApps:YES];
[theWindow orderFrontRegardless];
[theWindow makeKeyWindow];
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
}
Note the send-every-possible-message-to-make-it-do-what-it-should-be-doing-approach.
This works, kind-of, the window is brought to the front on top of all other windows from all apps, BUT most of the time it isn't active, meaning it's title bar is greyed out. Clicking on the title bar won't make the window active either. Clicking INSIDE of the window will make it active!?
This all didn't seem to be a problem in Leopard; just calling activateIgnoringOtherApps and making the window key seemed to work just fine.
In Snow Leopard there is a new API designed to replace LSUIElement that is supposed to emulate its behaviour:
http://developer.apple.com/mac/library/releasenotes/cocoa/appkit.html
I've played around with that, but it's SL-only and I haven't been able to get LSUIElement being set.
That's strange - I'm writing a LSUIElement application under Snow Leopard, and I didn't have such problems as you've described... I did have the problem that the newly created window didn't appear at the front, but I fixed it by calling activateIgnoringOtherApps. This was all I had to do to make it work as it should:
[NSApp activateIgnoringOtherApps: YES];
[preferencesWindow makeKeyAndOrderFront: self];
I didn't even touch anything that had 'policy' in the name.
After posting the question in desperation, I did continue looking and did eventually find the solution. Since this stumped me for a few days and there seems to be no other answer out there that google can find, I'll explain the solution for "future generations".
Snow Leopard adds a new NSApplication presentationOptions API:
http://developer.apple.com/mac/library/releasenotes/cocoa/appkit.html
This is supposed to simulate the way that LSUIElement works, but provide more developer control. Unfortunately, the simulation isn't perfect so there is a change of behaviour between 10.5 and 10.6.
In particular, if your application has the LSUIElement = 1 line in its info.plist, Snow Leopard will initialize "the application’s presentationOptions .. to an equivalent combination of NSApplicationPresentationOptions flags instead".
Only it doesn't really. It sets the new NSApplication setActivationPolicy to NSApplicationActivationPolicyAccessory:
"The application does not appear in the Dock and does not have a menu bar, but it may be activated programmatically or by clicking on one of its windows. This corresponds to value of the LSUIElement key in the application’s Info.plist being 1."
Despite the mention of being activated programatically, activateIgnoringOtherApps: is simply ignored completely.
The solution is to set the activation policy to "regular":
[[NSApplication sharedApplication] setActivationPolicy: NSApplicationActivationPolicyRegular];
Of course, you can only do this if you use the 10.6 SDK as Base SDK, something few people want to do at the moment, so below is a 10.5-safe way of doing this:
NSApplication* app = [NSApplication sharedApplication];
if( [app respondsToSelector: #selector(setActivationPolicy:)] ) {
NSMethodSignature* method = [[app class] instanceMethodSignatureForSelector: #selector(setActivationPolicy:)];
NSInvocation* invocation = [NSInvocation invocationWithMethodSignature: method];
[invocation setTarget: app];
[invocation setSelector: #selector(setActivationPolicy:)];
NSInteger myNSApplicationActivationPolicyAccessory = 0;
[invocation setArgument: &myNSApplicationActivationPolicyAccessory atIndex: 2];
[invocation invoke];
}
I hope somebody will find this useful.

Resources