Adding a new label where clicked SWIFT - swift

I would like to write a simple swift code for a MacOS app which add a new label wherever the user perform a mouse click in a window.
This code compiles but make the app crash:
#IBOutlet var here2 = [NSTextField]()
var count: Int = 0
func getCoordinates(){
NSEvent.addLocalMonitorForEvents(matching: [.leftMouseDown]) {
if self.location.x < 700 && self.location.y<750 {
self.here2.append(NSTextField.init())
self.here2[self.count].frame.origin = CGPoint(x: self.location.x, y: self.location.y)
self.here2[self.count].stringValue = String(self.count)
print("count is: " + String(self.here2.count))
self.count+=1
}
return $0
}

Here is a programmatic approach which may be run in Terminal. Note that window.acceptsMouseMovedEvents is set to true.
//May be run in Terminal with:
//swiftc label.swift -framework Cocoa -o label && ./label
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate {
var window : NSWindow!
var here2 = [NSTextField]()
var count: Int = 0
let _wndW : CGFloat = 700
let _wndH : CGFloat = 750
let _labelW : CGFloat = 24
let _labelH : CGFloat = 24
#objc func getCoordinates(_ sender:AnyObject ) {
NSEvent.addLocalMonitorForEvents(matching: [.leftMouseDown]) {
var pt: NSPoint? { self.window.mouseLocationOutsideOfEventStream }
if let location = pt {
let msPt:NSPoint = self.window.contentView!.convert(location, from: nil)
print("x = \(msPt.x) : y = \(msPt.y)")
if msPt.x < (self._wndW - self._labelW) && msPt.y < (self._wndH - self._labelH ) {
self.here2.append(NSTextField.init())
self.here2[self.count].frame = NSMakeRect(msPt.x, msPt.y, self._labelW, self._labelH)
print(self.here2[self.count].frame)
self.window.contentView!.addSubview (self.here2[self.count])
self.here2[self.count].backgroundColor = NSColor.white
self.here2[self.count].isSelectable = false
self.here2[self.count].stringValue = String(self.count)
print("count is: " + String(self.here2.count))
self.count+=1
}
}
return $0
}
}
func buildMenu() {
let mainMenu = NSMenu()
NSApp.mainMenu = mainMenu
// **** App menu **** //
let appMenuItem = NSMenuItem()
mainMenu.addItem(appMenuItem)
let appMenu = NSMenu()
appMenuItem.submenu = appMenu
appMenu.addItem(withTitle: "Quit", action:#selector(NSApplication.terminate), keyEquivalent: "q")
}
func buildWnd() {
window = NSWindow(contentRect:NSMakeRect(0,0,_wndW,_wndH),styleMask:[.titled, .closable, .miniaturizable, .resizable], backing:.buffered, defer:false)
window.center()
window.title = "Swift Test Window"
window.makeKeyAndOrderFront(window)
window.acceptsMouseMovedEvents = true
// **** Button **** //
let myBtn = NSButton (frame:NSMakeRect( _wndW - 180, 15, 135, 24 ))
myBtn.bezelStyle = .rounded
myBtn.autoresizingMask = [.maxXMargin,.minYMargin]
myBtn.title = "Start Label Maker"
myBtn.action = #selector(self.getCoordinates(_:))
window.contentView!.addSubview (myBtn)
// **** Quit btn **** //
let quitBtn = NSButton (frame:NSMakeRect( _wndW - 50, 10, 40, 40 ))
quitBtn.bezelStyle = .circular
quitBtn.autoresizingMask = [.minXMargin,.maxYMargin]
quitBtn.title = "Q"
quitBtn.action = #selector(NSApplication.terminate)
window.contentView!.addSubview(quitBtn)
}
func applicationDidFinishLaunching(_ notification: Notification) {
buildMenu()
buildWnd()
}
func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool {
return true
}
}
let appDelegate = AppDelegate()
// **** main.swift **** //
let app = NSApplication.shared
app.delegate = appDelegate
app.setActivationPolicy(.regular)
app.activate(ignoringOtherApps:true)
app.run()

You cannot call copy on NSTextView, that causes the error message.
You implement all the required methods by subclassing the view, but I'd suggest you allocate new text views programmatically and set their style in code instead of Interface builder.
Here's another thread dealing with copying objects: "[something copyWithZone:]: unrecognized selector sent to instance" when using Bindings / Core Data

You can't connect and array of NSTextField in a storyboard. In my opinion it's a bug in Xcode, IB shouldn't make the connection. It's also a bug in AppKit, I tried this and got this weird error:
Failed to set (contentViewController) user defined inspected property on (NSWindow): [<__NSTimeZone 0x6040000a2280> valueForUndefinedKey:]: this class is not key value coding-compliant for the key identifier.
Solution: remove the connection in IB and change
#IBOutlet var here2 = [NSTextField]()
to
var here2 = [NSTextField]()
#IBOutlet weak var here2TextField: NSTextField!
Connect here2TextField in IB and append here2TextField to here2 in viewDidLoad().

#Marco: The code which I posted is a template (aka boilerplate) example of the programmatic approach to creating applications. All that I did was copy/paste your function into the AppDelegate class of the template and connect it to a button. From there I revised your code until the desired result was obtained. Instead of using a XIB or storyboard the technique requires that source code be written by the author (or use templates). The good news is that you have control of your application and nothing is done behind your back; what you see is what you get. The downside is that the technique is cumbersome for really large projects; for this I rely on Xcode with XIBs. The autocompletion feature of Xcode is also very helpful, while with the programmatic approach you have to rely on Xcode/Help/DeveloperDocumentation as well as internet searches, especially StackOverflow (usually someone else has had the same problem that you are experiencing). In lieu of using the CommandLine from Terminal for every compile I automated the process with a very simple editor which was written in Swift using Xcode (with XIB). However, the posted code may also be run in Xcode by doing the following:
1) Create a new macOS App using Swift (User Interface is XIB but it won’t be needed for the demo)
2) Use File/New/File to add a Swift file and name it ‘main.swift’
3) In the new main.swift file change ‘import Foundation’ to ‘import Cocoa’
4) Copy/paste the last five lines of the demo (labelled main.swift) into this file
5) Go into the AppDelegate file that Apple provided and delete everything there except for ‘import Cocoa’
6) Copy/paste the entire AppDelegate class of the posted code (down to the main.swift section which you have already used)
7) Hit the ‘Run’ button, and it should compile without error.
Hope it helps and good luck with your project. Thanks for posting.

