OSX/Swift Make Application Useable Anywhere - swift

I have an application written in osx swift, and I need help with a particular behavior/issue. I have the application set to be above all other windows using this code:
self.window!.level = Int(CGWindowLevelForKey(Int32(kCGScreenSaverWindowLevelKey)))
A little issue with it, from what I've seen, is that it does work... but if I go to my launchpad applications menu, the window still shows up. That's exactly how I want the window to behave, but whenever I hit a button within the window, the application resets to the normal desktop to function properly. I have a link below demonstrating this:
https://gyazo.com/f4d05c10ad7b5dbf8b95f3bd2aa23cc4
See how I'm getting taken out of my launchpad and then reset to the normal desktop screen whenever I hit buttons within my application? I just really need to fix this issue.
Is there any info.plist property that I can use to prevent this from happening? Is there any piece of code I could use to make my window use-able everywhere without resetting it to the proper desktop environment? Thanks in advance!

NSFloatingWindowLevel might be a better choice:
import Cocoa
let kCGFloatingWindowLevel: CGWindowLevel =
CGWindowLevelForKey(CGWindowLevelKey.FloatingWindowLevelKey)
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
func applicationDidFinishLaunching(aNotification: NSNotification) {
self.window!.level = Int(kCGFloatingWindowLevel)
}
}
The window level type you are currently using is primarily meant for screensaver windows. If you want a floating palette or window then using the above should give you the desired behavior.
↳ NSWindow : NSFloatingWindowLevel

Related

Global keyboard shortcuts for a Mac tray app

I am developing a Mac app using Swift 4 which only runs as an Agent (it only has a menu in the tray). I'm completely new to Swift.
I want it to respond to keyboard shortcuts, but the basic shortcuts (see picture) only work when the app has focus (in my case, when the menu is being clicked).
So what I need is for my app to respond to system-wide keyboard shortcuts.
I've tried:
HotKey but it doesn't seem to be compatible with Swift 4, or perhaps I can't use Swift Package Manager
this answer but again Swift 4 raises several errors that I couldn't solve
Has anyone done it?
So I ended up getting it to work with HotKey:
by using Carthage as a package manager instead of SPM
and by not using HotKey's example code from their README, which for some reason didn't work for me, but the one in their example app.
It works great!
I made a Swift package that makes this very easy:
import KeyboardShortcuts
extension KeyboardShortcuts.Name {
static let startFiveRounds = Self("startFiveRounds", default: .init(.t, modifiers: [.command, .option]))
}
#main
final class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ notification: Notification) {
KeyboardShortcuts.onKeyUp(for: .startFiveRounds) {
// …
}
}
}
Even though you already solved your problem, I think this could be useful for other people having the same problem.
I would also recommend letting the user pick their own keyboard shortcut instead of hardcoding it. My package comes with a control where the user can set their preferred shortcut.

NSOutlineViewDelegate in High Sierra not working

