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

AppKit Documentation

Post

Replies

Boosts

Views

Activity

MouseDown location from MTKView wrapped NSVieRepresentable
Hi Devs, Anyone know how to get the local mouse click position of a UIKit view that is wrapped in a NSViewRepresentable and drawn using SwiftUI. No matter what I do it always returns the entire window view, and I am after the location relative to the MTKView. I am overriding the MTKView's, mouseDown function, and wanting to get the local position from the mouseDown event. using self.convert(event.locationInWindow, to:self), returns the same position as event.locationInWindow The reason I need the local position inside the MTKView, is I will be sampling an idBuffer at that point. Any help would be greatly appreciated, Thanks Simon
1
0
471
Oct ’23
Is "responsive scrolling" still a thing in modern macOS?
I started wondering after I saw jerky scrolling in my app when it draws a lot of curves (NSBezierPath), under Sonoma. So I made a simple Cocoa app, using the Xcode 15 objC template. The app only has a NSView subclass as a document view of an NSScrollView (not a subclass), which has copiesOnScroll set to YES. The document view returns YES to isOpaque and its class returns YES to isCompatibleWithResponsiveScrolling. Yet whenever I scroll, -drawRect is called on the document view and the dirtyRect passed is the same as its visibleRect. i.e., the view is asked to redraw its whole visible content at every scroll step. Clearly, responsive scrolling isn't working. I tried setting wantsLayer to YES or NO, it doesn't change anything. prepareContentInRect is called, but it doesn't seem that the rect argument covers a region of the view that is not visible. Am I doing something wrong or is responsive scrolling a thing of the past?
3
2
681
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
891
Oct ’23
NSSavePanel: „[NSPathStore2 stringByAppendingPathExtension:]: nil argument“
Hey, I‘m building a proven document-based app with Xcode 15 / macOS 14 SDK with a deployment target of macOS 10.13. After some adjustment due to unclipped views and state restoration, everything works fine under Sonoma. But on older systems (e.g. macOS 10.14) invoking an NSSavePanel directly throws an exception: 1: "*** -[NSPathStore2 stringByAppendingPathExtension:]: nil argument I‘m not explicitly fiddling with the path extension, and the code works - as mentioned - under some (old and new) macOS versions. The macOS 15 AppKit release notes are listing some changes to NSSavePanel, maybe the issue is related… Has anyone made similar observations - and knows a potential fix? Greetings, Mattes
1
0
460
Oct ’23
Changing mouse cursor with NSCursor.push() or .set() is soon replaced by arrow cursor again
I noticed an issue in macOS 14 which I didn't have on macOS 13. I used to be able to set a custom mouse cursor when it moves over a certain view area in my app, but now it's regularly reset to the standard arrow cursor. This is easily reproduced with the following code. When I move the mouse in and out of the red rectangle. When moving in, the cursor should become a hand, and when moving out an arrow again. It seems that particularly when moving the mouse to the right of the red rectangle it quickly gets reset to the arrow cursor, while moving the mouse on the left side it often stays a hand. Even uncommenting the line with cursor?.set() makes the mouse cursor flicker between arrow and hand. Is this a known bug or am I doing something wrong? class ViewController: NSViewController { var cursor: NSCursor? let subframe = CGRect(x: 100, y: 100, width: 300, height: 100) override func loadView() { let subview = NSView(frame: subframe) subview.wantsLayer = true subview.layer!.backgroundColor = NSColor.red.cgColor view = NSView(frame: CGRect(x: 0, y: 0, width: 500, height: 300)) view.addSubview(subview) view.addTrackingArea(NSTrackingArea(rect: .zero, options: [.activeInKeyWindow, .inVisibleRect, .cursorUpdate, .mouseMoved], owner: self)) } override func mouseMoved(with event: NSEvent) { if subframe.contains(view.convert(event.locationInWindow, from: nil)) { if cursor == nil { cursor = .openHand cursor!.push() print("set cursor") } } else if let cursor = cursor { cursor.pop() self.cursor = nil print("unset cursor") } // cursor?.set() } }
2
0
579
Oct ’23
MacOS Sonoma, NSCollectionView item clipping on when scrolled to the boundry of the clipView
Given I have an NSCollectionView, in one of the view the same collection view has multiple section, and in another view It has only one section, in the view that has one section, When the collection view is scrolled the the cell that overlaps the clipview bounds (both in top and bottom ) will reduce its size Note: This build is generated from xcode 14.2 and is shared into an Sonoma 14.0 machine, It is not observed in other OS, and the same issue is not observed while running the build from xcode Any insight similar to this issue would be appreciated
0
0
244
Oct ’23
Delete / Delete Forward key on Sonoma -- broken?
Something has happened to our users that are running MacOS Sonoma: our app's main window (NSView ) is no longer getting the NSResponder deleteBackward "bindable command" message when the user presses the DELETE key, and is connected to an Apple Extended Keyboard. (it DOES work on a laptop, however) Similarly, laptops that have updated to MacOS Sonoma no longer send the previously-accepted unicode key code for the FORWARD DELETE key: "\u007F". Both these keys worked PERFECTLY on all earlier versions of MacOS (Mojave 10.14 through Ventura 13.x). Any insights?
3
0
539
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
459
Oct ’23
keyboard navigation broken after use accessibilityRepresentation
Example code: struct ContentView: View { @State var isSelected = false var body: some View { VStack { Button("Button1") { } Button(action: { }, label: { Image(systemName: "checkmark.square") }) .accessibilityRepresentation { Toggle("", isOn: $isSelected) } Button("Button3") { } } .padding() } } There are three buttons in the view, the middle button I want to custom Toggle and using accessibilityRepresentation replace accessibility elements. But using keyboard navigation (System settings -> Keyboard -> Keyboard navigation) VocieOver can't read the middle button. (VoiceOver key can read it) If not use accessibilityRepresentation, the keyboard navigation works How to make keyboard navigation read the accessibilityRepresentation elements?
2
0
381
Oct ’23
wkWebview default drag crashing on login window
I am  working on  a macOS plugin application that replaces the default macOS login process and runs during login. However, I'm encountering a crash issue when a drag session is initiated inside a WKWebView component within my application. I have added the  part of crash log below . It's worth noting that I haven't implemented any custom drag protocols, so the default dragging method is the only one in use. Interestingly, this problem doesn't occur when I implemented the same WKWebView setup  in an app that runs at macOS Desktop environment (environment in which all regular apps run) . I would greatly appreciate it if someone could provide insights into the underlying causes of this behaviour. It would not only assist in resolving the issue but also contribute to a deeper understanding of the OSX system.      *******——  Crash Log    ——  ********   Process:             MyAppHelper-arm64 [6128] Path:                  /System/Library/Frameworks/Security.framework/Versions/A/MachServices/MyApp.bundle/Contents/XPCServices/MyAppHelper-arm64.xpc/Contents/MacOS/MyAppHelper-arm64 Identifier:            com.apple.MyAppHelper.arm64 Code Type:             ARM-64 (Native) Parent Process:        launchd [1] Responsible:          MyApp [6120] User ID:               92   Date/Time:             2023-10-05 10:21:03.6146 +0530 OS Version:            macOS 14.0 (23A344) Report Version:        12   Time Awake Since Boot: 5900 seconds Time Since Wake:       1053 seconds   System Integrity Protection: enabled   Crashed Thread:        0  Dispatch queue: com.apple.main-thread   Exception Type:        EXC_CRASH (SIGABRT) Exception Codes:       0x0000000000000000, 0x0000000000000000   Termination Reason:    Namespace SIGNAL, Code 6 Abort trap: 6 Terminating Process:   MyAppHel [6128]   Application Specific Information: abort() called     Thread 0 Crashed::  Dispatch queue: com.apple.main-thread 0   libsystem_kernel.dylib                0x1840fb11c __pthread_kill + 8 1   libsystem_pthread.dylib               0x184132cc0 pthread_kill + 288 2   libsystem_c.dylib                     0x184042a50 abort + 180 3   libc++abi.dylib                       0x1840ea6d8 abort_message + 132 4   libc++abi.dylib                       0x1840da7c8 demangling_terminate_handler() + 348 5   libobjc.A.dylib                       0x183d87894 _objc_terminate() + 144 6   libc++abi.dylib                       0x1840e9a9c std::__terminate(void ()()) + 16 7   libc++abi.dylib                       0x1840eca48 __cxxabiv1::failed_throw(__cxxabiv1::__cxa_exception) + 36 8   libc++abi.dylib                       0x1840ec9f4 __cxa_throw + 140 9   libobjc.A.dylib                       0x183d7e01c objc_exception_throw + 420 10  CoreFoundation                        0x1842a9bac -[NSException raise] + 16 11  AppKit                                0x187c741f8 -[NSDraggingSession(NSInternal) _initWithPasteboard:image:offset:source:] + 624 12  AppKit                                0x187c73c88 -[NSCoreDragManager dragImage:fromWindow:at:offset:event:pasteboard:source:slideBack:] + 996 13  WebKit                                0x1a6f6775c WebKit::WebViewImpl::startDrag(WebCore::DragItem const&, WebKit::ShareableBitmapHandle&&) + 620 14  WebKit                                0x1a73c2e48 WebKit::WebPageProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 27068 15  WebKit                                0x1a7484aa4 IPC::MessageReceiverMap::dispatchMessage(IPC::Connection&, IPC::Decoder&) + 264 16  WebKit                                0x1a709185c WebKit::WebProcessProxy::didReceiveMessage(IPC::Connection&, IPC::Decoder&) + 40 17  WebKit                                0x1a74800e4 IPC::Connection::dispatchMessage(std::__1::unique_ptr<IPC::Decoder, std::__1::default_deleteIPC::Decoder>) + 332 18  WebKit                                0x1a74805cc IPC::Connection::dispatchIncomingMessages() + 292 19  JavaScriptCore                        0x19fe0820c ***::RunLoop::performWork() + 204 20  JavaScriptCore                        0x19fe090dc ***::RunLoop::performWork(void) + 36 21  CoreFoundation                        0x18420fd28 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 28 22  CoreFoundation                        0x18420fcbc __CFRunLoopDoSource0 + 176 23  CoreFoundation                        0x18420fa2c __CFRunLoopDoSources0 + 244 24  CoreFoundation                        0x18420e61c __CFRunLoopRun + 828 25  CoreFoundation                        0x18420dc2c CFRunLoopRunSpecific + 608 26  HIToolbox                             0x18e766448 RunCurrentEventLoopInMode + 292 27  HIToolbox                             0x18e766284 ReceiveNextEventCommon + 648 28  HIToolbox                             0x18e765fdc _BlockUntilNextEventMatchingListInModeWithFilter + 76 29  AppKit                                0x1879e8f90 _DPSNextEvent + 660 30  AppKit                                0x1881bcb94 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 716 31  AppKit                                0x1879dc43c -[NSApplication run] + 476 32  AppKit                                0x1879b3708 NSApplicationMain + 880 33  MyAppHelper-arm64             0x102d6bb2c main + 388 34  dyld                                  0x183db9058 start + 2224
0
0
178
Oct ’23
Show custom AboutWindow - NSStatusItem only application
Hi! My application lives as icon in the systemStatusBar, but no Menubar (The user never see "App Name" "File" "Edit" ...) . The icon has a menu. One of its items is "About". The action linked to the item loads a custom NSWindowController and send showWindow:nil. In order to focus the window, the mesage [[NSApplication sharedApplication] activateIgnoringOtherApps:YES] is sent. This method is deprecated for macOS 14.0 upward. The message [[NSApplication sharedApplication] activate] does not activate the application and the window is in front, but not focused, which is slightly disturbing. What option are there, for such a simple thing as the AboutWindow. The standard AboutDialog is not an option! Thanks in advance
1
0
235
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
547
Oct ’23
Unable to move window on Sonoma
Hi, Updating a macOS application from Ventura to Sonoma, I encountered some issues, especially related to the new default value of -clipsToBounds (NO instead of YES previously), so that I had to add explicit definitions of this method in all my class views. All these problems are fixed now, except for one that I can't solve and that may or may not be related: The main window of this application has a toolbar containing a few custom views and using the NSWindowToolbarStyleExpanded style. In Sonoma, I can no longer move the window by clicking and dragging, even when I click on the title bar, and despite the fact that all my custom views inside this toolbar now have their -clipsToBounds method returning YES. -isMovable however returns YES, -isMovableyWindowBackground returns NO, and the window receives the events. But -mouseDown: is only called when the window can't be moved, which seems to mean that the event wasn't properly caught somewhere. Curiously, If I put the style to NSWindowToolbarStyleAutomatic, I can move the window again, but only by clicking on the left part (where is displayed the title and the following empty space). Does anybody encountered such an issue on Sonoma ? Or have an idea to fix or work around this issue ? Any help or advice is welcome, thank you!
1
0
581
Oct ’23
NSRunningApplication activateWithOptions does not work on Sonoma
Hello, Our application uses following code to activate itself: void BecomeFrontMostApp() { @autoreleasepool { if ([NSApp isActive] == YES) return; [[NSRunningApplication currentApplication] activateWithOptions: NSApplicationActivateIgnoringOtherApps | NSApplicationActivateAllWindows ]; } } Code works on Ventura and previous OS versions but not on Sonoma. On Sonoma application does not come to foreground but instead dock icon starts jumping same way when calling: [NSApp requestUserAttention: NSCriticalRequest]; And activateWithOptions returns false. I checked activationPolicy on the app running on Sonoma - it is NSApplicationActivationPolicyRegular Any ideas how to fix this appreciated.
2
0
465
Oct ’23
Strange Overlay with NSWorkspace.shared.icon(forFile: )
I am currently experiencing strange behavior when determining icons for files. When I determine icons using let icon = NSWorkspace.shared.icon(forFile: path) it generally works fine. However, for some files, a "denied" symbol appears as an overlay. When I look at the corresponding icon in the debugger, a Decorated-Icon with the decoration "com.apple.icon-decoration.system.unsupported" is determined. In Finder, Dock, or other programs, the symbol is displayed correctly. In the case mentioned, it is a website that has been converted into an app using the "Unite" application. Why is NSWorkspace.shared.icon(forFile: path) determining this overlay and is there a way to get the "normal" icon?
1
0
271
Oct ’23
Safari MacOS 14 Sonoma Consumes Global Key Events + Does Not Yield Activation
Context I am developing a small tool which is a small terminal to perform AI prompts which you should be able to quickly invoke upon a key press (https://swiftprompt.ai). This is how I try to bring up the application and obtain focus. if #available(macOS 14.0, *) { NSApplication.shared.activate() } else { NSApplication.shared.activate(ignoringOtherApps: true) } promptWindow.makeKeyAndOrderFront(self) I also use `NSEvent.addGlobalMonitorForEvents(..) to support specific shortcuts to trigger certain functionality. The Problem Since MacOS 14, I noticed sometimes issues with activating and obtaining focus for the window. Also shortcuts using letter keys are not recognized. I noticed when Safari is running while my application is launching, it will not be able to get global key events nor retain focus when Safari is active. As soon as Safari is closed everything works. Also if Safari is not running while launching my application everything works perfectly, even if Safari is opened after launching my application. This is a problem for me, as users of my application should be able to do one keypress and start writing without having to additionally having to click on the window to focus it. I expect many users having Safari open and running. I tried other shortcut libraries like (HotKey) for which I am getting the same issues. Is anyone running into similar issues or can reproduce this problem? I would appreciate any help. Cheers, Mo
0
0
326
Oct ’23
API for detecting whether certain gestures are enabled?
G'day folks, If you've got a trackpad on your Mac, you can enabled and disable the zoom/rotation/etc. gestures in System Settings. I think you can also do this if you have a Magic Mouse. My question is: is there any API for determining if the user has done this? If I add an NSMagnificationGestureRecognizer, is there a way to know if it's even possible for it to be triggered? I know, I know – the standard answer – don't give the user one way of doing a thing if that one way is a gesture. Add zoom in and out buttons like Maps does. But I'm talking about a game, and the default set of controls should be different for different input mechanisms. Think about a sim game: if you're using a standard mouse, then scroll wheel should be zoom, that's what the player expects - but if you're using a trackpad, zoom should be zoom and two-finger pan should move you around the map. With a mouse, the player probably expects that to be bound to right-click-and-drag, or middle-click-and-drag – gestures that are difficult or impossible to perform on a trackpad. I feel like the ability to interrogate this is pretty central to the whole "do something sensible by default" at the heart of the Mac HIG.
0
0
200
Oct ’23
Is there a way to determine if the mouse and cursor are currently dissociated using CGAssociateMouseAndMouseCursorPosition?
This status is essential for generating simulated CGEvents. Games often use this API to implement cursor lock. If we send CGEvents with a moving position, it's possible for the cursor to move outside the game window and cause the game window to become inactive. If we don't send CGEvents with updated positions, we can only control the mouse within the game but not in other windows or the desktop.
0
0
388
Oct ’23