Add UserApp class to RSCore. It represents an of the type usually found in /Applications. A UserApp may or may not be running and may or may not exist locally on disk. It could be entirely fictional, even.
This commit is contained in:
parent
8df34bfcda
commit
fd7c6d07ac
|
@ -71,6 +71,7 @@
|
||||||
842E45CC1ED623C7000A8B52 /* UniqueIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842E45CB1ED623C7000A8B52 /* UniqueIdentifier.swift */; };
|
842E45CC1ED623C7000A8B52 /* UniqueIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842E45CB1ED623C7000A8B52 /* UniqueIdentifier.swift */; };
|
||||||
8432B1861DACA0E90057D6DF /* NSResponder-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8432B1851DACA0E90057D6DF /* NSResponder-Extensions.swift */; };
|
8432B1861DACA0E90057D6DF /* NSResponder-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8432B1851DACA0E90057D6DF /* NSResponder-Extensions.swift */; };
|
||||||
8432B1881DACA2060057D6DF /* NSWindow-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8432B1871DACA2060057D6DF /* NSWindow-Extensions.swift */; };
|
8432B1881DACA2060057D6DF /* NSWindow-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8432B1871DACA2060057D6DF /* NSWindow-Extensions.swift */; };
|
||||||
|
8434D15C200BD6F400D6281E /* UserApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8434D15B200BD6F400D6281E /* UserApp.swift */; };
|
||||||
84411E731FE5FFC3004B527F /* NSImage+RSCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84411E721FE5FFC3004B527F /* NSImage+RSCore.swift */; };
|
84411E731FE5FFC3004B527F /* NSImage+RSCore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84411E721FE5FFC3004B527F /* NSImage+RSCore.swift */; };
|
||||||
844B5B571FE9D36000C7C76A /* Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B561FE9D36000C7C76A /* Keyboard.swift */; };
|
844B5B571FE9D36000C7C76A /* Keyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 844B5B561FE9D36000C7C76A /* Keyboard.swift */; };
|
||||||
844C915B1B65753E0051FC1B /* RSPlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 844C91591B65753E0051FC1B /* RSPlist.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
844C915B1B65753E0051FC1B /* RSPlist.h in Headers */ = {isa = PBXBuildFile; fileRef = 844C91591B65753E0051FC1B /* RSPlist.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
|
@ -191,6 +192,7 @@
|
||||||
842E45CB1ED623C7000A8B52 /* UniqueIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniqueIdentifier.swift; sourceTree = "<group>"; };
|
842E45CB1ED623C7000A8B52 /* UniqueIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UniqueIdentifier.swift; sourceTree = "<group>"; };
|
||||||
8432B1851DACA0E90057D6DF /* NSResponder-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSResponder-Extensions.swift"; sourceTree = "<group>"; };
|
8432B1851DACA0E90057D6DF /* NSResponder-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSResponder-Extensions.swift"; sourceTree = "<group>"; };
|
||||||
8432B1871DACA2060057D6DF /* NSWindow-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSWindow-Extensions.swift"; sourceTree = "<group>"; };
|
8432B1871DACA2060057D6DF /* NSWindow-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSWindow-Extensions.swift"; sourceTree = "<group>"; };
|
||||||
|
8434D15B200BD6F400D6281E /* UserApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = UserApp.swift; path = AppKit/UserApp.swift; sourceTree = "<group>"; };
|
||||||
84411E721FE5FFC3004B527F /* NSImage+RSCore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "NSImage+RSCore.swift"; path = "Images/NSImage+RSCore.swift"; sourceTree = "<group>"; };
|
84411E721FE5FFC3004B527F /* NSImage+RSCore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "NSImage+RSCore.swift"; path = "Images/NSImage+RSCore.swift"; sourceTree = "<group>"; };
|
||||||
844B5B561FE9D36000C7C76A /* Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Keyboard.swift; path = RSCore/Keyboard.swift; sourceTree = "<group>"; };
|
844B5B561FE9D36000C7C76A /* Keyboard.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Keyboard.swift; path = RSCore/Keyboard.swift; sourceTree = "<group>"; };
|
||||||
844C91591B65753E0051FC1B /* RSPlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RSPlist.h; path = RSCore/RSPlist.h; sourceTree = "<group>"; };
|
844C91591B65753E0051FC1B /* RSPlist.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RSPlist.h; path = RSCore/RSPlist.h; sourceTree = "<group>"; };
|
||||||
|
@ -460,6 +462,7 @@
|
||||||
84C687311FBAA3DF00345C9E /* LogWindowController.swift */,
|
84C687311FBAA3DF00345C9E /* LogWindowController.swift */,
|
||||||
84C687341FBC025600345C9E /* Log.swift */,
|
84C687341FBC025600345C9E /* Log.swift */,
|
||||||
84C687371FBC028900345C9E /* LogItem.swift */,
|
84C687371FBC028900345C9E /* LogItem.swift */,
|
||||||
|
8434D15B200BD6F400D6281E /* UserApp.swift */,
|
||||||
842DD7F91E1499FA00E061EB /* Views */,
|
842DD7F91E1499FA00E061EB /* Views */,
|
||||||
);
|
);
|
||||||
name = AppKit;
|
name = AppKit;
|
||||||
|
@ -794,6 +797,7 @@
|
||||||
842E45CC1ED623C7000A8B52 /* UniqueIdentifier.swift in Sources */,
|
842E45CC1ED623C7000A8B52 /* UniqueIdentifier.swift in Sources */,
|
||||||
84A8358A1D4EC7B80004C598 /* PlistProviderProtocol.swift in Sources */,
|
84A8358A1D4EC7B80004C598 /* PlistProviderProtocol.swift in Sources */,
|
||||||
849A339E1AC90A0A0015BA09 /* NSTableView+RSCore.m in Sources */,
|
849A339E1AC90A0A0015BA09 /* NSTableView+RSCore.m in Sources */,
|
||||||
|
8434D15C200BD6F400D6281E /* UserApp.swift in Sources */,
|
||||||
84CFF51B1AC3C77500CEA6C8 /* RSPlatform.m in Sources */,
|
84CFF51B1AC3C77500CEA6C8 /* RSPlatform.m in Sources */,
|
||||||
845A291F1FC8BC49007B49E3 /* BinaryDiskCache.swift in Sources */,
|
845A291F1FC8BC49007B49E3 /* BinaryDiskCache.swift in Sources */,
|
||||||
84CFF52C1AC3CA9700CEA6C8 /* NSData+RSCore.m in Sources */,
|
84CFF52C1AC3CA9700CEA6C8 /* NSData+RSCore.m in Sources */,
|
||||||
|
|
|
@ -0,0 +1,123 @@
|
||||||
|
//
|
||||||
|
// UserApp.swift
|
||||||
|
// RSCore
|
||||||
|
//
|
||||||
|
// Created by Brent Simmons on 1/14/18.
|
||||||
|
// Copyright © 2018 Ranchero Software, LLC. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
// Represents an app (the type of app mostly found in /Applications.)
|
||||||
|
// The app may or may not be running. It may or may not exist.
|
||||||
|
|
||||||
|
final class UserApp {
|
||||||
|
|
||||||
|
let bundleID: String
|
||||||
|
var icon: NSImage? = nil
|
||||||
|
var existsOnDisk = false
|
||||||
|
var path: String? = nil
|
||||||
|
var runningApplication: NSRunningApplication? = nil
|
||||||
|
|
||||||
|
var isRunning: Bool {
|
||||||
|
|
||||||
|
updateStatus()
|
||||||
|
if let runningApplication = runningApplication {
|
||||||
|
return !runningApplication.isTerminated
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
init(bundleID: String) {
|
||||||
|
|
||||||
|
self.bundleID = bundleID
|
||||||
|
updateStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
func updateStatus() {
|
||||||
|
|
||||||
|
if let runningApplication = runningApplication, runningApplication.isTerminated {
|
||||||
|
self.runningApplication = nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let runningApplications = NSRunningApplication.runningApplications(withBundleIdentifier: bundleID)
|
||||||
|
for app in runningApplications {
|
||||||
|
if let runningApplication = runningApplication {
|
||||||
|
if app == runningApplication {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if !app.isTerminated {
|
||||||
|
runningApplication = app
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let runningApplication = runningApplication {
|
||||||
|
existsOnDisk = true
|
||||||
|
icon = runningApplication.icon
|
||||||
|
if let bundleURL = runningApplication.bundleURL {
|
||||||
|
path = bundleURL.path
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
path = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: bundleID)
|
||||||
|
}
|
||||||
|
if icon == nil, let path = path {
|
||||||
|
icon = NSWorkspace.shared.icon(forFile: path)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
path = NSWorkspace.shared.absolutePathForApplication(withBundleIdentifier: bundleID)
|
||||||
|
if let path = path {
|
||||||
|
if icon == nil {
|
||||||
|
icon = NSWorkspace.shared.icon(forFile: path)
|
||||||
|
}
|
||||||
|
existsOnDisk = true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
existsOnDisk = false
|
||||||
|
icon = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func launchIfNeeded() -> Bool {
|
||||||
|
|
||||||
|
// Return true if already running.
|
||||||
|
// Return true if not running and successfully gets launched.
|
||||||
|
|
||||||
|
updateStatus()
|
||||||
|
if isRunning {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
guard existsOnDisk, let path = path else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = URL(fileURLWithPath: path)
|
||||||
|
if let app = try? NSWorkspace.shared.launchApplication(at: url, options: [.withErrorPresentation], configuration: [:]) {
|
||||||
|
runningApplication = app
|
||||||
|
if app.isFinishedLaunching {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
Thread.sleep(forTimeInterval: 0.5) // Give the app time to launch. This is ugly.
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func bringToFront() -> Bool {
|
||||||
|
|
||||||
|
// Activates the app, ignoring other apps.
|
||||||
|
// Does not automatically launch the app first.
|
||||||
|
|
||||||
|
updateStatus()
|
||||||
|
return runningApplication?.activate(options: [.activateIgnoringOtherApps]) ?? false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue