How do I get a titlebar to show programmatically in NSWindow? - swift

Im trying to develop an OS X cocoa application programmatically, and I'm trying to display a window with a title bar which displays the usual traffic light (close, minimise, fullscreen) options at the top.
However, when the window displays on the screen, there is just an empty window.
Here is the code I am using:
class AppDelegate: NSObject, NSApplicationDelegate {
let window = NSWindow(contentRect: NSMakeRect(10, 10, 200, 200),
styleMask: NSWindowStyleMask.closable,
backing: NSBackingStoreType.buffered, defer: true)
func applicationDidFinishLaunching(_ aNotification: Notification) {
self.titleVisibility = .visible;
self.titlebarAppearsTransparent = false;
self.isMovableByWindowBackground = true;
let controller = NSWindowController(window: window)
controller.showWindow(self);
}
I have tried different NSWindowStyleMask when constructing the NSWindow but to no success.
This is what I see:
I am using Xcode 8.3 on 10.12

So you need 4 style masks.
NSWindowStyleMask.closable
NSWindowStyleMask.miniaturizable
NSWindowStyleMask.resizable
NSWindowStyleMask.titled
To put them all into one, you can use array
[NSWindowStyleMask.closable, NSWindowStyleMask.miniaturizable, NSWindowStyleMask.resizable, NSWindowStyleMask.titled]
But try to write in swift style
[.closable, .miniaturizable, .resizable, .titled]

Related

Cannot inject AppDelegate to SwiftUI macos app

I'm new to swift development and stuck developing sattus bar application. Found some good toturials (first, second, third, fourth), and in eash of them at some point authors inject AppDelegate to : App class, kinda:
import SwiftUI
#main
struct CaptureOneAppApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
And in tutorials similar code works just fine, but me getting compile-time error pointing row #5:
Type annotation missing in pattern
As I understand, compiler asks me to add some suffix with type definition, but i have no idea how it should look like and actually not sure if this is a correct way to solve the problem. So, what I'm doing wrong?
UPD AppDelegate.swift code:
import Cocoa
import SwiftUI
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
var window: NSWindow!
var statusBar: StatusBarController?
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Create the SwiftUI view that provides the window contents.
let contentView = ContentView()
// Create the window and set the content view.
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.center()
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: contentView)
window.makeKeyAndOrderFront(nil)
//Initialising the status bar
statusBar = StatusBarController.init()
}
func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}
}
it's just copypasted from first

Xcode SwiftUI window not shown after successful build

I get the following warning, on main.storyboard
Unsupported Configuartion:
Window Controller requires a content view controller
This is the custom class linked to the Window Controller, which is also the StoryBoard Entry Point,
import Cocoa
import SwiftUI
class FirstWindowController: NSWindowController {
override func windowDidLoad() {
super.windowDidLoad()
let contentView = ContentView(myListModel: MyListModel())
.environmentObject(UserData())
self.window?.contentView = NSHostingView(rootView: contentView)
}
}
This is inside the AppDelegate.swift which is annotated as #NSApplicationMain.
func applicationDidFinishLaunching(_ aNotification: Notification) {
window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 480, height: 300),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.center()
window.setFrameAutosaveName("Main Window”)
}
The main.storyboard, AppDelegate.swift, and FirstWindowController.swift are identical to those of a project which was launching and showing the application window with no problem. I just renamed it to something else, and removed the Core Data support from the code. But in this project, the window doesn’t show up after successful build.
I also have checked and compared all the configuration of the storyboard for both of these projects. They seem to be totally identical.
Any help for fixing this would be appreciated.
This might be due to a bug.
I removed all the other schemes but the one I was using in the project and the window is now loading.
Yet, the same warning is still there.

Track NSWindow focus? (Swift, macOS)

