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.
AppKit
RSS for tagConstruct and manage a graphical, event-driven user interface for your macOS app using AppKit.
Post
Replies
Boosts
Views
Activity
I'm trying to understand the mechanism by which the Quit Application menu item gets disabled while a modal dialog/alert is up.
Who is responsible for disabling the menu item?
We have a case where in some cases, the Quit Application menu item is not getting disabled even when a modal dialog is up. So I'm trying to figure out where things may be going wrong.
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,
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!
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?
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!
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
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)
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
Is there a way to customize the context menu that pops up when right clicking on a toolbar (or the title bar of the window containing it)?
As of Sonoma, the steps that worked (described here: https://developer.apple.com/forums/thread/21887) up to Ventura no longer work. I'm developing in Objective-C.
In this code sample, the TextDocumentView has a variable set to 5.0. Any idea where this 5.0 number is coming from? It is used internally in other calculations within TextDocumentLayer. While it works, I'm not sure what it signifies, and how to adapt it to our projects? Thanks
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?
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];
...
}
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.
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.
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?
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.
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.
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```
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)
}
}