Post

Replies

Boosts

Views

Activity

Reply to Resizing text to fit available space
I just tried to load a video with subtitles in Safari, and the subtitles resize perfectly with the video (or at least the subtitle width is always proportional to the video width, while the height seems to be adjusted so that the line height is an integer, i.e. it changes in small jumps). Is it a secret how it's done, or can you share how that's implemented?
Topic: UI Frameworks SubTopic: AppKit Tags:
Oct ’25
Reply to NSDocument doesn't autosave last changes
Thanks. I added a link to this post to the feedback. NSDocument.fileURL is nil for a new document that hasn't been saved – In that case, when you try to terminate your app or close the document window, AppKit shows an alert asking if you'd save the document, and so you should be fine. Yes, but only assuming that the document has been marked as dirty... which is what we're trying to work around. I noticed that there is another issue now: Create a new document. Type a letter. Switch to another app and back again. Type another letter. Quit and restart the app. The document is correctly restored, but when selecting File > Close (or hitting Command-W), it is closed without asking whether I want to save or discard it, and so it probably stays in its autosave directory without the user knowing where it is. This is my current implementation: class Document: NSDocument { private var textStorage: NSTextStorage! private(set) var savedText: String? override func data(ofType typeName: String) throws -> Data { savedText = textStorage.string ... } } func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { var remaining = 1 for document in documents as! [Document] { if document.textStorage.string != document.savedText, let fileURL = document.fileURL, let fileType = document.fileType { remaining += 1 document.save(to: fileURL, ofType: fileType, for: .saveOperation) { [self] error in if let error = error { presentError(error) } else { remaining -= 1 if remaining == 0 { NSApp.reply(toApplicationShouldTerminate: true) } } } } } remaining -= 1 return remaining == 0 ? .terminateNow : .terminateLater }
Topic: UI Frameworks SubTopic: AppKit Tags:
Oct ’25
Reply to NSDocument doesn't autosave last changes
Same with document.fileType. When do these properties become non-nil? I'm afraid they don't become non-nil soon enough for new documents. You ignore the error parameter of the callback passed to save(to:ofType:for:callback:). Shouldn't app termination be cancelled if an error happens while saving? I noticed that you used NSDocumentController.shared.currentDocument. In my example above I iterated through NSDocumentController.shared.documents. Is there a specific reason why you didn't do so as well? I still can't wrap my head around this behaviour that sometimes discards the latest text changes. It appears to me as a bug, but I got the impression that you still see it as expected behaviour. As I mentioned at the beginning, when entering any text, switching to another app and back again, then entering some new text and quitting the app, the last changes are discarded. Why does this only happen for changes that are inserted after switching to another app and back again? Why do changes inserted in a new document always seem to be saved, provided that I don't switch app? I tried creating a new document and typing the letters "a b c d e" with a 1 second time interval after each one, and they were always correctly restored after restarting the app. Whereas when creating a new document, typing the letter "a", switching to another app and back again, then typing "b c d e" (again with a 1 second time interval after each one) and quitting the app, only "a" is restored. If this is intended, what's the intention/logic behind this behaviour?
Topic: UI Frameworks SubTopic: AppKit Tags:
Sep ’25
Reply to Resizing text to fit available space
By "some text that should appear the same," did you mean that the text size (both width and height) changes proportionally with the window size? Correct. Worth mentioning though, adjustsFontSizeToFitWidth doesn't provide a pixel perfection result. I haven't used UILabel.adjustsFontSizeToFitWidth before, so I'm not sure how it actually behaves, and I'm also not sure what you mean with "pixel perfection". I'm looking for a solution that resizes the text so that it stays proportional to the container view frame (which has a fixed aspect ratio). To be specific, I'm simulating subtitles on top of a video. While playing with NSString.size(withAttributes:) and NSAttributedString.size(), I noticed that these methods only allow me to determine the size of a string when laid out on a single, infinite line. There is no equivalent to NSString.draw(in:withAttributes:) that also takes a rectangle. Should I instead use NSTextView (in which the text is eventually laid out anyway) and query its frame property?
Topic: UI Frameworks SubTopic: AppKit Tags:
Sep ’25
Reply to Control status item and login item from within app
I'm sorry for the confusion, I know the two are completely unrelated. I just wanted to point out that they are currently different in the following way: one can be controlled within the app (login items), and the other one cannot (status item). For me, it would have made sense if both can be managed in System Settings alone. I just thought that perhaps it was Apple's intention to "slowly" migrate the status item to something that can strictly be toggled in System Settings (similarly to widgets and extensions which cannot be added or removed by the app itself).
Sep ’25
Reply to Control status item and login item from within app
Thanks for explaining about SMAppService. Admittedly I haven't used it to add login items or agents yet, and I probably made some wrong assumptions about how it would work. Regarding the status item, I filed FB20384263. Below is the code I attached to reproduce it. If this bug gets solved, will I be able to change isVisible back to true from within the app and have it reflected in System Settings? That's what I was talking about in my previous reply: if the current behaviour is intended, then one could enable the status item in the app, disable it in System Settings, and later become mad at the app because apparently the in-app preference doesn't make the status item visible again. That's why I was considering to remove the in-app preference and let the user toggle it in System Settings, just like with the system status bar icons. I personally like the idea of an app offering the functionality and then letting the user enable or disable it outside of the app, just like widgets or extensions (e.g. for Finder and Shortcuts). @main class AppDelegate: NSObject, NSApplicationDelegate { var statusItem: NSStatusItem! func applicationDidFinishLaunching(_ aNotification: Notification) { statusItem = NSStatusBar.system.statusItem(withLength: 20) statusItem.button?.image = NSImage(systemSymbolName: "globe", accessibilityDescription: nil) Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [self] _ in print(Date(), statusItem.isVisible) } } }
Sep ’25
Reply to NSDocument doesn't autosave last changes
I'd really appreciate any concrete tip on how I should save the document, because everything I've tried doesn't work. Simply calling updateChangeCount(_:), like we already saw, messes with the undo mechanism. How is the text view able to save everything I input when the window first appears and then quit the app, but isn't able to when switching to another app and back again? This is the last thing I tried, and when quitting the app the .terminateNow branch is always executed. Just calling endUndoGrouping() without beginUndoGrouping() logs an error in the Xcode console that no undo group is currently open. func applicationShouldTerminate(_ sender: NSApplication) -> NSApplication.TerminateReply { for document in documents { document.undoManager?.beginUndoGrouping() document.undoManager?.endUndoGrouping() } let edited = documents.filter({ $0.hasUnautosavedChanges }) if edited.isEmpty { return .terminateNow } var remaining = edited.count for document in edited { document.autosave(withImplicitCancellability: false) { [self] error in if let error = error { presentError(error) } else { remaining -= 1 if remaining == 0 { NSApp.reply(toApplicationShouldTerminate: true) } } } } return .terminateLater }
Topic: UI Frameworks SubTopic: AppKit Tags:
Sep ’25
Reply to NSDocument doesn't autosave last changes
In your case, the changes in your text view don't go to the undo stack Only the last changes, all previous other changes do as expected. save the document as needed That is what I'm wondering about. What is the correct way of nudging the undo mechanism so that autosaving would see the document as dirty? We already saw that simply calling updateChangeCount(_:) breaks the undo mechanism. though AppKit folks may see the current behavior, which skips the save for a clean document when terminating the app, as correct Skipping save for a clean document is correct in my opinion as well, but the problem is that the document should not be clean in this case, and the question is how it should correctly be marked as dirty without breaking the undo mechanism. The text view probably has an open undo group (waiting for more text to be inserted) that should be closed when trying to quit the app, so that the document is then correctly marked as dirty.
Topic: UI Frameworks SubTopic: AppKit Tags:
Sep ’25
Reply to NSDocument doesn't autosave last changes
Thanks. Your code doesn't do step 2, and that's why your changes are lost. But again, even without doing that, the document is regularly saved, so the fact that the very last changes are not saved is, from my point of view, unexpected behaviour. I came across NSDocument.updateChangeCount(_:) some time ago, but concluded that I shouldn't interfere with automatic saving done by the text view. For instance, when using your latest code, if I type anything in an empty document, then undo all the changes and try to close the now empty document, it presents a save panel. This doesn't happen when I just let the text view track the changes (which is also what I would expect). The documentation for that method reads: If you are implementing undo and redo in an app, you should increment the change count every time you create an undo group and decrement the change count when an undo or redo operation is performed. Note that if you are using the NSDocument default undo/redo features, setting the document’s edited status by updating the change count happens automatically. You only need to invoke this method when you are not using these features. Since the documentation says that I don't need to call that method when I use the default undo mechanism and, like I explained above, doing so introduces unwanted behaviour, I'm a little wary. I even had this code in my production app for some time many years ago, but then removed it again, possibly because it caused other unwanted side effects or bugs (although I don't remember exactly right now). I think I also tried implementing my own undo mechanism for text views, but quickly figured out that going beyond a basic implementation (registering a new undo group for each typed letter, which is a pain for the user to undo and not what they're used to) would take too much time. It looks to me like the default undo mechanism would need to be nudged when the user tries to close a document or the app. Would that be something AppKit could do automatically in a future release, and can I nudge it somehow now?
Topic: UI Frameworks SubTopic: AppKit Tags:
Sep ’25
Reply to Control status item and login item from within app
Thanks for your input. I haven't tested this, but I think isVisible will tell you when it's been disabled. I tried before posting, but isVisible stays true even when disabling the status item in System Settings. I'd generally recommend using an agent (not login item) But will the agent be listed in System Settings > General > Login Items? If not, then that could be another source of confusion, similar to the status item: the user can enable "launch at login" both in the app (which uses an agent) and in System Settings (which uses a login item), then later removes it from System Settings and wonders why it keeps being launched at login (because they forgot that they have to disable it in the app as well). In my opinion it would make more sense to use an option that is kept in sync between the app and System Settings, or remove it from the app entirely since it can already be done in System Settings. Looking at how different privacy features are implemented in macOS, I would have expected that login items (or agents, or however we might call them) can be disabled in System Settings, without the app being able to turn them on again without the user noticing. That's the same reasoning that makes me want to remove the option to show or hide the status item from my app in macOS 26: System Settings has the last word in regard to the status item's visibility, so it would only be confusing to have that option in the app if toggling it doesn't do anything. After all, the status item is something similar to a widget, and I haven't done widgets yet but I would assume that they can only be added and removed by the user outside of the app (in macOS itself).
Sep ’25
Reply to Sidebar created on macOS 26 with NSSplitViewItem(sidebarWithViewController:) is cut off at the top in fullscreen mode
I forgot to mention that this behaviour only happens when using the .fullSizeContentView window style mask. Without it, the sidebar extends almost to the top of the screen in fullscreen mode. It's still cut off shortly before reaching the top, but at least there's not such a big gap. When moving the mouse to the top of the screen to show the menu bar, the top of the sidebar and content view are hidden, but that's what I would also expect with a full screen content view.
Topic: UI Frameworks SubTopic: AppKit Tags:
Sep ’25