LoneSTrider
LoneSTrider

Reputation: 51

Can I access the properties of the window that hosts a SwiftUI scene

I want to move a window to a specific location on the Mac desktop. Is there a way to access and manipulate this view's properties? This would be a window created by SwiftUI to hold a scene.

Upvotes: 2

Views: 778

Answers (2)

LoneSTrider
LoneSTrider

Reputation: 51

Based on @asperi comment above, I was able to distill the solution to this.

import SwiftUI

struct ContentView: View {
    
    @State var theWindow: NSWindow?
    
    var body: some View {
        Text("Window Access")
            .frame(width: 400, height: 100, alignment: .center)
            .padding()
            .background(WindowAccessor(window: $theWindow))
            .onTapGesture {
                theWindow!.setFrameTopLeftPoint(NSPoint(x: 500, y: 800))
            }
    }
}

struct WindowAccessor: NSViewRepresentable {
    @Binding var window: NSWindow?

    func makeNSView(context: Context) -> NSView {
        let view = NSView()
        DispatchQueue.main.async {
            self.window = view.window   // << right after inserted in window
        }
        return view
    }

    func updateNSView(_ nsView: NSView, context: Context) {}
}

Upvotes: 2

Lemon
Lemon

Reputation: 1450

I would use a library called Swindler

After adding this to your AppDelegate to ask for AX permissions,

func applicationDidFinishLaunching(_ aNotification: Notification) {
    guard AXSwift.checkIsProcessTrusted(prompt: true) else {
        print("Not trusted as an AX process; please authorize and re-launch")
        NSApp.terminate(self)
        return
    }
    // your code here
}

You can then play around with windows:

Swindler.initialize().then { state -> Void in
    let screen = state.screens.first!

    let allPlacedOnGrid = screen.knownWindows.enumerate().map { index, window in
        let rect = gridRect(screen, index)
        return window.frame.set(rect)
    }

    when(allPlacedOnGrid) { _ in
        print("all done!")
    }
}.catch { error in
    // ...
}

func gridRect(screen: Swindler.Screen, index: Int) -> CGRect {
    let gridSteps = 3
    let position  = CGSize(width: screen.width / gridSteps,
                           height: screen.height / gridSteps)
    let size      = CGPoint(x: gridSize.width * (index % gridSteps),
                            y: gridSize.height * (index / gridSteps))
    return CGRect(origin: position, size: size)
}

More information here.

Upvotes: 0

Related Questions