Related

Accessing NSWindow-like properties in Catalyst macOS app

I am thinking about porting my macOS app to Catalyst.
My app shows a transparent window (no title bar, clear background) on top of all other apps windows (dock included).
To do that, in the non-catalyst code I use:
window.isOpaque = false
window.hasShadow = false
window.backgroundColor = .clear
window.styleMask = .borderless
window.isMovableByWindowBackground = true
window.level = .statusBar
Using UIKit, I was only able to remove the toolbar so far:
window.titleBar.titleVisibility
...But no clue about the other settings.
I plan to make the app available on the App Store in the future, but if the only way to do so is and hack with a private API, that's fine.
Any ideas?
Thanks in advance
There is no official API for doing that, but you can easily access the NSWindow instance and modify it directly. You can do that manually or using some library like Dynamic (Full disclosure: I'm the author):
let window = Dynamic.NSApplication.sharedApplication.delegate.hostWindowForUIWindow(uiWindow)
window.isOpaque = false
window.hasShadow = false
window.backgroundColor = Dynamic.NSColor.clearColor
window.styleMask = 0 /*borderless*/
window.isMovableByWindowBackground = true
window.level = 25 /*statusBar*/
I have some success removing the close button on Catalyst by calling a function from the viewDidAppear(). I called it AppDelegate().disableTitleBarButtons(). Has to be from view did appear.
AppDelegate().disableTitleBarButtons() is as follows
func disableTitleBarButtons() {
func bitSet(_ bits: [Int]) -> UInt {
return bits.reduce(0) { $0 | (1 << $1) }
}
func property(_ property: String, object: NSObject, set: [Int], clear: [Int]) {
if let value = object.value(forKey: property) as? UInt {
object.setValue((value & ~bitSet(clear)) | bitSet(set), forKey: property)
}
}
// disable full-screen button
if let NSApplication = NSClassFromString("NSApplication") as? NSObject.Type,
let sharedApplication = NSApplication.value(forKeyPath: "sharedApplication") as? NSObject,
let windows = sharedApplication.value(forKeyPath: "windows") as? [NSObject]
{
for window in windows {
let resizable = 4
property("styleMask", object: window, set: [], clear: [resizable])
let fullScreenPrimary = 7
let fullScreenAuxiliary = 8
let fullScreenNone = 9
property("collectionBehavior", object: window, set: [fullScreenNone], clear: [fullScreenPrimary, fullScreenAuxiliary])
}
}
}
Where is says let resizable = 4,
Change to 3 for no Maximise,
Change to 2 for No minimise,
Change to 1 of No Close button.
Play with the other numbers or stylemask settings also. Good luck

How to manage multiple NSWindows in a dictionary

What I'm trying to do:
I'm currently developing a Command-Line-Tool that creates a blurred window for each desktop space available. I save these windows in a dictionary where the spaceIdentifier is the keyand the NSWindow is the value.
In order to keep the windows in sync with the spaces I periodically check if there are new spaces or if spaces are closed.
My Code:
import AppKit
import Foundation
func createBlurWindow(screen: NSScreen?, contentRect: NSRect, brightness: Int) -> NSWindow
{
# irrelevant code that creates a blurred window
}
class AppController: NSObject, NSApplicationDelegate
{
var spaceWindowList: [NSNumber: NSWindow] = [:]
func applicationDidFinishLaunching(_ aNotification: Notification)
{
self.manageWindows()
Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(self.manageWindows), userInfo: nil, repeats: true)
}
#objc func manageWindows()
{
// create windows
for scr in NSScreen.screens {
let scrHeight = scr.frame.height
let scrWidth = scr.frame.width
let windowHeight = CGFloat(22)
let size = CGRect(x: 0, y: scrHeight-windowHeight, width: scrWidth, height: windowHeight)
let currentScreenSpaces = WindowHelper.getSpacesforScreen(scr)
for space in currentScreenSpaces!
{
if self.spaceWindowList[space] == nil
{
let w = createBlurWindow(screen: scr, contentRect: size, brightness: 9)
let windowID = NSNumber.init(value: w.windowNumber)
// #TODO this may fail if the space was created just now -> fix this by waiting some time
WindowHelper.moveWindow(windowID, toSpace: space)
self.spaceWindowList[space] = w
// debuginfo
let displayNr = scr.deviceDescription[NSDeviceDescriptionKey("NSScreenNumber")]!
print(getTime(), " Display:", displayNr, " added Window(", windowID , ") for Space: ", space, separator: "")
}
}
}
let currentSpaces = WindowHelper.getAllSpaces()
for (space, window) in self.spaceWindowList
{
// destroy window if space was closed
if !(currentSpaces?.contains(space))!
{
window.close()
//self.spaceWindowList.removeValue(forKey: space)
// debuginfo
print(getTime(), "Destroyed window of closed Space:", space)
}
}
}
}
let app = NSApplication.shared
let controller = AppController()
app.delegate = controller
app.run()
The complete source can be found here
My Problem:
When detecting that a space was closed I try to programatically close the corresponding NSWindow, however the next time manageWindows() is called the application segfaults on this loop: for (space, window) in self.spaceWindowList. To debug I activated zombieobjects and got the following errormessage -[NSWindow retain]: message sent to deallocated instance 0x101241150
I don't understand why there is still a pointer to my window the next time spaceWindowList is iterated. I also tried to nil the dictionary entry with self.spaceWindowList.removeValue(forKey: space) but that also lead to a segfault.
I'm fairly new to swift and macdev in general so I'm not that confident with memory management in swift.
I would really appreciate if someone could tell me the best way to safely close windows organized in some kind of dictionary/map/whatever.
PS:
If you are wondering why I don't use .canJoinAllSpaces instead of creating the window for each space: When using .canJoinAllSpaces you can see the blurred NSEffectView flickering on a space change if the spaces have different desktop images. The only way to circumvent this is to create individual windows for each space.

