Post

Replies

Boosts

Views

Activity

SCNCylinder shows mirrored texture for base and top elements
SCNBox renders the textures correctly, but SCNCylinder seems to mirror the base and top textures. The following code reproduces the issue (just set the image variable to the name of the image you're using, in this case an image with the number 2 in it): class GameViewController: NSViewController { let image = "art.scnassets/image.heic"          override func viewDidLoad() {         super.viewDidLoad()                  let scene = SCNScene(named: "art.scnassets/ship.scn")!                  let cameraNode = SCNNode()         cameraNode.camera = SCNCamera()         scene.rootNode.addChildNode(cameraNode)         cameraNode.position = SCNVector3(x: 0, y: 3, z: 3)         let scnView = self.view as! SCNView         scnView.scene = scene                  let node = SCNNode(geometry: SCNCylinder(radius: 0.5, height: 1))         node.geometry!.materials = [SCNMaterial(), SCNMaterial(), SCNMaterial()]         node.geometry!.materials[1].diffuse.contents = image         node.geometry!.materials[2].diffuse.contents = image         node.position.x = -1         node.runAction(.repeatForever(.rotate(by: 1, around: SCNVector3(x: 1, y: 0, z: 0), duration: 1)))         scene.rootNode.addChildNode(node)         let node2 = SCNNode(geometry: SCNBox(width: 1, height: 1, length: 1, chamferRadius: 0))         node2.geometry!.materials = [SCNMaterial(), SCNMaterial(), SCNMaterial(), SCNMaterial(), SCNMaterial(), SCNMaterial()]         node2.geometry!.materials[4].diffuse.contents = image         node2.geometry!.materials[5].diffuse.contents = image         node2.position.x = 1         node2.runAction(.repeatForever(.rotate(by: 1, around: SCNVector3(x: 1, y: 0, z: 0), duration: 1)))         scene.rootNode.addChildNode(node2)         cameraNode.look(at: SCNVector3(x: 0, y: 0, z: 0))     } }
0
0
656
Feb ’23
Cannot download Feedback Assistant data
I have been trying for several months now to download my Feedback Assistant data on privacy.apple.com. Since the very first time I tried, I keep receiving emails that "because of a technical issue it wasn't possible to download your data and you'll receive a notification as soon as the problem is solved. This procedure can last up to 60 days". And some days later I receive an email "The technical problem is now solved. To get a copy of your data, initiate a new request". I already initiated a new request at least twice, and each time I get the same outcome I just described, i.e. one email tells me the problem is solved, and the next one tells me that there is a problem that will be solved within 60 days. Am I doing something wrong?
0
0
578
Feb ’23
SCNNode.position is sometimes not reflected on screen
The desired outcome of the code below is that both the red and yellow spheres should be at the same position at the center of the scene, (0, 0, 0), but instead the red sphere remains at its initial position (1, 0, 0). Commenting out any of the lines marked in the code, strangely, solves the issue. The code shows a simplified version of some other code, so it would be desirable to keep the order of the lines as they currently are. Am I doing something wrong? class GameViewController: NSViewController {          override func viewDidLoad() {         super.viewDidLoad()                  let scene = SCNScene(named: "art.scnassets/ship.scn")!                  let cameraNode = SCNNode()         cameraNode.camera = SCNCamera()         scene.rootNode.addChildNode(cameraNode)         cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)                  let lightNode = SCNNode()         lightNode.light = SCNLight()         lightNode.light!.type = .omni         lightNode.position = SCNVector3(x: 0, y: 10, z: 10)         scene.rootNode.addChildNode(lightNode)                  let scnView = self.view as! SCNView         scnView.scene = scene                  let parent0 = SCNNode()         scene.rootNode.addChildNode(parent0)         let parent1 = SCNNode()         scene.rootNode.addChildNode(parent1)         let sphere0 = SCNNode(geometry: SCNSphere(radius: 1))         sphere0.geometry!.firstMaterial!.diffuse.contents = NSColor.red                  let sphere1 = SCNNode(geometry: SCNSphere(radius: 1))         sphere1.geometry!.firstMaterial!.diffuse.contents = NSColor.yellow                  sphere0.position = SCNVector3(x: -1, y: 0, z: 0) // commenting out this line solves the issue         parent1.addChildNode(sphere0) // or commenting out this line solves the issue         sphere0.position = SCNVector3(x: 0, y: 0, z: 0)         parent0.addChildNode(sphere1) // or commenting out this line solves the issue                  DispatchQueue.main.asyncAfter(deadline: .now() + 1) {             print(sphere0.worldPosition, sphere1.worldPosition)         }     } }
1
0
796
Feb ’23
Getting clicked item index in NSPathControl with pathItems instead of pathComponentCells
Since NSPathControl.setPathComponentCells(_:) and .clickedPathComponentCell() are deprecated, I'm trying to use pathItems and clickedPathItem instead. Since I'm representing a virtual path, I cannot use the NSPathControl.url setter, but instead set pathItems directly. The problem is that in the action method it doesn't seem possible to get the index of the clicked path item, nor does it seem possible to associate any kind of data with each path item, since when the action method is called, the actual object instances stored in pathItems and also the one returned by clickedPathItem change every time. Here is the sample code that reproduces the issue: class ViewController: NSViewController {     @IBOutlet weak var pathControl: NSPathControl!          override func viewDidLoad() {         super.viewDidLoad()         pathControl.pathItems = ["a", "b", "c"].map({ title in             let item = NSPathControlItem()             item.title = title             return item         })     }     @IBAction func selectPath(_ sender: NSPathControl) {         print(sender.clickedPathItem!.description, sender.clickedPathItem!.title, sender.pathItems.description)     }      } Here is a sample output (notice how the printed addresses change every time): <NSPathControlItem: 0x6000012780a0> a [<NSPathControlItem: 0x6000012780a0>, <NSPathControlItem: 0x600001278020>, <NSPathControlItem: 0x600001278090>] <NSPathControlItem: 0x600001278070> a [<NSPathControlItem: 0x600001278070>, <NSPathControlItem: 0x600001278140>, <NSPathControlItem: 0x6000012780d0>] <NSPathControlItem: 0x60000124c030> a [<NSPathControlItem: 0x60000124c030>, <NSPathControlItem: 0x60000124c080>, <NSPathControlItem: 0x60000124c070>]
Topic: UI Frameworks SubTopic: AppKit Tags:
7
0
860
Feb ’23
Passing nil to NEFilterDataProvider.apply(_:completionHandler:) causes error and doesn't apply default settings as documented
I'm trying to adapt the Filter Network Traffic sample code found at https://developer.apple.com/documentation/networkextension/filtering_network_traffic In FilterDataProvider.swift I've replaced the argument passed to NEFilterDataProvider.apply(_:completionHandler:) with nil, which according to the documentation should apply the default settings. Instead I'm getting the following error: Error Domain=NEFilterErrorDomain Code=1 "The settings parameter doesn’t correspond to a NEFilterSettings object" (translated from my local language) (When logging the error with os_log, the Console app just shows it as <private>. A NSLog call instead displays it correctly.) After that the internet doesn't seem to work at all anymore and I have to trash the app to make the internet work again. (If the bin is not completely empty before trashing the app from the Applications folder, I'm prompted that there is another operation in progress like moving a file.) If a nil parameter doesn't work, what is the correct way of not filtering anything, but just observing all the network traffic?
1
0
404
Mar ’23
Get executable path from audit token provided by NEFilterDataProvider
I'm using this code to get the path of an executable from the audit token provided in NEFilterDataProvider.handleNewFlow(_:): private func securePathFromAuditToken(_ auditToken: Data) throws -> String? { let secFlags = SecCSFlags() var secCode: SecCode? var status = SecCodeCopyGuestWithAttributes(nil, [kSecGuestAttributeAudit: auditToken] as CFDictionary, secFlags, &secCode) guard let secCode = secCode else { throw SecError(status) } var secStaticCode: SecStaticCode? status = SecCodeCopyStaticCode(secCode, secFlags, &secStaticCode) guard let secStaticCode = secStaticCode else { throw SecError(status) } var dict: CFDictionary? status = SecCodeCopySigningInformation(secStaticCode, secFlags, &dict) guard let dict = dict as NSDictionary? else { throw SecError(status) } if let identifier = dict[kSecCodeInfoIdentifier as String] as? String, let path = NSWorkspace.shared.urlForApplication(withBundleIdentifier: identifier)?.path { return path } else if let path = dict[kSecCodeInfoMainExecutable as String] as? String { return path } return nil } But it seems that only applications inside the /Applications folder have a non-nil path. For all other executables I have to resort to this code, which I have read is not as secure: private func insecurePathFromAuditToken(_ auditToken: Data) throws -> String? { if auditToken.count == MemoryLayout<audit_token_t>.size { let pid = auditToken.withUnsafeBytes { buffer in audit_token_to_pid(buffer.baseAddress!.assumingMemoryBound(to: audit_token_t.self).pointee) } let pathbuf = UnsafeMutablePointer<Int8>.allocate(capacity: Int(PROC_PIDPATHINFO_SIZE)) defer { pathbuf.deallocate() } let ret = proc_pidpath(pid, pathbuf, UInt32(PROC_PIDPATHINFO_SIZE)) if ret <= 0 { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) } return String(cString: pathbuf) } return nil } This seems to happen with both NEFilterFlow.sourceAppAuditToken and sourceProcessAuditToken. Is this expected? Can it really be that all executables that are not apps shipped with macOS are not signed?
1
0
585
Mar ’23
Listing all apps with App Store Connect API returns error ENTITY_INVALID
I'm using this code to get all apps in App Store Connect: let jwt = ... var request = URLRequest(url: URL(string: "https://api.appstoreconnect.apple.com/v1/apps")!) request.setValue("Bearer \(jwt)", forHTTPHeaderField: "Authorization") let session = URLSession(configuration: .ephemeral) let task = session.dataTask(with: request) { data, response, error in if let error = error { print(error) } else if let data = data { print(String(data: data, encoding: .utf8)) } } task.resume() But the response is an error status: 400, code: ENTITY_INVALID, title: JSON processing failed. What entity is this error referring to? And what JSON is invalid? The JWT token seems to be fine, since when using a random value I get an error 401 NOT_AUTHORIZED.
0
0
549
Mar ’23
Xcode UI testing right-to-left language but UI is left-to-right
In my UI test I'm trying to set different languages. I noticed that with right-to-left languages, such as Arabic, the UI is still aligned left-to-right. When I manually run the app with the scheme's language set to Arabic, the UI is correctly aligned right-to-left. Am I missing something? let app = XCUIApplication() app.launchArguments += ["-AppleLanguages", "(ar)"] app.launch()
1
0
1.2k
Mar ’23
Force app appearance in UI tests to be light or dark
In my UI test I'm trying to force the app's appearance (light or dark). When the system appearance is light, I can force the app to be dark with this code: var app = XCUIApplication() app.launchArguments += ["-AppleInterfaceStyle", "Dark"] app.launch() But replacing Dark with Light doesn't have any effect: if the system appearance is dark: the app remains dark. Is this not possible?
0
0
463
Mar ’23
Using custom shadow path on NSView
Unfortunately it seems that setting the shadow attributes on the layer directly doesn't work: let shadowView = NSView(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) shadowView.wantsLayer = true shadowView.layer!.backgroundColor = .white shadowView.layer!.shadowRadius = 50 shadowView.layer!.shadowColor = .black shadowView.layer!.shadowOffset = CGSize(width: 0, height: -30) shadowView.layer!.shadowPath = CGPath(roundedRect: shadowView.bounds, cornerWidth: 25, cornerHeight: 25, transform: nil) Setting the NSView.shadow property instead works: let shadowView = NSView(frame: CGRect(x: 0, y: 0, width: 100, height: 100))let shadow = NSShadow() shadow.shadowBlurRadius = 50 shadow.shadowColor = .black shadow.shadowOffset = CGSize(width: 0, height: -30) shadowView.shadow = shadow shadowView.wantsLayer = true shadowView.layer!.backgroundColor = .white But NSShadow doesn't support a custom path. What's the easiest way to set a shadow with a custom path?
Topic: UI Frameworks SubTopic: AppKit Tags:
0
0
496
Mar ’23
Override user default in UI test with key containing whitespaces
In my UI test I'm trying to force some user defaults. It seems that one can override them with code such as: var app = XCUIApplication() app.launchArguments += ["-myUserDefaultKey", "value"] app.launch() But I would like to replace the value of a default where the key contains whitespaces, such as the key created automatically when setting NSSplitView.autosaveName = "someSplitView", which is NSSplitView Subview Frames someSplitView. I tried escaping the whitespaces with NSSplitView\\ Subview\\ Frames\\ someSplitView and putting the key between single or double quotes, but nothing helped. Is this somehow possible? Also, what would be the preferred way of temporarily removing a user default instead of overwriting it?
1
0
1.5k
Mar ’23
Localized name for default sounds in /System/Library/Sounds
In the Mail settings one can choose one of the default sounds located at /System/Library/Sounds. Playing them is easy, e.g. with NSSound(named: "Purr")?.play(), but how can I show a localized name for those sounds as Mail does? I couldn't find any way of getting a localized name. Would I have to manually translate each one to each supported language?
Topic: UI Frameworks SubTopic: AppKit Tags:
0
0
448
Mar ’23
Mismatching locale identifiers for default languages in Xcode and App Store Connect
The list of "main" languages that can be added in Xcode in the project's Info panel (i.e. the ones that can be added without diving into the long submenu) are basically the same that can be added in App Store Connect (except that Xcode also lists Chinese (Hong Kong) (zh-HK) and English (India) (en-IN) which don't exist in App Store Connect). But I noticed that the locale identifiers sometimes refer to different regions: e.g. Xcode has Spanish (es) and Spanish (Latin America) (es-419) while App Store Connect uses Spanish (Spain) and Spanish (Mexico) which when downloaded through the App Store Connect API have the identifiers en-ES and en-MX. Forgive my ignorance, but does that mean that the language used in Latin America and Mexico is the same? Or should I instead select the Mexico variant in Xcode so that the locale identifiers used in the app and on the App Store match? All the mismatching locales are (Xcode first, App Store Connect second): ar vs. ar-SA de vs de-DE en vs en-US es vs es-ES es-419 vs es-MX fr vs fr-FR nl vs nl-NL
0
0
670
Mar ’23
Reading Finder Info ATTR_CMN_FNDRINFO with getattrlistbulk
After successfully implementing a scan with getattrlistbulk (thanks to https://developer.apple.com/forums/thread/656787/), I'm now trying for each file to get whether the extension is shown in the Finder or not. I think this could be read from the Finder Info (i.e.ATTR_CMN_FNDRINFO), although I'm not sure, since there doesn't seem do be any documentation about what this attribute actually contains. From the setattrlist documentation archive it seems that it is char[32], and I've tried different changes within readUnaligned() so that it would work with an array, but I couldn't get it to work. Below is my current implementation. The comment How to get Finder Info? shows where the implementation currently doesn't work. class AppDelegate: NSObject, NSApplicationDelegate { private static var attributeKeys: attrlist = { var attributeKeys = attrlist() attributeKeys.bitmapcount = u_short(ATTR_BIT_MAP_COUNT) attributeKeys.commonattr = attrgroup_t(ATTR_CMN_RETURNED_ATTRS) | attrgroup_t(bitPattern: ATTR_CMN_ERROR | ATTR_CMN_NAME | ATTR_CMN_OBJTYPE | ATTR_CMN_MODTIME | ATTR_CMN_FNDRINFO | ATTR_CMN_FILEID) attributeKeys.fileattr = attrgroup_t(bitPattern: ATTR_FILE_DATALENGTH) return attributeKeys }() private let bufferWithAlignment16 = UnsafeMutableRawBufferPointer.allocate(byteCount: 256, alignment: 16) func applicationDidFinishLaunching(_ notification: Notification) { let openPanel = NSOpenPanel() openPanel.canChooseDirectories = true openPanel.canChooseFiles = false openPanel.runModal() try! scan(directoryPath: openPanel.urls[0].path) } deinit { bufferWithAlignment16.deallocate() } func scan(directoryPath: String) throws { let fileDescriptor = open(directoryPath, O_RDONLY) if fileDescriptor < 0 { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) } defer { let result = close(fileDescriptor) assert(result == 0) } let attributeBuffer = UnsafeMutableRawBufferPointer.allocate(byteCount: 2048, alignment: 16) defer { attributeBuffer.deallocate() } while true { let itemCount = Int(getattrlistbulk(fileDescriptor, &AppDelegate.attributeKeys, attributeBuffer.baseAddress!, attributeBuffer.count, 0)) if itemCount == 0 { return } else if itemCount > 0 { var entryOffset = attributeBuffer.baseAddress! for _ in 0..<itemCount { let length = Int(entryOffset.load(as: UInt32.self)) try unpackResources(at: entryOffset + MemoryLayout<UInt32>.size, parentDirectory: directoryPath) entryOffset += length } } else if errno != EINTR { throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno)) } } } private func unpackResources(at attributeOffset: UnsafeMutableRawPointer, parentDirectory: String) throws { var attributeOffset = attributeOffset let returned = attributeOffset.load(as: attribute_set_t.self) attributeOffset += MemoryLayout<attribute_set_t>.size var error: Error? if (returned.commonattr & attrgroup_t(bitPattern: ATTR_CMN_ERROR)) != 0 { error = NSError(domain: NSPOSIXErrorDomain, code: Int(attributeOffset.load(as: UInt32.self))) attributeOffset += MemoryLayout<UInt32>.size } let name: String if (returned.commonattr & attrgroup_t(bitPattern: ATTR_CMN_NAME)) != 0 { let nameInfo = attributeOffset.load(as: attrreference_t.self) name = String(cString: (attributeOffset + Int(nameInfo.attr_dataoffset)).assumingMemoryBound(to: CChar.self)) attributeOffset += MemoryLayout<attrreference_t>.size } else { name = "" } let fileType: fsobj_type_t if (returned.commonattr & attrgroup_t(bitPattern: ATTR_CMN_OBJTYPE)) != 0 { fileType = attributeOffset.load(as: fsobj_type_t.self) attributeOffset += MemoryLayout<fsobj_type_t>.size } else { fileType = VNON.rawValue } var modificationDate: Date? if (returned.commonattr & attrgroup_t(bitPattern: ATTR_CMN_MODTIME)) != 0 { modificationDate = Date(timeIntervalSince1970: TimeInterval(readUnaligned(pointer: attributeOffset, as: timespec.self).tv_sec)) attributeOffset += MemoryLayout<timespec>.size } // How to get Finder Info? let finderInfo: [Int8] if (returned.commonattr & attrgroup_t(bitPattern: ATTR_CMN_FNDRINFO)) != 0 { finderInfo = readUnaligned(pointer: attributeOffset, as: [Int8].self) attributeOffset += MemoryLayout<Int8>.size } else { finderInfo = [] } let fileId: UInt64 if (returned.commonattr & attrgroup_t(bitPattern: ATTR_CMN_FILEID)) != 0 { fileId = readUnaligned(pointer: attributeOffset, as: UInt64.self) attributeOffset += MemoryLayout<UInt64>.size } else { fileId = 0 } let size: Int64 if (returned.fileattr & attrgroup_t(bitPattern: ATTR_FILE_DATALENGTH)) != 0 { size = Int64(readUnaligned(pointer: attributeOffset, as: off_t.self)) attributeOffset += MemoryLayout<off_t>.size } else { size = 0 } if let error = error { throw error } let isDirectory = fileType == VDIR.rawValue let isSymbolicLink = fileType == VLNK.rawValue print(name, isDirectory, isSymbolicLink, modificationDate as Any, finderInfo, fileId, size) } private func readUnaligned<Result>(pointer: UnsafeRawPointer, as: Result.Type) -> Result { bufferWithAlignment16.copyMemory(from: UnsafeRawBufferPointer(start: pointer, count: MemoryLayout<Result>.size)) return bufferWithAlignment16.baseAddress!.load(as: Result.self) } }
1
0
525
Apr ’23