Cannot close Window after opening another window modally - cocoa

I have a problem.
In my mac osx app I have a mainwindow. This window is opening initial. I am working with storyboard.
But there are moments when the user needs to login again into the app. If this is the case (for example when the session ends) I open a new small window modally with this code:
private func openLogin() {
loginController = self.storyboard?.instantiateController(withIdentifier: "LoginController") as? LoginWindowController
guard let window = loginController?.window else {
return false
}
NSApp.runModal(for: window)
}
after I once opened this window and close it again I can never close the main window. If the login window never opened, there is no problem and I can close the MainWindow. But if I opened the loginwindow once, I cannot close the mainwindow. I can click on the close button but it does nothing.
And, I cannot assure this but, I think that I cannot close any window after that.
Do you have any idea?
Thank you for your Help!
Artur

Ok, I have found the issue...
I called the code function openLogin() inside of the windowDidLoad() function of the NSWindowController. The problem is that the applicationDidFinishLaunching of the appDelegate will first be called after the windowDidLoad function finished, which is logically correct.
I stopped the mainThread by running a window modally. Somehow the framework doesn´t like this before the app has completed the launch process.
I solved this by using the NSNotificationCenter and observe the notification name NSApplicationDidFinishLaunching. On that I run the openLogin() code.

Related

'Close' button in Storyboard won't link to IBAction in view controller.swift to dismiss a window

Hello all you smart people! I am very new to Xcode 8 and Swift3, and am bringing a new meaning to the phrase 'killer app'. It'll kill me before it gets a chance to provide my pension!!! :-)
My OSX app is a stay resident app in the top right of the apple menu (info.plist set to Application is Agent(UIElement)= True). The main function of the app, executing an applescript, works fine. It is run from the app menu icon or key combo. I've added an 'about' window and the window appears if I select 'about' from the App menu and it closes if I click the red circle. However I can't seem to get an (interface) close button to close the window.
The 'about' window is generated from an NSMenuItem in AppDelegate.swift as in the code below. All I'm trying to do is close said window with a close button in the (viewcontroller)interface. It's that simple but no matter what I try I cannot link the close button in the Storyboard viewcontroller to an IBAction in viewcontroller.swift so as to add window!.close. The only option given is a 'represented object' binding. It's not possible to link to an IBAction in AppDelegate.swift either.
t must be something to do with the way the window is generated because if I build an app with a normal apple menu the interface buttons will link to actions in the code. If anyone can help please email me at pauljvallance#icloud.com and I can send you the Xcode 8.2.1 project and Swift3 code. Best regards, Paul
func windowAbout(sender: NSMenuItem){
let mainStoryboard = NSStoryboard.init(name: "Main", bundle: nil)
myWindowController = mainStoryboard.instantiateController(withIdentifier: "aboutWindowController") as!
NSWindowController
myWindowController.showWindow(self)
}
Xcode 8 appears to have introduced a bug that prevents you from making connections by dragging from an Interface Builder element to a view controller method when the method in question is defined in a class extension. You can however create the desired connection by dragging from your method to the relevant UI element in Interface Builder:

Cocoa App will not quit after transitioning away from initial VC

This is the set up of my ViewControllers
If i run the app and i move from one view controller to the other, the "Quit appName" menu item does not work, views are presented as sheets..
Why is the Quit function the only one not being triggered when moved away from the initial VC, but other menu items(e.g Minimize) work fine?
Any how can i fix the issue?
Ok i found the solution. In every class of ViewVontroller that is presented i had to insert:
override func viewDidAppear() {
self.view.window!.preventsApplicationTerminationWhenModal = false
}
Apple Doc: "Usually, application termination is prevented when a modal window or sheet is open, without consulting the application delegate. Some windows may wish not to prevent termination, however. Setting this property to NO overrides the default behavior and allows termination to proceed even if the window is open, either through the sudden termination path if enabled, or after consulting the application delegate."

Open Spotify main window from another app when closed

Iam working on an application that tries to extend some Spotify functionality (not another client). I would like to show Spotify's main window when my icon is clicked on the dock - even if the main window in Spotify is closed.
This is my code now:
- (void) applicationDidBecomeActive:(NSNotification *)notification {
// Causes Spotify to hit the front when selecting it!
[[[NSRunningApplication
runningApplicationsWithBundleIdentifier:#"com.spotify.client"] lastObject]
activateWithOptions:NSApplicationActivateAllWindows];
}
It works when the window is open but not in focus (background), but not when I close the Spotify main window (which I people tend to do). Is there any way to re-open this window if it's closed from another application?
The Spotify icon can do this (obviously). Try to hit the close button (the red x) and press the icon (it will reappear). Is that possible from another app?
The Dock sends the reopen Apple Event to the application you clicked on, which then executes code as it sees fit. To simulate a Dock click, you need to send the reopen event to the application manually.
The Apple Documentation on the matter states that the reopen event has the ID of rapp code (kAEReopenApplication) and is part of the kCoreEventClass class.
From there, it's relatively simple to construct the Apple Event in code and send it off to the application. Note that you really should do some error checking from the AESendMessage call, as the event will likely fail if the application isn't launched, etc — I haven't really tested those cases.
Here is my solution. Note that you'll need to keep your original code to bring the application to the front — the Apple Event doesn't change application order.
NSAppleEventDescriptor *target = [[NSAppleEventDescriptor alloc]
initWithDescriptorType:typeApplicationBundleID
data:[#"com.spotify.client" dataUsingEncoding:NSUTF8StringEncoding]];
NSAppleEventDescriptor *event = [[NSAppleEventDescriptor alloc]
initWithEventClass:kCoreEventClass
eventID:kAEReopenApplication
targetDescriptor:target
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
AESendMessage(event.aeDesc, NULL, kAEWaitReply | kAENeverInteract, kAEDefaultTimeout);

- (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

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.

Resources