NSApplication menubar does not respond as expected in nib-less Cocoa application

I have the following single file of code, in which I'm trying to create a Cocoa application with basic functionality in as little code as possible without using nibs or Xcode. I have been getting most of my information from the following blog post, in which the equivalent Objective-C code has been posted: (http://www.cocoawithlove.com/2010/09/minimalist-cocoa-programming.html). The only major change that I have made is an AppDelegate class to manage the window, which is typically what is done in Xcode projects.
import Cocoa
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow
override init() {
self.window = NSWindow()
self.window.setFrame(NSRect(x: 0, y: 0, width: 1280, height: 720), display: true)
self.window.collectionBehavior = .FullScreenPrimary
self.window.styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask
self.window.title = "Main Window"
}
func applicationDidFinishLaunching(notification: NSNotification) {
window.makeKeyAndOrderFront(self)
}
func applicationShouldTerminateAfterLastWindowClosed(sender: NSApplication) -> Bool {
return true
}
}
autoreleasepool {
NSApplication.sharedApplication()
NSApp.setActivationPolicy(.Regular)
let delegate = AppDelegate()
NSApp.delegate = delegate
let mainMenu = NSMenu()
NSApp.mainMenu = mainMenu
let applicationMenuItem = NSMenuItem()
mainMenu.addItem(applicationMenuItem)
let applicationMenu = NSMenu()
let quitMenuItem = NSMenuItem()
quitMenuItem.action = #selector(NSApp.terminate(_:))
quitMenuItem.keyEquivalent = "q"
quitMenuItem.title = "Quit Cocoa Window Test"
applicationMenu.addItem(quitMenuItem)
applicationMenuItem.submenu = applicationMenu
NSApp.activateIgnoringOtherApps(true)
NSApp.run()
}
I successfully compile from Terminal with the following command:
swiftc -o bin/CocoaWindowTest -g -framework Cocoa ./src/main.swift
My issue arises with the menu. Although the ⌘Q keyboard shortcut works as expected, the application menu that I've created won't open, and I haven't been able to figure out why.
Solved the problem by calling NSApp.activateIgnoringOtherApps() after NSApp.run() has already been called. To summarize, the main segment of my code now reads something like this:
autoreleasepool {
NSApplication.sharedApplication()
NSApp.setActivationPolicy(.Regular)
let delegate = AppDelegate()
NSApp.delegate = delegate
// Menu setup here...
NSApp.run()
NSApp.activateIgnoringOtherApps(true)
}
You should use mainMenu.setSubmenu(applicationMenu, forItem:applicationMenuItem) to set the submenu. Items with submenus have a special action, submenuAction(_:), assigned, which is responsible for actually showing the submenu. The above method properly assigns that action (and is preferred to setting it yourself).
For what it's worth, I wouldn't set NSApp.mainMenu until the menu is complete.

