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

AppKit Documentation

Post

Replies

Boosts

Views

Activity

How to drag an item using NSItemProviderWriting using async
Scenario: The following Swift code uses NSItemProviderWriting to load a file from some data source async (The code actually just uses a for loop to simulate the time it needs to load the file). It returns the file url then. This code is used for drag & drop behavior in a macOS app from an app to another app. As the other app does only support file URLs as drop types, I can't send over the data itself. class AnyFile: NSObject, NSItemProviderWriting { let url: URL init(url: URL) { self.url = url } static var writableTypeIdentifiersForItemProvider: [String] { return [UTType.fileURL.identifier] } func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, Error?) -> Void) -> Progress? { let count = 100000 let progress = Progress(totalUnitCount: Int64(count)) print("a") Task { print("b") for i in 0...100000 { progress.completedUnitCount = Int64(i) print(i) } print("c") completionHandler(url.dataRepresentation, nil) print("d") } print("e") return progress } } Problem: Drag & drop works, but when I start to drag the view (SwiftUI view using .onDrag), the view gets stuck as long as the loop is running. It is not clear to me why this happens as the loop us running inside a task. The console output also shows that progress is returned before the loop as finished. But still, it is stuck until the end of the loop. So the user experience is like not using async and the task. Log output (shortened) a e b 0 ... 100000 c d Actual Question: Why is this Swift code for dragging files not behaving asynchronously even though it uses Task, completionHandler, and async/await constructs? Alternatives tried: I'm not bound to NSItemProviderWriting in particular. I have tried other ways, like Transferable, .draggable(), and NSItemProvider.registerFileRepresentation. But either they won't return a URL, or do not allow async at all. I also tried AppKit instead of SwiftUI with similar issues.
2
0
667
Sep ’23
transparent window can't click through in macos sonoma
i crate a fully transparent NSWindow like this: NSWindowStyleMask styleMask = NSBorderlessWindowMask | NSFullSizeContentViewWindowMask; NSWinod *window = [[BrowserNSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 500, 600) styleMask:styleMask backing:NSBackingStoreBuffered defer:NO]; [window setBackgroundColor:[NSColor clearColor]]; [window setOpaque:NO]; [window setHasShadow:NO]; NSCustomView *view = [[NSCustomView alloc] initWithFrame:NSMakeRect(0, 0, 500, 600) andBrowserWindow:this]; [view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; [view setAutoresizesSubviews: true]; [window.contentView addSubview:view]; and override the NSView drawRect function: - (void)drawRect:(NSRect)rect { [[NSColor clearColor] set]; NSRectFill(rect); NSRectFillUsingOperation(rect, NSCompositingOperationSourceOver); } i call setNeedDisplay:YES to redraw the view. in macos sonoma, i found that when after multiple calls setNeedDisplay:YES, the transparent window can't click through. This feature run correctly in previous versions, like macos 13,
4
0
646
Sep ’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.3k
Sep ’23
Replicate Command-Q in SwiftUI
I'm building a menuBarExtra app for macOS, and I want to make a Quit menu available from a sub menu in the menuBarExtra, because the main window may be closed. When I try to add .keyboardShorcut("q") to the Button within Menu{}, the shortcut doesn't display, presumably because it's taken by the Quit menu item in the Application Menu. Any way to tell SwiftUI that they're doing the same thing so it will share the keyboard shortcut?
1
0
410
Sep ’23
Changing the mouse cursor over a frontmost view of a non-active application
Our application is a login item which runs inactive in background, and in some cases, it shows its popovers in NSModalPanelWindowLevel over a window of an (unrelated) active application. That works well and without a glitch for years. Now we'd like to change the mouse cursor when the mouse is over some subviews of our popover. Is there a way to do that? I've tried essentially all the cursor-related APIs I know of, from the most obvious cursorRects through trackingAreas up to the low-level explicit NSCursor.push/set, but whatever I do, looks like macOS simply ignores it and keeps showing the arrow default cursor, even though the mouse is over our window whose views have proper cursorRects or explicitly call NSCursor.push/set etc. Is there a trick to change the cursor in this case? Thanks!
2
0
483
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
4
4
1.4k
Sep ’23
Issues making a fullscreen & always on top Window
I'm making a menu bar app that has a timer, and when a timer expires I wanna show a fullscreen popup / window that goes above all other windows, and stays on top even if the user changes desktop via the "three finger swipe" gesture for example. This is my current code: class ZbBreakWindowController: NSWindowController { convenience init() { guard let screenFrame = NSScreen.main?.frame else { fatalError("Failed to obtain the main screen's frame") } let window = ZbBreakWindow( contentRect: screenFrame, styleMask: [.borderless], backing: .buffered, defer: false ) window.collectionBehavior = [.fullScreenPrimary] window.contentView = NSHostingView(rootView: ZbBreakWindowView()) window.level = .floating window.center() self.init(window: window) } } struct ZbBreakWindowView: View { var body: some View { Text("It works!") .frame(maxWidth: .infinity, maxHeight: .infinity) } } This has two issues right now: the window or content view height is not fullscreen, it's missing the menu bar height I can use the swipe gesture to change desktop and the window does not stay on top How should I go about this? The window will have buttons to dismiss it of course, I'm just making a break timer kinda like (https://breaktimer.app/#download)
2
0
264
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.2k
Sep ’23
NSOpenPanel Ignores treatsFilePackagesAsDirectories for Framework UTType
Given the below setup for NSOpenPanel, treatsFilePackagesAsDirectories = false is ignored when using the updated allowedContentTypes property with UTType.framework: let openPanel = NSOpenPanel(); openPanel.canChooseFiles = true; openPanel.canChooseDirectories = false; openPanel.allowsMultipleSelection = false; openPanel.treatsFilePackagesAsDirectories = false; openPanel.message = "Select a framework for import..."; // deprecated, but works openPanel.allowedFileTypes = ["framework"]; // not deprecated, but doesn't work openPanel.allowedContentTypes = [.framework]; openPanel.begin(completionHandler: { guard $0 == .OK, let url = openPanel.url else { return } self.frameworkPath = url.path(); }); Using the deprecated allowedFileTypes property with a value of "framework" produces an NSOpenPanel which respects the treatsFilePackagesAsDirectories property. I'm seting this behavior in both Ventura and Sonoma. Is there something I'm missing?
0
0
234
Sep ’23
AppKit does not allow directory to be selected
I have a UTI for "public.directory" and can drag-drop folders onto my app and open them. I also added this to the Info.plist to say the app supported directoryies. But the default "Open" command seems to popup up an NSOpenPanel with folders not selectable. The "Open" button stays disabled. How do I change this? I tried implementing "openDocument", but then it lets through any file type, not just the ones in my Info.plist. So I'd like to just use the default implementation, but need an override for the NSOpenPanel. (IBAction)openDocument:(id)sender { NSOpenPanel *panel = [NSOpenPanel openPanel]; [panel setCanChooseFiles:YES]; [panel setCanChooseDirectories:YES]; [panel setAllowsMultipleSelection:NO]; ... }
1
0
389
Oct ’23
Why was NSAttributedString.Key.verticalGlyphForm Deprecated in macOS 14, and How to Handle Vertical Text Now?
In macOS 14, NSAttributedString.Key.verticalGlyphForm has been deprecated. This key was previously used for rendering text vertically, particularly in languages like Chinese, Japanese, and Korean. I'm curious about the reasons behind its deprecation and would appreciate insights into alternative methods for displaying vertical text.
1
0
503
Oct ’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
428
Oct ’23
NSView blurry in Sonoma, in app and Xcode 15
I have a non-shipping internal test app which is macOS only. It uses AppKit and .xib files to describe the UI. On Sonoma, the app renders with most of its UI quite blurry, as if a 10 pixel Gaussian blur were applied to it. The blur is applied to entire views, not just the text. It doesn't vary with screen resolution. I observed this behavior with one of the Sonoma betas but I think it went away when I re-launched the app - at any rate, I forgot about it. I've updated my dev machine to the shipping Sonoma and the problem is extant. I opened up the .xib file in Xcode and the blurriness is visible there too. I haven't applied any effect layers to my UI. Not all of the views in my UI are blurry. Has anyone else seen this?
3
0
943
Oct ’23
"Customize Toolbar" on NSToolbar Causes Autolayout Constraints Violation on macOS Sonoma
I have a customizable NSToolbar (using in a Mac Catalyst app "optimized for Mac"). When I right click and choose "Customize toolbar" I get the following error: Conflicting constraints detected: ( "<NSLayoutConstraint:0x6000014a24e0 NSToolbarItemGroupView:0x13de568c0.width <= 88.5 (active)>", "<NSAutoresizingMaskLayoutConstraint:0x6000014f5f90 h=--& v=--& NSToolbarItemGroupView:0x13de568c0.width == 89 (active)>" ). Will attempt to recover by breaking <NSLayoutConstraint:0x6000014a24e0 NSToolbarItemGroupView:0x13de568c0.width <= 88.5 (active)>. Unable to simultaneously satisfy constraints: ( "<NSLayoutConstraint:0x6000014a24e0 NSToolbarItemGroupView:0x13de568c0.width <= 88.5 (active)>", "<NSAutoresizingMaskLayoutConstraint:0x6000014f5f90 h=--& v=--& NSToolbarItemGroupView:0x13de568c0.width == 89 (active)>" ) Will attempt to recover by breaking constraint <NSLayoutConstraint:0x6000014a24e0 NSToolbarItemGroupView:0x13de568c0.width <= 88.5 (active)> Set the NSUserDefault >NSConstraintBasedLayoutVisualizeMutuallyExclusiveConstraints to YES to have ->[NSWindow visualizeConstraints:] automatically called when this happens. And/or, set a symbolic breakpoint on LAYOUT_CONSTRAINTS_NOT_SATISFIABLE to catch this in the debugger.
1
0
409
Oct ’23
Insert/Overwrite Mode in MacOS/NSTextField
Hi, Does MacOS support the "Insert" key (Overwrite mode) in general and in an NSTextField? There are Articles that say this can be done using "Fn + Enter", "Fn + i" or "Shift + 0" but I'm unable to trigger the same https://discussions.apple.com/thread/8457698 https://discussions.apple.com/thread/5469511 Plugging in a Keyboard with a physical 'Insert' key also does nothing.
1
0
369
Oct ’23
Crash expanding save panel
Full crash log Running on an M1-based iMac, macOS 13.6, if I trigger a save panel, I get a crash in com.apple.appkit.xpc.openAndSavePanelService if I expand the panel with the button next to the folder selection popup button (shrinking works fine). Since this is not code that I control, what can I do? Here is the first part of the crash info: Crashed Thread: 0 Dispatch queue: com.apple.main-thread Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x00000001a2788728 Termination Reason: Namespace SIGNAL, Code 5 Trace/BPT trap: 5 Terminating Process: exc handler [2915] Application Specific Backtrace 0: 0 CoreFoundation 0x000000019f2fb104 __exceptionPreprocess + 176 1 libobjc.A.dylib 0x000000019ee19fd0 objc_exception_throw + 60 2 CoreFoundation 0x000000019f324350 _CFBundleGetValueForInfoKey + 0 3 ViewBridge 0x00000001a6cae5b0 -[NSViewServiceMarshal addChildWindow:ordered:] + 604 4 ViewBridge 0x00000001a6ca6948 -[NSWindow(ViewBridgeSwizzle) swizzledAddChildWindow:ordered:] + 92 5 AppKit 0x00000001a2e85f4c -[NSWindow(NSLayoutConstraintVisualization) _updateConstraintVisualization] + 272 6 AppKit 0x00000001a2eb3cd4 -[NSView(NSConstraintBasedLayoutInternal) engine:willBreakConstraint:dueToMutuallyExclusiveConstraints:] + 104 7 CoreAutoLayout 0x00000001a6e0ce30 -[NSISEngine handleUnsatisfiableRow:usingInfeasibilityHandlingBehavior:prospectiveRowHead:mutuallyExclusiveConstraints:] + 888```
1
0
310
Oct ’23
Modal NSWindow's behavior changed?
My app use modal window opened by NSApp.runModal(for: NSWindow). This program works in macOS 13, but nothing happens when I press the button(Button("close ModalWindow")) in macOS 14.0 Sonoma. Why is it not working in macOS 14 ? import SwiftUI struct ContentView: View { var body: some View { VStack { Button("runModal") { let window = ModalWindow( contentRect: NSRect(x: 20, y: 20, width: 500, height: 350), styleMask: [.titled, .closable, .miniaturizable, .resizable], backing: .buffered, defer: false) window.isReleasedWhenClosed = false window.title = NSLocalizedString("subView", comment: "") window.contentView = NSHostingView(rootView: SubView()) NSApp.runModal(for: window) } .buttonStyle(.borderedProminent) .tint(.accentColor) } .padding(10) .frame(minWidth: 150, maxWidth: .infinity, minHeight: 60, maxHeight: 60, alignment: .center) } } #Preview { ContentView() } final class ModalWindow: NSWindow { override func becomeKey() { super.becomeKey() level = .modalPanel } override func close() { super.close() NSApp.stopModal() } } struct SubView: View { var body: some View { HStack { Button("close ModalWindow") { NSApplication.shared.keyWindow?.close() } } .padding(10) .frame(minWidth: 150, maxWidth: .infinity, minHeight: 60, maxHeight: 60, alignment: .center) } }
2
0
479
Oct ’23