Construct and manage a graphical, event-driven user interface for your macOS app using AppKit.

AppKit Documentation

Post

Replies

Boosts

Views

Activity

SwiftUI Scene with a single window on macOS
Is it possible to only allow a single window instance on macOS? WindowGroup/DocumentGroup allow the user to create multiple instances of a window. I'd like to only allow one, for an Onboarding sequence. I've checked the Scene documentation - https://developer.apple.com/documentation/swiftui/scene, and it appears the only types conforming to the Scene protocol are WindowGroup, DocumentGroup and Settings. How can I create a single Window in a SwiftUI App? An example use case: struct TutorialScene: Scene {   var body: some Scene { 	// I don't want to allow multiple windows of this Scene! 	WindowGroup { 		TutorialView() 	}	 }
6
0
4.3k
Aug ’20
Can NSTextView work with custom NSTextContentManager implementation? (TextKit2)
I'm trying to implement custom NSTextContentManager and use it with NSTextView, however it seems that NSTextView expect NSTextContentStorage all the time. final class MyTextContentManager: NSTextContentManager { // ... } It's added to layout manager, and NSTextView instance finds it properly: let textContentManager = MyTextContentManager() textContentManager.addTextLayoutManager(textLayoutManager) however, when I use it, I see errors at: [MyTextContentManager textStorage]: unrecognized selector sent to instance 0x600003d84870 the textStorage property is part of NSTextStorageObserving, that is not NSTextContentManager interface. It looks like NSTextView is not ready to work with custom NSTextContentManager. What did I miss?
3
0
2.3k
Sep ’21
Badge label not appearing in Monterey 12.0.1
Using the Lazarus IDE and Free Pascal the following code works in previous macOS versions, but not in Monterey: procedure TForm1.FormActivate(Sender: TObject); begin NSApp := NSApplication.sharedApplication; end; procedure TForm1.Button1Click(Sender: TObject); begin NSApp.dockTile.setBadgeLabel(NSStr('1')); end; Any ideas why it fails in Monterey? There are no related errors in the system console log.
3
0
1k
Dec ’21
-[NSView (un)lockFocus] deprecated, what to use instead?
I am hitting major road blocks in migrating one of my Obj-C-Cocoa applications away from -[NSView (un)lockFocus] and -[NSBitmapImageRep initWithFocusedViewRect:]. In a transcript of a presentation on WWDC2018 I read: With our changes to layer backing, there's a few patterns I want to call out that aren't going to work in macOS 10.14 anymore. If you're using NSView lockFocus and unlockFocus, or trying to access the window's graphics contents directly, there's a better way of doing that. You should just subclass NSView and implement draw rect. ... Of course, we all implemented -[NSView drawRect:] for decades now. The big question is, how can we do incremental (additional, event driven) drawing in our views, without redrawing the whole view hierarchy. This is the use case of -(un)lockFocus, and especially when drawing of the base view is computational expensive. Wo would have thought that people use -(un)lockFocus for regular drawing of the NSView hierarchy. I tried to get away with CALayer, only to find out after two days experimenting with it, that a sublayer can only be drawn if the (expensive) main layer has been drawn before —> dead end road. Now I am going to implement a context dependent -[NSView drawRect:]. Based on a respective instance variable, either of the (expensive) base presentation of the view or the simple additions are drawn. Is it that what Apple meant by … just subclass NSView and implement draw rect? From the point of view of object oriented programming, using switch() in methods to change the behaviour of the object is ugly - to say the least. Any better options? Ugly or not, in any case, I don’t want to redraw the whole view hierarchy only for moving a crosshairs in a diagram. My actual use case is: This application draws into a custom diagram NSView electrochemical measurement curves which may consist of a few thousands up to millions of data points. The diagram view provides a facility for moving crosshairs and other pointing aids over the displayed curves, by dragging/rolling with the mouse or the touch pad, or by moving it point by point with the cursor keys. Diagram generation is computational expensive and it must not occur only because the crosshairs should be moved to the next data point. So for navigating the crosshairs (and other pointing aids), a respective method locks the focus of said view, restores the background from a cache, caches the background below the new position of the crosshairs using -[NSBitmapImageRep initWithFocusedViewRect:], draws the crosshairs and finally unlocks the focus. All this does not work anymore since 10.14.
3
0
1.2k
Jan ’22
Popover from NSToolbarItem in Mac Catalyst app
Hi, Inside a Mac Catalyst app, I need to display a popover starting from an NSToolbarItem contained inside the app toolbar (like the Apple Maps Mac app does, see below image). In order to do that, when I press the button I need to find the toolbar item view and use it as popover anchor. How can I find the view or frame of an NSToolbarItem on Mac Catalyst? A property that could help me is the NSToolbarItem "view" property (NSView), but that property has been marked has unavailable in Mac Catalyst. Any idea? Thank you
3
3
1.5k
Feb ’22
NSTextField changes its text color when users click on it under dark theme
// //  AppDelegate.swift //  HelloCocoa // import Cocoa @main class AppDelegate: NSObject, NSApplicationDelegate {     func applicationDidFinishLaunching(_ aNotification: Notification) {                  let myAlert = NSAlert()         myAlert.messageText = "Alert Title"         let messageAttributedString = NSAttributedString(string: "Hello,world", attributes: [.font : NSFont.systemFont(ofSize: 12, weight: .bold)])         let myTextField = NSTextField(labelWithAttributedString: messageAttributedString)         myTextField.allowsEditingTextAttributes = true         myTextField.isSelectable = true         myAlert.accessoryView = myTextField         myAlert.runModal()     }     func applicationWillTerminate(_ aNotification: Notification) {         // Insert code here to tear down your application     }     func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool {         return true     } } The alert appears like this: but when I clicks on the textfield, the text's color become black: Adding foregroundColor key to attribute dictionary works for me but I really want to know why NSTextfield has such behavior
1
1
832
Jan ’23
A VZMacGraphicsDisplayConfiguration with a large resolution causes macOS Ventura to incorrectly draw its menu bar items.
Filed as rdar://FB11975037 When macOS Ventura is run as a guest OS within the virtualization framework, the main menu bar items will not be displayed correctly if VZMacGraphicsDisplayConfiguration defines a large resolution. The menu bar titles appear to be using the same color as the menu bar itself. When the Appearance is set to Light, the menu bar items are effectively invisible. When the Appearance is set to Dark, the menu bar items are drawn in what looks like a disabled state. This only affects the menu bar item titles on the left-hand side. The date-time and menu bar icons on the right side are always displayed in the correct color. This appears to be a regression in macOS Ventura as this issue is not present in macOS 12 running as a guest. This bug can be easily reproduced using Apple's own Virtualization sample code titled: "Running macOS in a Virtual Machine on Apple Silicon Macs" Steps to reproduce: Follow the sample code instructions for building and installing a VM.bundle. Before running 'macOSVirtualMachineSampleApp', change the VZMacGraphicsDisplayConfiguration to use: width = 5120, height = 2880, ppi = 144. Run 'macOSVirtualMachineSampleApp' and notice that the menu bar titles on the left side of the screen are not correctly drawn in the guest instance. This has been tested on: Host: macOS 13.1 Guest: macOS 13.x (All versions) Hardware: MBP 14" M1 Pro 32GB/2TB Is there anything that can be done to resolve this issue?
4
2
1.4k
Jan ’23
How to hide NSToolbar background when NSHostingController's ScrollView is at the top
In Monterey, when a user was at the top of a ScrollView implemented inside of a NSHostingController's view (that was itself embedded in a window with a NSToolbar), the window's toolbar background would be hidden until the user scrolled from the top. In Ventura, this behavior is different, with the toolbar's background visible all of the time unless a traditional NSScrollView is used (which means no SwiftUI). Is there the ability to change this behavior within SwiftUI some how now?
1
1
605
May ’23
Multiple NSMenu issues in Sonoma
Sonoma beta release notes mention that NSMenu was rewritten from scratch using AppKit, however, it seems like a lot of behavior was removed along the way which breaks applications. I've filed several requests using Feedback Assistant, but none of them were fixed in the 3 following betas. FB12867496: NSMenu no longer receives keyboard events from GetEventDispatcherTarget (there is a workaround) FB12867573: NSMenuItem custom view window is nil FB12887219 : NSMenu performSelector highlightItem doesn't highlight menu item FB12938907: NSMenu not properly updated when adding/removing NSMenuItem I wonder if anyone else has experienced similar problems and can share workarounds for them:
6
2
1.3k
Aug ’23
drawRect broken in Xcode 15/Sonoma
I'm manually placing a subclass of NSView into the parent view using addSubview:positioned:relativeTo. The dirtyRect passed to drawRect: is wildly incorrect. Can folks attempt to reproduce and file bugs? This is awfully close to the release of Sonoma, and I feel like folks with bezier curves (or maybe other drawing code?) in their NSView subclasses are going to experience problems. To reproduce, place a view (I'm using an NSImageView) as a subview within a view. Then, create a subclass of NSView and draw a bezier curve in the drawRect method. Add an instance of this subclass as a subview of your original view. I'm offsetting the x value for clarity. When I build with Xcode 15 and run on Ventura or earlier, I get the correct result. Or, if I build with Xcode 14.3 and run on Sonoma I get the correct result. However, when I build in Xcode 15 and run on the RC build of Sonoma, I get a whacky result. I get something like (origin = (x = -264, y = -146), size = (width = 480, height = 388)) for the dirtyRect in the error case, while the rect is supposed to be (origin = (x = 0, y = 0), size = (width = 48, height = 48)) (I'm basing the frame of the new view on the original image.) Thanks!
4
1
1.8k
Sep ’23
Window updates are broken on Sonoma
Our MacOS application has a single window which is occupied by an NSView-derived view. It's been working for the last ten years or so, but when using the Sonoma beta, window updates are badly broken. We rely on using setNeedsDisplayInRect to redisplay any portions of the view that need to be redisplayed, but no matter how small a rectangle we specify, the entire window is repainted with the background colour before our drawRect implementation is called. We already provide an overload of isOpaque in our view which returns true, and in the past this was effective for suppressing the background fill, but it no longer seems to work (although I can confirm that it is still called along the way). I've attached an image that shows an example of how a sample window looks after resizing (which is correct) and then what it looks like after using setNeedsDisplayInRect to invalidate the region occupied by the button in the centre. I've explicitly set the NSWindow background colour to blue to make it more obvious : Is it still possible to inhibit the background fill? Repainting the entire view for every update is not really an option for us, for performance reasons
6
4
1.8k
Sep ’23
[macOS Sonoma] screencapture CLI no longer includes DPI information
Using the screencapture CLI on macOS Sonoma 14.0 (23A344) results in a 72dpi image file, no matter if it was captured on a retina display or not. For example, using screencapture -i ~/Desktop/test.png in Terminal lets me create a selective screenshot, but the resulting file does not contain any DPI metadata (checked using mdls ~/Desktop/test.png), nor does the image itself have the correct DPI information (should be 144, but it's always 72; checked using Preview.app). I noticed a (new?) flag option, -r, for which the documentation states: -r Do not add screen dpi meta data to captured file. Is that flag somehow automatically set? Setting it myself makes no difference and obviously results in a no-dpi-in-metadata and wrong-dpi-in-image file. The only two ways I got the correct DPI information in a resulting image file was using the default options (forced by -p): screencapture -i -p, and by making the capture go to the clipboard screencapture -i -c. Sadly, I can't use those in my case. Feedback filed: FB13208235 I'd appreciate any pointers, Matthias
4
2
1.4k
Sep ’23
NSTextLayoutManager's enumerateTextSegments parameters documentation
This function on NSTextLayoutManager has the following signature func enumerateTextSegments( in textRange: NSTextRange, type: NSTextLayoutManager.SegmentType, options: NSTextLayoutManager.SegmentOptions = [], using block: (NSTextRange?, CGRect, CGFloat, NSTextContainer) -> Bool ) The documentation here doesn't define what the CGRect and CGFloat passed to block are. However, looking at sample code Using TextKit2 To Interact With Text, they seem to be the frame for the textsegment and baselineposition respectively. But, the textSegmentFrame seems to start at origin.x = 5.0 when text is empty. Is this some starting offset for text segments? I don't seem to be able to find mention of this anywhere.
1
0
612
Oct ’23
Simulate sending key to an NSView on a macOS application
Hello, I am trying to simulate a keystroke inside a macOS application. Here is what i've done: let src = CGEventSource(stateID: CGEventSourceStateID.hidSystemState) let cmd_down = CGEvent(keyboardEventSource: src, virtualKey: 0x38, keyDown: true) let cmd_up = CGEvent(keyboardEventSource: src, virtualKey: 0x38, keyDown: false) cmd_down?.post(tap: .cghidEventTap) cmd_up?.post(tap: .cghidEventTap) macOS is asking me to allow my application on TCC accessibility. This is a global privilege and needs admin rights. And i want to avoid that. Is there an alternative to simulate a key stroke inside my application ? Thanks
2
0
697
Oct ’23
NSImageView with icns file issue on Sonoma
I find NSImageView with icns file does not display color correctly on Sonoma. As the test app shows, on the retina display, if the image view size is 18 or less, the problem happens. On non-retina display, the threshold is 42. The correct colors should be red, yellow, and blue. _imageView1.image = [[NSImage alloc] initWithContentsOfFile:@"/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/AlertStopIcon.icns"]; _imageView2.image = [[NSImage alloc] initWithContentsOfFile:@"/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/Actions.icns"]; _imageView3.image = [[NSImage alloc] initWithContentsOfFile:@"/System/Library/CoreServices/CoreTypes.bundle/Contents/Resources/BookmarkIcon.icns"]; And if put the icns file into xcode project, then change code to _imageView3.image = [NSImage imageNamed:@"BookmarkIcon"]; The problem still exists. Wrong (image view size is small) Correct (image view size is big enough)
3
0
582
Oct ’23
Mouse events on popup menu view seem to be incorrect in Sonoma.
as I open the pop-up menu and move the mouse before that opened, MouseEntered Event and MouseExited Event are called when mouse moved. The following trackingAreas options are inclued in the view in pop-up area. NSTrackingInVisibleRect, NSTrackingMouseEnteredAndExited, NSTrackingMouseMoved, NSTrackingActiveInKeyWindow LocationInWindow of MouseExitedEvent seem to be incorrect. This problems does not occur in the following cases. Do not move the mouse until the popup is fully opened. Left mouse button down on pop-up area. Move the mouse out of the pop-up area. This issue occurs in Sonoma(MacOS14.0) and later. I would like to know if this is a code issue or a bug in the OS Version. AppDelegate.h #import <Cocoa/Cocoa.h> @interface ViewInPopup : NSView { NSString* resultStr; NSUInteger enteredCount; NSPoint lastEnteredPos; NSUInteger exitedCount; NSPoint lastExitedPos; NSUInteger movedCount; NSPoint lastMovedPos; NSTrackingArea* trackingArea; } @end @interface AppDelegate : NSObject <NSApplicationDelegate> { NSMenu* myMenu; ViewInPopup* viewInPopup; } - (IBAction)onClickButton:(id)sender; @end AppDelegate.mm #import "AppDelegate.h" @interface ViewInPopup () - (void)showResult:(NSEvent*)event; @end @implementation ViewInPopup - (id)initWithFrame:(NSRect)frameRect { self = [super initWithFrame:frameRect]; [self setWantsLayer:TRUE]; [[self layer] setBackgroundColor:[NSColor redColor].CGColor]; return self; } - (void)drawRect:(NSRect)dirtyRect { [super drawRect:dirtyRect]; [resultStr drawInRect:[self bounds] withAttributes:nil]; } - (void)updateTrackingAreas { if (trackingArea) { [self removeTrackingArea:trackingArea]; } NSTrackingAreaOptions options = NSTrackingInVisibleRect | NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveInKeyWindow; trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil]; [self addTrackingArea:trackingArea]; [super updateTrackingAreas]; } - (void)mouseEntered:(NSEvent *)event { [self showResult:event]; [super mouseEntered:event]; } - (void)mouseExited:(NSEvent *)event { [self showResult:event]; [super mouseExited:event]; } - (void)mouseMoved:(NSEvent *)event { [self showResult:event]; [super mouseMoved:event]; } - (void)showResult:(NSEvent*)event { NSString* eventTypeStr = @""; switch (event.type) { case NSEventTypeMouseEntered: eventTypeStr = @"Entered"; [[self layer] setBackgroundColor:[NSColor redColor].CGColor]; if (enteredCount >= NSUIntegerMax) { enteredCount = 0; } else { enteredCount++; } lastEnteredPos = event.locationInWindow; break; case NSEventTypeMouseExited: eventTypeStr = @"Exited"; [[self layer] setBackgroundColor:[NSColor blueColor].CGColor]; if (exitedCount >= NSUIntegerMax) { exitedCount = 0; } else { exitedCount++; } lastExitedPos = event.locationInWindow; break; case NSEventTypeMouseMoved: eventTypeStr = @"Moved"; [[self layer] setBackgroundColor:[NSColor greenColor].CGColor]; if (movedCount >= NSUIntegerMax) { movedCount = 0; } else { movedCount++; } lastMovedPos = event.locationInWindow; break; default: return; } resultStr = [NSString stringWithFormat:@"LastEventType:%@\n\nEnteredCount:%ld\nLastEnteredPosition:(%f, %f)\n\nExitedCount:%ld\nLastExitedPosition:(%f %f)\n\nMovedCount:%ld\nLastMovedPosition:(%f, %f)", eventTypeStr, enteredCount, lastEnteredPos.x, lastEnteredPos.y, exitedCount, lastExitedPos.x, lastExitedPos.y, movedCount, lastMovedPos.x, lastMovedPos.y]; [self setNeedsDisplay:YES]; } @end @interface AppDelegate () @property (strong) IBOutlet NSWindow *window; @end @implementation AppDelegate - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { // Insert code here to initialize your application myMenu = [[NSMenu alloc] init]; NSMenuItem* item = [[NSMenuItem alloc] init]; [myMenu addItem:item]; viewInPopup = [[ViewInPopup alloc] initWithFrame:NSMakeRect(0, 0, 300, 300)]; [item setView:viewInPopup]; } - (void)applicationWillTerminate:(NSNotification *)aNotification { // Insert code here to tear down your application } - (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app { return YES; } - (IBAction)onClickButton:(id)sender { [myMenu popUpMenuPositioningItem:nil atLocation:NSZeroPoint inView:(NSView*)sender]; } @end
2
1
1.1k
Oct ’23
NSTextView crash with interaction between inserted .link attribute in text storage and NSSpellChecker
I have been getting crash reports from users of my Mac app on Sonoma 14.0 and 14.1 when typing into an NSTextView subclass. The crash logs I have show involvement of the spell-checking system - NSTestCheckingController, NSSpellChecker, and NSCorrectionPanel. The crash is because of an exception being thrown. The throwing method is either [NSString getParagraphStart:end:contentsEnd:forRange:] or [NSTextStorage ensureAttributesAreFixedInRange:]. I have not yet reproduced the crash. I have tried modifying the reference finding process to simply link every word, via NSStringEnumerationByWords. The text view in question recognizes certain things in the entered text and adds hyperlinks to the text while the user is typing. It re-parses and re-adds the links on every key press (via overriding the didChangeText method), on a background thread. From user reports, I have learned that: The crash only occurs on macOS 14.0 and 14.1, not on previous versions The call stack always involves the spell checker, and sometimes involves adding recognized links to the text storage (the call to DispatchQueue.main.async in the code below) The crash stops happening if the user turns off the system spell checker in System Settings -> Keyboard -> Edit on an Input Source -> Correct Spelling Automatically switch The crash does not happen when there are no links in the text view. Here is the relevant code: extension NSMutableAttributedString { func batchUpdates(_ updates: () -> ()) { self.beginEditing() updates() self.endEditing() } } class MyTextView : NSTextView { func didChangeText() { super.didChangeText() findReferences() } var parseToken: CancelationToken? = nil let parseQueue = DispatchQueue(label: "com.myapp.ref_parser") private func findReferences() { guard let storage = self.textStorage else { return } self.parseToken?.requestCancel() let token = CancelationToken() self.parseToken = token let text = storage.string self.parseQueue.async { if token.cancelRequested { return } let refs = RefParser.findReferences(inText: text, cancelationToken: token) DispatchQueue.main.async { if !token.cancelRequested { storage.batchUpdates { var linkRanges: [NSRange] = [] storage.enumerateAttribute(.link, in: NSRange(location: 0, length: storage.length)) { linkValue, linkRange, stop in if let linkUrl = linkValue as? NSURL { linkRanges.append(linkRange) } } for rng in linkRanges { storage.removeAttribute(.link, range: rng) } for r in refs { storage.addAttribute(.link, value: r.url, range: r.range) } } self.verseParseToken = nil } } } } } I've filed this as FB13306015 if any engineers see this. Can anyone
2
0
730
Oct ’23
macOS 14 - NSAttributedString created from HTML displays as "undefined character" glyphs when certain fonts are used
I allow users to choose a font to use throughout the app, then display text using that font in 3 different ways: As the default body font of an HTML document displayed in a WKWebView. Used to create an NSAttributedString then displayed in an NSTextField. Used as the body font of a very small HTML document (2-3 lines), converted to NSAttributedString, then displayed in an NSTextField. My code has been working fine for years, but starting with the release of Sonoma (macOS 14), any text that is converted from HTML to NSAttributedString displays as all "question marks in boxes" for each character. This happens when certain fonts are used. In particular I've seen it with Calibri, Candara, and SF Pro. Calibri and Candara are Microsoft fonts and I think are distributed with MS Office. SF Pro is an Apple font. There could be others; I haven't done an exhaustive check. What I can tell you is that this has been working fine literally until a couple weeks ago when customers began installing macOS 14. If they go into my app and select a different font (such as Arial or Times New Roman) everything works fine. It is only certain fonts that don't work, and those fonts work when used as the body font of an HTML document in WKWebView and when used as the font for a new NSAttributedString. They just don't work if you make a little HTML document with the font selected as the body font, then convert to NSAttributedString. Here's the code that worked up until macOS 14: NSString *htmlString = @"<!DOCTYPE html>" "<html>" "<head>" "<style>" "body { font-family: 'Candara', serif; font-size: 14px; }" "</style>" "</head>" "<body>" "This won't display right." "</body>" "</html>"; NSData *htmlData = [htmlString dataUsingEncoding:NSUTF8StringEncoding]; NSDictionary *options = @{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)}; NSError *error; NSAttributedString *attributedString = [[NSAttributedString alloc] initWithData:htmlData options:options documentAttributes:nil error:&error]; Note the fallback of "serif" — that doesn't matter. you get all undefined characters and the fallback font is not used. It's as if the renderer really believes the font is usable, but it isn't.
1
0
757
Nov ’23
No proper replacement for LaunchServices functions
Apple deprecated launch service calls like LSCopyAllRoleHandlersForContentType, referring to -[NSWorkspace URLsForApplicationsToOpenContentType:] instead. However all those new NSWorkspace methods do not have the crucial LSRolesMask the launch service calls have. For example, I have code that looks up all alternative shells, and with LSCopyAllRoleHandlersForContentType I could simply provide LSRoleMask.shell to restrict the returned bundle identifiers to shells only. This is not the first time Apple deprecates stuff without a proper replacement and I don't really get it. Every OS update is basically a downgrade. Or is there another way to replicate the old launch service call behavior?
2
1
701
Nov ’23
Why fonts loaded using CoreText (CTFont) behave different than loaded using AppKit (NSFont)?
I tried to load font using CTFontCreateWithFontDescriptor() and it behaves differently than loaded using NSFont(). Let's say the goal is to load font using CoreText that is exactly the same as using AppKit. NSTextField If I use them in NSTextField text offsets and rendering do not match. let familyName = "Helvetica" let fontSize: CGFloat = 30 let string = "Hello, World! gÖ,|#" // Load font using AppKit let font1 = NSFont(name: familyName, size: fontSize)! // Load font using CoreText API let font2 = CTFontCreateWithFontDescriptor(CTFontDescriptorCreateWithAttributes([ kCTFontFamilyNameAttribute: familyName, kCTFontSizeAttribute: fontSize, ] as [CFString : Any] as CFDictionary), 0, nil) as NSFont // Setup text fields let field1 = NSTextField() let field2 = NSTextField() field1.setAsLabel() field2.setAsLabel() field1.font = font1 field2.font = font2 field1.stringValue = string field2.stringValue = string NSAttributedString If I use them in NSAttributedString bounding box height of text is different: let bounds1 = NSAttributedString(string: string, attributes: [ .font: font1 ]).boundingRect(with: .infinity) let bounds2 = NSAttributedString(string: string, attributes: [ .font: font2 ]).boundingRect(with: .infinity) print(bounds1) // Prints: (0.0, -7.0, 252.3486328125, 37.0) print(bounds2) // Prints: (0.0, -7.0, 252.3486328125, 31.0) Investigation I compared fonts, font attributes, traits, feature settings, even binary font tables but I didn't find any difference. It seems like there is something inside that alters behaviour. I found that if I add .usesDeviceMetrics option to NSAttributedString bounds getter, it returns the same result but also completely different frame. let bounds1 = NSAttributedString(string: "Hello, World! gÖ,|#", attributes: [.font: font1]).boundingRect(with: .infinity, options: [.usesDeviceMetrics]) let bounds2 = NSAttributedString(string: "Hello, World! gÖ,|#", attributes: [.font: font2]).boundingRect(with: .infinity, options: [.usesDeviceMetrics]) print(bounds1) // Prints: (2.3583984375, -6.6357421875, 249.9609375, 33.837890625) print(bounds2) // Prints: (2.3583984375, -6.6357421875, 249.9609375, 33.837890625) Question How to load a font using CoreText in a way that NSFont does? Minor question: Why does NSTextField set it's frame origin to -2.0? Just extensions I used in code above: extension CGSize { public static var infinity: Self { .init(width: CGFloat.infinity, height: CGFloat.infinity) } } extension NSTextField { func setAsLabel() { translatesAutoresizingMaskIntoConstraints = false isBezeled = false isBordered = false isEditable = false isSelectable = false drawsBackground = false } }
2
0
742
Nov ’23