I am a novice learning Swift and xcode by rewriting a code I originally developed in Javascript/PHP/MySql. I am working in macOS, using a storyboard in xcode as my basis for development. At the moment I am developing a SplitView. In the Master side I have an OutlineView. It has three levels, the outer two are expandable, and, until today, it worked just fine. All levels were populated, visible, and expandable where appropriate. I had Swift(4.0) and xcode (9.1) up-to-date as far as I know. So, today I decided it was time to update from Sierra to High Sierra. My master view has now gone completely blank. Nada. I tried to track the problem down and discovered, using the debugger in xcode, that the outlineView function in the NSOutlineViewDelegate extension to my MasterViewController is, apparently, not being called at all! I checked the Connections Inspector, and the connections to DataSource and Delegate are still intact. I searched online and found a few people with what seemed to be vaguely related recent problems associated with Cocoa bindings, but I could not connect their problem solution to mine since I am not using Cocoa bindings...it's on my list, but I am not there yet. The only thing I know that changed was going from Sierra to High Sierra. Any suggestions? Thanks!
ADDED: I now know a bit more about the problem.
Here is the code that works prior to High Sierra:
class ViewController: NSViewController {
#IBOutlet weak var webView: WebView!
#IBOutlet weak var outlineView: NSOutlineView!
var feeds = Feed
let dateFormatter = DateFormatter()
override func viewDidLoad() {
super.viewDidLoad()
dateFormatter.dateStyle = .short
if let filePath = Bundle.main.path(forResource: "Feeds", ofType: "plist") {
feeds = Feed.feedList(filePath)
print(feeds)
}
}
The code is taken from a tutorial on the OutlineView on the Ray_Wenderlich.com site. I patterned my code after this and both the tutorial and my code worked...until High Sierra. Apparently, until High Sierra, the system would spontaneously parse "feeds" and generate the outlineView display. With High Sierra the behavior changed and it no longer spontaneously produced the outlineView, neither in the tutorial nor my project. The result was a blank outLineView.
In a comment added to the tutorial, I now find that someone else had encountered the same behavior and suggested that the code now needed:
outlineView.reloadData(),
but my naive implementation of that suggestion simply generated a runtime error,
"[NSView reloadData]: unrecognized selector sent to instance"
Just make sure that when you start a new ‘Playground’ you have macOS as an application checked and not IOS. If you have IOS checked Swift will import UIKit (instead of Cocoa) which will cause your problem. GL.

Programmatically minimize all windows or besides my Cocoa application?

I haven't been able to find anything about this in Swift. Is there a way to programmatically make my application minimize all other windows open in the background, or even just minimize Safari? I basically want my application to run against the desktop, without any clutter in the background. Is there a way to programmatically do this for a Cocoa app? I'm pretty new to swift, so any help would be appreciated.
You can use api on NSWorkspace which allows you to hide all visible app in the background.
You can find more about NSWorkspace here: link
Hides all applications other than the sender. This method must be called from your app’s main thread.
NSWorkspace.shared().hideOtherApplications()
If you only want to hide Safari,
let appPath = NSWorkspace.shared().fullPath(forApplication: "Safari")
let identifier = Bundle.init(path: appPath!)?.bundleIdentifier
if let bundleID = identifier {
let runningApps = NSRunningApplication.runningApplications(withBundleIdentifier:bundleID )
if !runningApps.isEmpty {
runningApps.first?.hide()
}
}

NSApplication keyWindow is nil during applicationDidFinishLaunching

Starting with a blank OS X application project, I add the following code to applicationDidFinishLaunching.
func applicationDidFinishLaunching(aNotification: NSNotification) {
let app = NSApplication.sharedApplication()
guard let window = app.keyWindow else {
fatalError("No keyWindow\n")
}
print(window)
}
At launch I hit the error case because my local window variable is nil. Yet when I show the contents of the app variable, I see a valid value for _keyWindow. Also notice that the blank GUI Window is being displayed on the screen next to the stack dump.
Why does the keyWindow: NSWindow? property return nil in this case?
Thanks
NSApplication's keyWindow property will be nil whenever the app is not active, since no window is focused for keyboard events. You can't rely on it being active when it finished launching because the user may have activated some other app between when they launched your and when it finished launching, and Cocoa is designed to not steal focus.
To some extent, you may be seeing that happen more when launching from Xcode because app activation is a bit strange in that case. But, still, you must not write your applicationDidFinishLaunching() method to assume that your app is active.
What you're seeing in terms of the app's _keyWindow instance variable is, of course, an implementation detail. One can't be certain about what it signifies and you definitely should not rely on it. However, I believe it's basically the app's "latent" key window. It's the window that will be made key again when the app is activated (unless it is activated by clicking on another of its windows).

My App crashes when iCloud status changes

I know there is a similar question but the OP seems to think his problem was only on the simulator and so not such an issue... But I think mine is in both.
I was having a problem adapting an app for iCloud storage (when trying to observe for NSUbiquityIdentityDidChangeNotification). I could not see what the problem was with my code and so...
...after hours of banging my head against a wall I have set up a new project in Xcode (v6.1 6A1046a) to try and narrow it down. It seems it must be a very basic problem indeed...
The only things I have done in this new projects are:
Enable iCloud capabilities for 'Key-value storage' and for 'iCloud
Documents'(using the default container) - no error messages, appears to be set up fine.
Add a label and a button to the provided view controller in IB.
Add an IBOutlet for both and hook up an IBAction to change the label text when pressed.
For clarity, the only code I added to an empty 'Single View Application' template is:
#IBOutlet weak var label: UILabel!
#IBOutlet weak var button: UIButton!
#IBAction func buttonPressed(sender: AnyObject) {
self.label.text = "You pressed the button"
}
So if I run the project from Xcode in the simulator or on the device, or if I run the project directly on the device, it launches fine and the button works properly - as you would expect...
The problem is:
If I am running on the device from Xcode & I go to the Settings->iCloud->iCloud Drive on the device and toggle the switch for my app (from/to either state) the app crashes. I'm getting no feedback except this:
If I am running the app directly on the device and try and toggle iCloud Drive setting, when I go back into the app it appears to restart (the view is being reset, along with the label.text - neither of which happen if I just visit settings without touching the switch).
It also has the habit of freezing my device completely, which is mildly irritating.
I'm new to iCloud development so I guess I may be missing something really basic...
As I say it's an empty project with only a couple of lines of additional code so it's probably not something I HAVE done. Which limits it to something I HAVEN'T done. I am trying to follow as many tutorials as I can find and as much apple documentation as well. I just can't see any obvious steps I may have overlooked.
Unless it's the expected behaviour, or an Apple issue I guess.
Thanks for any help - it's driving me nuts!
iOs kill your app when you change iCloudDrive state. This is standard iOs behavior you can check this with build in applications(Safari for example).