How can I make an editable text field in a swift shell application

I'm trying to make a editable text region in a NSWindow. So far I can make
a window and add a text field - but when I select it and type characters the characters are echoed in the shell and NOT the text area.
NOTE: this is NOT an Xcode project - I am trying to do this in a single
file in the shell - my goal is to do this in code only
To replicate the error put the following code into a file (experiment.swift) and give the shell command
> swift experiment.swift
Here's the code
import Cocoa
class MyAppDelegate: NSObject, NSApplicationDelegate {
let window = NSWindow()
let ed = NSTextField(frame: NSMakeRect(20, 10, 180, 160))
func applicationDidFinishLaunching(aNotification: NSNotification) {
window.setContentSize(NSSize(width:600, height:200))
window.styleMask = NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask |
NSResizableWindowMask
window.opaque = false
window.center();
window.title = "My window"
ed.font = NSFont(name:"Helvetica Bold", size:20)
ed.stringValue = "edit me"
ed.editable = true
ed.selectable = true
window.contentView!.addSubview(ed)
window.makeKeyAndOrderFront(window)
window.level = 1
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
let app = NSApplication.sharedApplication()
let obj = MyAppDelegate()
app.delegate = obj
app.run()
Before app.run(), add
app.setActivationPolicy(.Regular)
According to the docs, the default activationPolicy is Prohibited:
Prohibited
The application does not appear in the Dock and may not create windows or be activated. [...] This is also the default for unbundled executables that do not have Info.plists.

Display window on OSX using Swift without XCode or NIB

Disclaimer: I'm attempting the following exercise because I think it will be instructive. I'm interested in how it might be done. So please don't be too hasty to jump in with "This is the wrong way to do it, you should never do it like this!"
Working from the commandline with my favourite text editor, I would like to construct a minimal Swift program that displays a window.
It's a GUI/Cococa hello world, if you like.
In the same spirit, I want to avoid NIB.
So, No XCode, No NIB.
I would like to:
compile it with the swift compiler
create a #! swift script which runs using the Swift interpreter
If I can do both of those things I will feel my feet on the ground and be much more at ease upgrading to Xcode.
I tried the following:
window.swift
import Cocoa
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
#IBOutlet weak var window: NSWindow!
let newWindow = NSWindow(contentRect : NSScreen.mainScreen()!.frame
, styleMask : NSBorderlessWindowMask
, backing : NSBackingStoreType.Buffered
, defer : false)
func applicationDidFinishLaunching(aNotification: NSNotification) {
// Insert code here to initialize your application
newWindow.opaque = false
newWindow.movableByWindowBackground = true
newWindow.backgroundColor = NSColor.whiteColor()
newWindow.makeKeyAndOrderFront(nil)
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
However, attempting to run this from the command line fails:
pi#piBookAir.local ~ /Users/pi/dev/macdev:
⤐ swift window.swift
window.swift:3:1: error: 'NSApplicationMain' attribute cannot be used in a
module that contains top-level code
#NSApplicationMain
^
window.swift:1:1: note: top-level code defined in this source file
import Cocoa
^
✘
What's the correct way to eliminate the error?
Porting this code from objective-c to Swift, you get
import Cocoa
let nsapp = NSApplication.shared()
NSApp.setActivationPolicy(NSApplicationActivationPolicy.regular)
let menubar = NSMenu()
let appMenuItem = NSMenuItem()
menubar.addItem(appMenuItem)
NSApp.mainMenu = menubar
let appMenu = NSMenu()
let appName = ProcessInfo.processInfo.processName
let quitTitle = "Quit " + appName
let quitMenuItem = NSMenuItem.init(title:quitTitle,
action:#selector(NSApplication.terminate),keyEquivalent:"q")
appMenu.addItem(quitMenuItem);
appMenuItem.submenu = appMenu;
let window = NSWindow.init(contentRect:NSMakeRect(0, 0, 200, 200),
styleMask:NSTitledWindowMask,backing:NSBackingStoreType.buffered,defer:false)
window.cascadeTopLeft(from:NSMakePoint(20,20))
window.title = appName;
window.makeKeyAndOrderFront(nil)
NSApp.activate(ignoringOtherApps:true)
NSApp.run()
Save it as minimal.swift, compile
swiftc minimal.swift -o minimal
and run
./minimal
You will get an empty window and a menu bar with a menu named like the application and a quit button.
Why it works exactly, I don't know. I'm new to Swift and Cocoa programming, but the linked website explains a bit.
Make a file TestView.swift (like this):
import AppKit
class TestView: NSView
{
override init(frame: NSRect)
{
super.init(frame: frame)
}
required init?(coder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}
var colorgreen = NSColor.greenColor()
override func drawRect(rect: NSRect)
{
colorgreen.setFill()
NSRectFill(self.bounds)
let h = rect.height
let w = rect.width
let color:NSColor = NSColor.yellowColor()
let drect = NSRect(x: (w * 0.25),y: (h * 0.25),width: (w * 0.5),height: (h * 0.5))
let bpath:NSBezierPath = NSBezierPath(rect: drect)
color.set()
bpath.stroke()
NSLog("drawRect has updated the view")
}
}
Make a file TestApplicationController.swift (like this):
import AppKit
final class TestApplicationController: NSObject, NSApplicationDelegate
{
/// Seems fine to create AppKit UI classes before `NSApplication` object
/// to be created starting OSX 10.10. (it was an error in OSX 10.9)
let window1 = NSWindow()
let view1 = TestView(frame: NSRect(x: 0, y: 0, width: 1000, height: 1000))
func applicationDidFinishLaunching(aNotification: NSNotification)
{
window1.setFrame(CGRect(x: 0, y: 0, width: 1000, height: 1000), display: true)
window1.contentView = view1
window1.opaque = false
window1.center();
window1.makeKeyAndOrderFront(self)
// window1.backgroundColor = view1.colorgreen
// window1.displayIfNeeded()
}
func applicationWillTerminate(aNotification: NSNotification) {
// Insert code here to tear down your application
}
}
Make a file main.swift (like this):
//
// main.swift
// CollectionView
//
// Created by Hoon H. on 2015/01/18.
// Copyright (c) 2015 Eonil. All rights reserved.
//
import AppKit
let app1 = NSApplication.sharedApplication()
let con1 = TestApplicationController()
app1.delegate = con1
app1.run()
The last file must not be renamed, main.swift is apparently a special name for swift (otherwise the example will not compile).
Now, enter this (to compile the example):
swiftc -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk TestView.swift TestApplicationController.swift main.swift
Run the code by entering:
./main
It shows a main window (centered) with a nice green collor and a yellow rectangle within it).
You can kill the app by entering Control-C.
Note that this is a swift compilation not an interpreter running, so you have a native app.
Note that -sdk and the path to MacOSX10.11.sdk is essential (otherwise the code will not compile).
Note also that this compilation depends on the latest Xcode distribution, so update MacOSX10.11.sdk to MacOSX10.10.sdk or whatever is in the SDKs directory.
It took a while to find this out ...
Based on the other solutions I wrote a recent version of a single file app.
Requirements: Swift 5.6, Command Line Tools, no XCode, no XIB, no Storyboard.
One file, one class, run it with swift app.swift.
file: app.swift
import AppKit
class App : NSObject, NSApplicationDelegate {
let app = NSApplication.shared
let name = ProcessInfo.processInfo.processName
let status = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
let window = NSWindow.init(
contentRect: NSMakeRect(0, 0, 200, 200),
styleMask: [.titled, .closable, .miniaturizable],
backing: .buffered,
defer: false
)
override init() {
super.init()
app.setActivationPolicy(.accessory)
window.center()
window.title = name
window.hidesOnDeactivate = false
window.isReleasedWhenClosed = false
let statusMenu = newMenu()
status.button?.title = "🤓"
status.menu = statusMenu
let appMenu = newMenu()
let sub = NSMenuItem()
sub.submenu = appMenu
app.mainMenu = NSMenu()
app.mainMenu?.addItem(sub)
}
#IBAction func activate(_ sender:Any?) {
app.setActivationPolicy(.regular)
DispatchQueue.main.async { self.window.orderFrontRegardless() }
}
#IBAction func deactivate(_ sender:Any?) {
app.setActivationPolicy(.accessory)
DispatchQueue.main.async { self.window.orderOut(self) }
}
private func newMenu(title: String = "Menu") -> NSMenu {
let menu = NSMenu(title: title)
let q = NSMenuItem.init(title: "Quit", action: #selector(app.terminate(_:)), keyEquivalent: "q")
let w = NSMenuItem.init(title: "Close", action: #selector(deactivate(_:)), keyEquivalent: "w")
let o = NSMenuItem.init(title: "Open", action: #selector(activate(_:)), keyEquivalent: "o")
for item in [o,w,q] { menu.addItem(item) }
return menu
}
func applicationDidFinishLaunching(_ n: Notification) { }
func applicationDidHide(_ n: Notification) {
app.setActivationPolicy(.accessory)
DispatchQueue.main.async { self.window.orderOut(self) }
}
}
let app = NSApplication.shared
let delegate = App()
app.delegate = delegate
app.run()
The 64 lines of code above provide the following features and fixes over the previous solutions:
app menu is visible and usable
status menu can be clicked and is usable
both menus have working key keybindings
dock item appears when window is open:
app.setActivationPolicy(.regular)
dock item hides when window is closed:
app.setActivationPolicy(.accessory)
window is preserved on close and reused on open:
window.hidesOnDeactivate = false
window.isReleasedWhenClosed = false
Tested on M1 Pro. Here is how it looks.
Pass the -parse-as-library flag to swiftc:
swiftc -parse-as-library window.swift
That said, you'll just end up running into a second error when you do this:
2015-06-10 14:17:47.093 window[11700:10854517] No Info.plist file in application bundle or no NSPrincipalClass in the Info.plist file, exiting