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

AppKit Documentation

Post

Replies

Boosts

Views

Activity

macOS Sonoma: Activate Menubar-Only App When UI Appears
Context I have a Mac app that runs from the status bar. When an NSStatusItem is clicked, I display an NSWindow rather than the standard NSMenu. Problem Before Sonoma, when the NSStatusItem was clicked I used the activate(ignoringOtherApps: true) API that is now deprecated to ensure that my application became the active app. On Sonoma, macOS now shows my window but does not activate the application, which means the user must click on the window before interacting with my UI. It also produces a very jarring experience when the user does click in the window, because the active application finally switches. Worst of all, the problem occurs only about 85% of the time. 15% of the time, the system activates my app when the UI is shown. I cannot nail down a pattern for it yet, but this jives with the AppKit release notes that suggest the system "may" activate my App. (If some stupid, over-engineered, machine-learning gobbldegook thinks it's worth doing, no doubt.) Question What is the solution here? How do I tell the system that my app NEEDS to become active when my NSStatusItem is selected because (A) that's what the user expects and (B) the alternative looks like macOS is broken? Attempts I have tried setting NSApplication.shared.setActivationPolicy() with both .accessory and even .regular (even though that adds a Dock icon and menubar) and the problem persists.
0
1
430
Oct ’23
Programmatically Launch an macOS Action Extension?
Is there a way to programmatically launch a macOS Action Extension (related documentation: https://developer.apple.com/library/archive/documentation/General/Conceptual/ExtensibilityPG/Action.html) I'm aware how to create "Action Extensions" but they only seem to be activated from NSTextView "rollover" button. Say I know there is an action extension that works on a particular type of data can I launch it from my app? Obviously we can launch "regular" apps with NSWorkspace by bundle iD but I was wondering if there is any API where my app could directly launch an action extension as the "host app" programmatically.
1
0
483
Oct ’23
Key equivalent matching for non-Roman layouts
What's the right way to implement key equivalent matching that handles non-Roman/Latin layouts? E.g. pressing Cmd+Option+C in a Greek layout produces an NSEvent with chars="ç" unmodchars="ψ", neither of which is going to match a key equivalent of Cmd+Option+C by simile comparison, yet performKeyEquivalent on a button with that exact key equivalent returns YES and activates the button. How would someone replicate that? [NSEvent charactersByApplyingModifiers:] also reports "ç", and so does UCKeyTranslate. Yet the Keyboard Viewer shows a modifier layer with "c", not the "ç" that the event reports:
0
0
525
Oct ’23
[MacOS] Detecting System Shortcut Keys inside a Swift Application
Hi, Is there a way to detect if a shortcut key is set as a system shortcut. Or list all the assigned system shortcuts in code. I want to have users set custom shortcut keys in my application (for app functionality), but would want to show them a warning that the shortcut is already a system shortcut. For eg, Cmd+Space is a system shortcut for Spotlight search and I wouldn't want the user to set it as a custom shortcut within the App. Thanks
0
1
274
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
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
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
372
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
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
945
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
429
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
507
Oct ’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
392
Oct ’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
[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
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
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
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
484
Sep ’23