I'm trying to track a created windows focus so I can perform actions on those events.
I'm able to track a windows frame dimensions with the notification center using NSView.frameDidChangeNotification, but I cant find a correct way of using something like NSWindowDidResignKeyNotification or NSWindowDidResignMainNotification.
private func newWindow() {
let windowInfo = WindowInfo()
let contentView = ContentView()
.environmentObject(windowInfo)
let window = NSWindow(
contentRect: NSRect(x: 0, y: 0, width: 350, height: 600),
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered,
defer: false
)
window.isReleasedWhenClosed = false
window.contentView = NSHostingView(rootView: contentView)
window.contentView?.postsFrameChangedNotifications = true
window.makeKeyAndOrderFront(nil)
// vvv I'm trying to use a similar method of being notified when a created window loses/regains focus. vvv
// v v v
NotificationCenter.default.addObserver(forName: NSView.frameDidChangeNotification, object: nil, queue: nil) { (notification) in
windowInfo.frame = window.frame
}
}
Also, if theres some method for detecting window focus in SwiftUI, I could use that too. The notifications that actions are performed on are for my Views in SwiftUI
This was just a dumb oversight from me (it was pretty late at night), and I found the line I needed.
Adding NSWindow.didBecomeKeyNotification did the trick to properly catch the focus events.
Also changing object: nil to object: window made sure the focus events caught were only for the specific window, instead of all.

NSPanel not hiding when focus is lost

I am trying to create a window like Spotlight.
As in Spotlight it should hide when the background is clicked. I tried doing it unsuccessfully with NSWindow but I was lead to believe using NSPanel instead would solve the problem.
However, even when using NSPanel the window does not hide.
Here is the code I'm using.
let panel = NSPanel(contentRect: CGRect(x: 0, y: 0, width: 200, height: 200), styleMask: [.titled, .nonactivatingPanel], backing: .buffered, defer: true)
panel.level = .mainMenu
panel.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary]
panel.orderFrontRegardless()
It is due to used window level (.mainMenu which is above all windows), so you need to hide it explicitly via delegate methods
so assuming you create window/panel in your controller, make that controller a delegate of window
panel.delegate = self
and implement something like
extension ViewController { // << your controller class here
func windowDidResignKey(_ notification: Notification) {
if let panel = notification.object as? NSWindow {
panel.close()
}
}
}

CGDisplayCreateImage only returns wallpaper and task bar

I am trying to get the pixel colors from the screen for a specified portion of the display.
I am using CGDIsplayCreateImage(_:) to do so, but for some reason instead of creating a screenshot of the currently open windows it just gives an image of the wallpaper and the task bar.
In order to visualize the screenshot I am using a SwiftUI view. In my application I actually don't need the screenshot displayed.
struct ScreenshotView: View {
let cgImage: CGImage
var body: some View {
Image(decorative: cgImage, scale: 3)
}
}
And the applicationDidFinishLaunching(_:) methods looks like this.
func applicationDidFinishLaunching(_ aNotification: Notification) {
let contentRect = NSRect(x: 0, y: 0, width: 240, height: 240)
// Create the window and set the content view.
window = NSWindow(
contentRect: contentRect,
styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView],
backing: .buffered, defer: false)
window.center()
window.setFrameAutosaveName("Main Window")
window.contentView = NSHostingView(rootView: ScreenshotView(cgImage: CGDisplayCreateImage(CGMainDisplayID())!))
window.makeKeyAndOrderFront(nil)
}
Since XCode and some other apps are open it should give me a screenshot of the current screen with all open windwos. Instead I get a screenshot of the wallpaper and the taskbar showing my apps name. No apps are showing and the dock is also missing.
Am I doing something wrong or is this a bug?
In this stackoverflow answers suggest that I am using the function correctly.
Even if this might be obvious to some people I will answer my own question here using the help of Ken Thomases.
Below you can find the settings I set within my target. It now works after every rebuild.
Make sure to deactivate automatic signing and set the signing certificate to 'Sign to Run Local'.
Hope this helps someone at some point.