Working on a macOS app. I need to display user-added images as a background to the view, with all of:
Tiling (auto repeat in both axes)
Scaling (user-configured scale of the image)
Offset (user-configured offset)
I've been able to achieve scaling and offset with:
Image(nsImage: nsImage)
.scaleEffect(mapImage.scale)
.offset(mapImage.offset)
.frame(width: scaledImageSize.width, height: scaledImageSize.height)
But when I try to incorporate tiling into that with .resizable(resizingMode: .tile) everything breaks.
Is there a way to position the "anchor" of an image, scale it, and tile it in both axes to fill a container view?
AppKit
RSS for tagConstruct and manage a graphical, event-driven user interface for your macOS app using AppKit.
Posts under AppKit tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
You'll have to forgive me, I am still pretty new to Swift, but I'm really struggling to figure out what I'm doing wrong or how I can fix it. I'm working on an app that generates an image from some views and then exports that image, but it always returns this very vague error:
The operation couldn’t be completed. (SwiftUI.FileExportOperation.Error error 0.)
Here's most of the program:
import SwiftUI
import UniformTypeIdentifiers
struct ContentView: View {
@State private var backgroundColor = Color.black
@State private var fileExporterIsPresented = false
@State private var image: NSImage?
@State private var fileExporterErrorAlertIsPresented = false
@State private var fileExporterErrorDescription: String?
var body: some View {
let wallpaper = Rectangle()
.foregroundStyle(backgroundColor)
.aspectRatio(16 / 9, contentMode: .fit)
VStack {
wallpaper
.clipShape(.rect(cornerRadius: 10))
.overlay {
RoundedRectangle(cornerRadius: 10)
.strokeBorder(.separator, lineWidth: 5)
}
ColorPicker("Background Color", selection: $backgroundColor, supportsOpacity: false)
Button("Generate Wallpaper") {
let renderer = ImageRenderer(content: wallpaper.frame(width: 3840, height: 2160))
image = renderer.nsImage
fileExporterIsPresented = true
}
.fileExporter(
isPresented: $fileExporterIsPresented,
item: image,
contentTypes: [UTType.heic, UTType.png]
) { result in
if case .failure(let error) = result {
fileExporterErrorDescription = error.localizedDescription
fileExporterErrorAlertIsPresented = true
}
}
.alert("File Exporter Failure", isPresented: $fileExporterErrorAlertIsPresented, actions: {
Button("OK") {}
}, message: {
if let fileExporterErrorDescription {
Text(fileExporterErrorDescription)
}
})
.dialogSeverity(.critical)
}
.padding()
}
}
#Preview {
ContentView()
}
I have a problem with rulers in an NSTextView. My code has worked fine from about Sierra (10.12), up to Ventura (13), it stopped working in Sonoma and continues to fail in the same way in Sequoia (14 - 15). When I display the ruler, the contents of the text area disappears leaving just a pale grey background. When I make the ruler invisible again the text reappears.
No errors are reported (at compile or run time). I have tried adding refreshes of the text view in various places with no result. I have (for Sequoia) used Interface Builder to force the text view to use TextKit 1, also with no success. I’m at a loss as to how to proceed because I’m not getting any diagnostics, simply changed behaviour.
My app provides a programming IDE. It includes a program editor that uses line numbering code for an NSTextView from WWDC/Noodlesoft. The line numbers are shown in the ruler which is sometimes visible and sometimes not. When I display the ruler, I also set the main text to not editable but removing this setting does not appear to make any difference.
Any suggestions would be very wel
PLATFORM AND VERSION
macOS, Objective C
Development environment: Xcode Version 16.0 (16A242d) [and previously Xcode 15], macOS All releases of Sonoma and Sequoia 15.0.1 (24A348)
Run-time configuration: macOS Sequoia 15.0.1 (24A348)
The sequence is essentially:
[editTextView setEditable:NO];
[self showRulerIn:editTextView visible:YES];
Using:
-(void)showRulerIn:(NSTextView*)editorTv visible:(BOOL)vis {
NSScrollView *scrollV = [editorTv enclosingScrollView];
NSClipView *clipV = [scrollV contentView];
MBEditorTextView *textView = (MBEditorTextView*)[scrollV documentView]; // The actual text
[scrollV setRulersVisible:vis]; // Creates the ruler if necessary
…
return; }
LINE NUMBERING CODE
The line number code comes from 2 sources but they are so similar that one must be derived from the other:
Apple’s WWDC 2010 code at: https://download.developer.apple.com/videos/wwdc_2010__hd/session_114__advanced_cocoa_text_tips_and_tricks.mov
Noodlesoft's code at: https://www.noodlesoft.com/blog/2008/10/05/displaying-line-numbers-with-nstextview/
I'm still discovering swift and the various frameworks. So I'm now trying to create scrolling composition with a grid - containing images - and an NSStackView at on top.
However, I'm running into a problem that might seem stupid, but when I try to wrap my NSCollectionView in another NSView and pointing the scrollView.documentView to, I can't scroll anymore... Even though it works fine when I set the scrollView.documentView to the NSCollectionView directly.
Working case:
override func viewDidLoad() {
super.viewDidLoad()
scrollView = NSScrollView(frame: .zero)
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = false
scrollView.scrollerStyle = .overlay
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
vStack = NSStackView(frame: .zero)
vStack.orientation = .vertical
vStack.spacing = 12 * 2
vStack.translatesAutoresizingMaskIntoConstraints = false
let hStack = NSStackView()
hStack.orientation = .horizontal
hStack.spacing = 12
hStack.translatesAutoresizingMaskIntoConstraints = false
let label1 = NSTextField(labelWithString: "Collection")
hStack.addArrangedSubview(label1)
let layout = PinterestLayout()
layout.delegate = self
collectionView = NSCollectionView(frame: .zero)
collectionView.collectionViewLayout = layout
collectionView.dataSource = self
collectionView.delegate = self
collectionView
.register(
ArtCardCell.self,
forItemWithIdentifier: NSUserInterfaceItemIdentifier("ArtCardCell")
)
collectionView.backgroundColors = [.BG]
collectionView.translatesAutoresizingMaskIntoConstraints = false
// vStack.addArrangedSubview(hStack)
// vStack.addArrangedSubview(collectionView)
scrollView.documentView = collectionView
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
// vStack.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
// vStack.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
// vStack.topAnchor.constraint(equalTo: scrollView.topAnchor),
// vStack.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
// vStack.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
collectionView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
// vStack.arrangedSubviews[0].leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 12),
// vStack.arrangedSubviews[0].trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -12),
// vStack.arrangedSubviews[0].topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 80)
])
collectionView.postsBoundsChangedNotifications = true
NotificationCenter.default.addObserver(self, selector: #selector(didScroll(_:)),
name: NSView.boundsDidChangeNotification,
object: collectionView.enclosingScrollView?.contentView
)
}
collectionView height: 3549.0
ScrollView height: 628.0
StackView height: --
Dysfunctional case:
override func viewDidLoad() {
super.viewDidLoad()
scrollView = NSScrollView(frame: .zero)
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = false
scrollView.scrollerStyle = .overlay
scrollView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(scrollView)
vStack = NSStackView(frame: .zero)
vStack.orientation = .vertical
vStack.spacing = 12 * 2
vStack.translatesAutoresizingMaskIntoConstraints = false
let hStack = NSStackView()
hStack.orientation = .horizontal
hStack.spacing = 12
hStack.translatesAutoresizingMaskIntoConstraints = false
let label1 = NSTextField(labelWithString: "Collection")
hStack.addArrangedSubview(label1)
let layout = PinterestLayout()
layout.delegate = self
collectionView = NSCollectionView(frame: .zero)
collectionView.collectionViewLayout = layout
collectionView.dataSource = self
collectionView.delegate = self
collectionView
.register(
ArtCardCell.self,
forItemWithIdentifier: NSUserInterfaceItemIdentifier("ArtCardCell")
)
collectionView.backgroundColors = [.BG]
collectionView.translatesAutoresizingMaskIntoConstraints = false
vStack.addArrangedSubview(hStack)
vStack.addArrangedSubview(collectionView)
scrollView.documentView = vStack
NSLayoutConstraint.activate([
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
scrollView.topAnchor.constraint(equalTo: view.topAnchor),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
vStack.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
vStack.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
vStack.topAnchor.constraint(equalTo: scrollView.topAnchor),
vStack.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
vStack.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
collectionView.widthAnchor.constraint(equalTo: scrollView.widthAnchor),
vStack.arrangedSubviews[0].leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: 12),
vStack.arrangedSubviews[0].trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -12),
vStack.arrangedSubviews[0].topAnchor.constraint(equalTo: scrollView.topAnchor, constant: 80)
])
}
collectionView height: 508.0
ScrollView height: 628.0
StackView height: 628.0
I'm looking at a case where a handler for NSWindowDidBecomeMain gets the NSWindow* from the notification object and verifies that window.isVisible == YES, window.windowNumber > 0 and window.screen != nil. However, window.windowNumber is missing from the array [NSWindow windowNumbersWithOptions: NSWindowNumberListAllSpaces] and from CGWindowListCopyWindowInfo( kCGWindowListOptionOnScreenOnly, kCGNullWindowID ), how can that be?
The window number is in the array returned by CGWindowListCopyWindowInfo( kCGWindowListOptionAll, kCGNullWindowID ).
I'm seeing this issue in macOS 15, maybe 14, but not 13.
I would like to show a nswindow at a position on screen base on height of the nswindow and its content view. I received zero width and height on macOS 15.0 and xCode 16.1 however they were returned correct width and height on previous macOS version.
import Cocoa
import SwiftUI
class AppDelegate: NSObject, NSApplicationDelegate {
private var window: NSWindow!
func applicationDidFinishLaunching(_ aNotification: Notification) {
window = NSWindow(
contentRect: .zero,
styleMask: [.miniaturizable, .closable, .resizable],
backing: .buffered, defer: false)
window.title = "No Storyboard Window"
window.contentView = NSHostingView(rootView: ContentView()) // a swiftui view
window.center()
let windowFrame = window.frame
print("window Frame \(windowFrame)") // print width and height zero here
window.makeKeyAndOrderFront(nil)
}
}
struct ContentView: View {
var body: some View {
VStack {
Image(systemName: "globe")
.imageScale(.large)
.foregroundStyle(.tint)
Text("Hello, world!")
}
.padding()
}
}
I tried window.layoutIfNeeded() after setting contentview but it didn't work
How can I get the frame after setting contentview for nswindow on macOS 15.0?
So I was trying to use an NSArrayController to bind the contents of a property , first I tried using NSDictionary and it worked great, here's what I did:
@interface ViewController : NSViewController
@property IBOutlet ArrayController * tableCities;
@end
...
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
NSString* filePath = @"/tmp/city_test.jpeg";
NSDictionary *obj = @{@"image": [[NSImage alloc] initByReferencingFile:filePath],
@"name": @"NYC",
@"filePath": filePath};
NSDictionary *obj2 = @{@"image": [[NSImage alloc] initByReferencingFile:filePath],
@"name": @"Chicago",
@"filePath": filePath};
NSDictionary *obj3 = @{@"image": [[NSImage alloc] initByReferencingFile:filePath],
@"name": @"Little Rock",
@"filePath": filePath};
[_tableCities addObjects:@[obj, obj2, obj3]];
}
@end
Now for an NSPopUpButton, binding the Controller Key to the ArrayController and the ModelKeyPath to "name" works perfectly and the popupbutton will show the cities as I expected.
But now, instead of using an NSDictionary I wanted to use a custom class for these cities along with an NSMutableArray which holds the objects of this custom class. I'm having some trouble going about this.
Hi,
I have noticed a major uptick in crash reports, ever since I updated my app for macOS Sequoia. All of them have to do with NSOutlineView, and they all have a similar internal API in the crash log, which shows that the issue is something to do with the framework. They all have references to NSConcreteMapTable and _TtCs12_SwiftObject isEqual.
The issue isn't reproducible, but it's reported by many different users, all on macOS15+, and it was never an issue with macOS14 or below, so I'm not sure what to do about it.
Here's a couple of examples of the new crash reports:
Date/Time: 2024-10-29T06:55:19.999Z
Launch Time: 2024-10-29T06:50:08Z
OS Version: Mac OS X 15.0.1 (24A348)
Report Version: 104
Exception Type: SIGTRAP
Exception Codes: TRAP_BRKPT at 0x1a98c9c90
Crashed Thread: 0
Thread 0 Crashed:
0 libswiftCore.dylib 0x00000001a98c9c90 -[_TtCs12_SwiftObject isEqual:] + 240
1 Foundation 0x0000000199ad4e0c probeGC + 408
2 Foundation 0x0000000199b01e6c -[NSConcreteMapTable removeObjectForKey:] + 76
3 AppKit 0x000000019c5966a8 _NSOVFreeRowEntry + 44
4 AppKit 0x000000019c5965c4 _NSOVRecursiveFreeChildrenAndItem + 100
5 AppKit 0x000000019c59649c _NSOVFastRemoveChildRowEntries + 260
6 AppKit 0x000000019c595d40 -[NSOutlineView reloadItem:reloadChildren:] + 1016
7 MyApp 0x0000000104b454fc CJ_CRM.MacCJSidebarViewController.compareContactsDictionariesForPublicGroups() -> () (MacCJSidebarViewController.swift:1611)
8 MyApp 0x0000000104b44518 $s20MyApp26MacCJSidebarViewControllerC27contactsChangedNotificationyySo14NSNotificationCFySo7NSTimerCYbcfU_ (MacCJSidebarViewController.swift:461)
9 MyApp 0x0000000104ba5310 $sSo7NSTimerCIeghg_ABIeyBhy_TR (<compiler-generated>:0)
10 Foundation 0x0000000199b64cfc __NSFireTimer + 100
11 CoreFoundation 0x0000000198988184 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 28
12 CoreFoundation 0x0000000198987e28 __CFRunLoopDoTimer + 1008
13 CoreFoundation 0x0000000198987938 __CFRunLoopDoTimers + 352
14 CoreFoundation 0x000000019896d0f0 __CFRunLoopRun + 1852
15 CoreFoundation 0x000000019896c334 CFRunLoopRunSpecific + 568
16 HIToolbox 0x00000001a3da50cc RunCurrentEventLoopInMode + 288
17 HIToolbox 0x00000001a3daaebc ReceiveNextEventCommon + 632
18 HIToolbox 0x00000001a3dab020 _BlockUntilNextEventMatchingListInModeWithFilter + 72
19 AppKit 0x000000019c4b0a70 _DPSNextEvent + 656
20 AppKit 0x000000019cdd67b8 -[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 684
21 AppKit 0x000000019c4a3b7c -[NSApplication run] + 476
22 AppKit 0x000000019c47a44c NSApplicationMain + 884
23 MyApp 0x0000000104a1e26c main (main.m:24)
24 ??? 0x0000000198504274 0x0 + 0
Another one with a different trigger but same internal API:
Date/Time: 2024-10-29T16:49:12.999Z
Launch Time: 2024-10-29T15:51:27Z
OS Version: Mac OS X 15.1 (24B83)
Report Version: 104
Exception Type: SIGSEGV
Exception Codes: SEGV_MAPERR at 0x4cde11282080
Crashed Thread: 0
Thread 0 Crashed:
0 libswiftCore.dylib 0x00000001a04efa1c isSubclass(swift::TargetMetadata<swift::InProcess> const*, swift::TargetMetadata<swift::InProcess> const*) + 28
1 libswiftCore.dylib 0x00000001a04ef9f8 _swift_class_isSubclass + 12
2 libswiftCore.dylib 0x00000001a04ffa9c -[_TtCs12_SwiftObject isEqual:] + 252
3 Foundation 0x00000001906b4cec probeGC + 408
4 Foundation 0x00000001906b4adc -[NSConcreteMapTable objectForKey:] + 64
5 AppKit 0x00000001930f8eec -[NSOutlineView _rowEntryForItem:requiredRowEntryLoadMask:] + 48
6 AppKit 0x00000001930f8e80 -[NSOutlineView parentForItem:] + 24
7 MyApp 0x0000000100e2faec MyApp.MacCJSidebarViewController.outlineView(_: __C.NSOutlineView, selectionIndexesForProposedSelection: Foundation.IndexSet) -> Foundation.IndexSet (MacCJSidebarViewController.swift:759)
8 MyApp 0x0000000100e30dbc @objc MyApp.MacCJSidebarViewController.outlineView(_: __C.NSOutlineView, selectionIndexesForProposedSelection: Foundation.IndexSet) -> Foundation.IndexSet (<compiler-generated>:0)
9 AppKit 0x000000019324c4e4 -[NSTableView _userSelectableRowIndexesForProposedSelection:userCanAlreadyChangeSelection:] + 288
10 AppKit 0x00000001933176c4 -[NSTableView _userSelectRowIndexes:withNewSelectedRow:] + 140
11 AppKit 0x00000001933175a0 -[NSTableView _userSelectSingleRow:] + 76
12 AppKit 0x0000000193315c8c -[NSTableView mouseDown:] + 2536
13 AppKit 0x0000000193315120 -[NSOutlineView mouseDown:] + 72
14 MyApp 0x0000000100dabb38 -[CustomNSOutlineView mouseDown:] (CustomNSOutlineView.m:180)
15 AppKit 0x000000019320d98c forwardMethod + 248
16 AppKit 0x000000019320d98c forwardMethod + 248
17 AppKit 0x0000000193213518 -[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 3668
18 AppKit 0x000000019319f00c -[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 380
19 AppKit 0x000000019319ecbc -[NSWindow(NSEventRouting) sendEvent:] + 280
20 AppKit 0x00000001939b6bf0 -[NSApplication(NSEventRouting) sendEvent:] + 1652
21 AppKit 0x00000001935c489c -[NSApplication _handleEvent:] + 56
22 AppKit 0x000000019306ab08 -[NSApplication run] + 516
23 AppKit 0x0000000193041364 NSApplicationMain + 884
24 MyApp 0x0000000100d0626c main (main.m:24)
25 ??? 0x000000018f0e4274 0x0 + 0
I just created a Feedback FB15625970. Please let me know if this is a known issue, and/or if there's any ideas out there on how I can do to avoid this. It's causing a lot of instability in my app, that wasn't there before macOS15, so something changed in the internal APIs, and hopefully there's a way to work around it.
Hello,
I have an NSViewRepresentable displaying an NSTextView in SwiftUI.
GeometryReader() { geometry in
ScrollView([.vertical, .horizontal]) {
Representable()
// -18 for vertical scroller
.frame(minWidth: geometry.size.width - 18)
}
}
When I use the vertical scrollbar the mouse click is passed to the Representable and is not registered by the Scroll bar. In the image you can see I tried to use the scroll bar and it highlighted some text instead.
There is a suggestion on stackoverflow to use an overlay. This fixes the scrolling issue, but will then make the Representable uninteractable.
How can I use the horizontal scroll bar here as expected?
I am trying to figure out if AppKit provides any support for Async/Await when presenting ViewControllers.
Typically one has to use a completionHandler that gets called when the viewController is dismissed.
Any way to used Async/Await for achieving the same thing ?
I have an NSMutableArray defined as a property in my ViewController class:
@interface ViewController ()
@property NSMutableArray *tableCities;
@end
When the "Add" button is clicked, a new city is added:
NSString* filePath = @"/tmp/city_test.jpeg";
NSDictionary *obj = @{@"image": [[NSImage alloc] initByReferencingFile:filePath],
@"name": @"testCity",
@"filePath": filePath};
[_tableCities addObject: obj];
Okay, this is fine, it is adding a new element to this NSMutableArray, now what I want is to somehow bind the "name" field of each city to my NSPopUpButton.
So in storyboard I created an NSArrayController and tried to set its "Model Key Path" to my NSMutableArray as shown below:
Then I tried to bind the NSPopUpButton to the NSArrayController as follows:
but it doesn't work either, a city is added but the NSPopUpButton isn't displaying anything, what gives?
In genealogy software, I have an NSView that displays a family tree where each person is in a subview. Before Sequoia, the subviews would draw in the order I add them to the parent NSView. For some reason, Sequoia calls drawRect in reverse order.
For example, a tree with cells for son, father, and mother used to be drawn in that order, but Sequoia draws them as mother, father, and son.
For static cell placement it would not matter, but these trees dynamically adjust as users change data or expand and contract branches from the tree. Drawing them in the wrong order messes up all the logic and many trees are corrupted.
Has the new drawing order been implemented for some reason and can it be changed? Is it documented?
While trying to debug some weird drawing issues under macOS 14, I remembered that there was a comment in the AppKit Release notes related to drawing and NSView.clipsToBounds.
AppKit Release Notes for macOS 14
Under the section titled NSView, the following statement is made:
For applications linked against the macOS 14 SDK, the default value of this property is true. Apps linked against older SDKs default to false. Some classes, like NSClipView, continue to default to true.
Is this statement possibly backwards? From what I can tell, under macOS 14 NSView.clipsToBounds now defaults to false.
I came across this while trying to debug an issue where views that override drawRect with the intent of calling NSFillRect(self.bounds) with a solid color are, sometimes, briefly flickering because self.bounds is NSZeroRect, even though self.frame is not (nor is the dirtyRect).
This seems to be happening when views are added as subviews to a parent view. The subviews, which override drawRect, periodically "miss" a repaint and thus flicker. This seems to happen when views are frequently added or removed, like what happens in a scrolling view that is "recycling" views as they go offscreen. Views that scroll into the viewport are added as subviews and, sometimes, briefly flicker.
Replacing calls to drawRect with wantsUpdateLayer and updateLayer eliminates the flickering, which makes me think something is going astray in drawRect and the various rects you can use.
This is with Xcode 15.4, linking against macOS 14.5 and running on macOS 14.6.1
I want to simulate the pressing of Fn (Globe) + Control + arrow keys combo, but I’m encountering an issue where the Fn modifier seems to be ignored, and the system behaves as if only Control + arrow keys are pressed.
In macOS, the combination of Fn + Right Arrow (key code 124) is treated as End (key code 119), and even that didn’t have expected behavior. Instead of moving the window to the right edge of the screen on Sequoia, it switches to the next space, which is the default behavior for Control + Right Arrow.
Demo:
(I included Fn + Control + C to show that centering the window works for example.)
import SwiftUI
@main
struct LittleKeypressDemo: App {
var body: some Scene {
Window("Keypress Demo", id: "keypress-demo") {
ContentView()
}
.windowStyle(.hiddenTitleBar)
.windowResizability(.contentSize)
.windowBackgroundDragBehavior(.enabled)
}
}
struct ContentView: View {
var body: some View {
VStack(spacing: 20) {
KeyPressButton(icon: "arrowtriangle.right.fill", keyCode: 124)
KeyPressButton(icon: "arrow.down.to.line", keyCode: 119)
KeyPressButton(label: "C", keyCode: 8)
}
.padding()
}
}
struct KeyPressButton: View {
let icon: String?
let label: String?
let keyCode: CGKeyCode
init(icon: String? = nil, label: String? = nil, keyCode: CGKeyCode) {
self.icon = icon
self.label = label
self.keyCode = keyCode
}
var body: some View {
Button(action: { simulateKeyPress(keyCode) }) {
HStack {
Image(systemName: "globe")
Image(systemName: "control")
if let icon = icon {
Image(systemName: icon)
} else if let label = label {
Text(label)
}
}
}
.buttonStyle(.bordered)
.controlSize(.large)
}
}
func simulateKeyPress(_ keyCode: CGKeyCode) {
let fnKey = VirtualKey(keyCode: 63, flags: .maskSecondaryFn)
let controlKey = VirtualKey(keyCode: 59, flags: [.maskControl, .maskSecondaryFn])
let targetKey = VirtualKey(keyCode: keyCode, flags: [.maskControl, .maskSecondaryFn])
[fnKey, controlKey, targetKey].forEach { $0.pressAndRelease() }
}
struct VirtualKey {
let keyCode: CGKeyCode
let flags: CGEventFlags
func pressAndRelease() {
postKeyEvent(keyDown: true)
postKeyEvent(keyDown: false)
}
private func postKeyEvent(keyDown: Bool) {
guard let event = CGEvent(keyboardEventSource: nil, virtualKey: keyCode, keyDown: keyDown) else { return }
event.flags = flags
event.post(tap: .cghidEventTap)
}
}
Expected behavior:
Simulating the key combo Fn + Control + Right Arrow on macOS Sequoia should move the current window to the right half of the screen, instead of switching to the next desktop space.
Questions:
Is CGEventFlags.maskSecondaryFn enough to simulate the Fn key in combination with Control and the arrow keys? Are there alternative approaches or workarounds to correctly simulate this behavior? What’s the obvious thing I missing?
(Btw., window management is completely irrelevant here. I’m specifically asking about simulating these key presses.)
Any insights or suggestions would be greatly appreciated.
Thank you.
My view controller has this property:
@property NSMutableArray *tableCities;
Whenever I press a button a new city object is added to this array, it consists of a dictionary of NSStrings containing the name and state of the city being added.
Now, I have an NSPopUpButton that I'd like to bind to the city name of all cities in this NSMutableArray, how exactly can I achieve this with the Bindings Inspector?
I'm trying to display my images in a tableView, I'm using NSFIleManager and NSDirectoryEnumerator to get all files in the current folder:
NSString *path = @"/Users/eagle/Documents/avatars";
NSFileManager *fileManager = NSFileManager.defaultManager;
NSDirectoryEnumerator *directoryEnum = [fileManager enumeratorAtPath:path];
NSString *file;
while (file = [directoryEnum nextObject])
{
// ...
}
the problem is that this line
file = [directoryEnum nextObject]
always returns nil, what gives?
I already made sure that this folder has no subfolders and contains only images, so what's the problem here?
I have created a progress indicator to simulate some progressing download task in the dock icon. However, I can see the progress bar appearing in the dock icon but it is not getting updated when I invoked the updateProgress() method. Ideally it should have updated it, and I m not able to figure out the reason?
I have creating the same NSProgressIndicator on an NSWindow and it works to update the progress bar with the same code. Anything that I m missing to understand here? Below is the code I m using:
class AppDelegate: NSObject, NSApplicationDelegate {
var progressIndicator: NSProgressIndicator!
let dockTile = NSApp.dockTile
func applicationWillFinishLaunching(_ notification: Notification) {
// Step 1: Create a progress bar (NSProgressIndicator)
progressIndicator = NSProgressIndicator(frame: NSRect(x: 10, y: 10, width: 100, height: 20))
progressIndicator.isIndeterminate = false
progressIndicator.minValue = 0.0
progressIndicator.maxValue = 100.0
progressIndicator.doubleValue = 0.0
progressIndicator.style = .bar
dockTile.contentView = progressIndicator
dockTile.display()
//// Update the progress bar for demonstration
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.updateProgress(50)
}
}
func updateProgress(_ value: Double) {
progressIndicator.doubleValue = value
NSApp.dockTile.display()
}
}
I need to add an accessory view with a text field to an NSAlert. This works as expected but as my app comes in different languages, the alert looks a bit different depending on the language used:
So I wonder how I can make the text field automatically use the full width of the alert window. I tried to call the alert's layout method and then resize the text field but this seems not work in all cases. Any help would be highly appreciated. Thanks!
Which method allows me to apply larger-than-default rounded corners to a macOS window while maintaining the system’s dynamic, contrasting border – similar to what’s seen in the Control Center popup? (Control Center has a corner radius of 16, the default system window is 10.)
While I know how to closely achieve this effect manually for my plain panel, I'd like to leverage the built-in method and get it for free from the OS.
I’ve spent way more time on this problem than I'm willing to admit, and searched extensively, but haven’t found any solution. I’d really appreciate any pointers.
Thank you.
For a Cocoa project I have this table view controller:
@interface TableViewController : NSObject <NSTableViewDataSource, NSTableViewDelegate>
@property (nonatomic, strong) NSMutableArray *numbers;
@property (nonatomic, strong) NSMutableArray *letters;
@end
#import "TableViewController.h"
@implementation TableViewController
- (NSMutableArray *)numbers
{
if (!_numbers)
{
_numbers = [NSMutableArray arrayWithArray:@[@"1", @"2", @"3", @"4", @"5", @"6", @"7", @"8", @"9", @"10"]];
}
return _numbers;
}
- (NSMutableArray *)letters
{
if (!_letters)
{
_letters = [NSMutableArray arrayWithArray: @[@"a", @"b", @"c", @"d", @"e", @"f", @"g", @"h", @"i", @"j"]];
}
return _letters;
}
// NSTableViewDataSource Protocol Method
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView
{
return self.numbers.count;
}
// NSTableViewDelegate Protocol Method
-(NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
{
NSString *identifier = tableColumn.identifier;
NSTableCellView *cell = [tableView makeViewWithIdentifier:identifier owner:self];
if ([identifier isEqualToString:@"numbers"])
{
cell.textField.stringValue = [self.numbers objectAtIndex:row];
}
else
{
cell.textField.stringValue = [self.letters objectAtIndex:row];
}
return cell;
}
In the storyboard I created a NSTableView and set up the connection, after running it I get what I expected:
okay, cool, but I have a question:
why is this working even though I haven't created a NSTableView as a property for my ViewController or for my TableViewController?
Also, there's another problem, now I want to add a button to this window such that, every time I click it, a new item should be added to this table(for now it can be anything)
So I created a button and a method for this and linked the action to the story board:
-(IBAction) addNewNumber:(id)sender
{
[_numbers addObject:@"1234"];
[_letters addObject:@"testing"];
}
Now, every time I click this button I can see that this method is indeed being called and that indeed IT IS adding a new member to these arrays, the thing is, the table is not being updated, what gives? Any advice on how I can fix this behavior?