I’m building a macOS document based app using SwiftUI’s DocumentGroup API. By default, when a document based app launches, macOS automatically shows a file open panel or creates a new untitled document window.
However, I want to suppress this default behavior and instead show a custom welcome window when the app starts — something similar to how Xcode or Final Cut Pro shows a “Welcome” or “Start Project” screen first.
So basically, when the user opens the app normally, it should not open the document selector or create a document automatically. Instead, it should show my custom SwiftUI or AppKit window. Here is my Code :-
//MyApp.swift
import SwiftUI
import AppKit
@main
struct PhiaApp: App {
@NSApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
DocumentGroup(newDocument: MyDocumentModel()) { file in
EditorView(document: file.document, filePath: file.fileURL)
}
Settings { EmptyView() }
}
}
Current I have this code setup for my MainApp.swift, where I am using the AppDelegate to create a custom recording window using appkit and also defining the DocumentGroup to handle the custom .myapp file opens. However, when I launch the app, its showing my appkit window as well as the macOs native file Selector to select the file I want to open.
I want when the user opens the app normally, it should not open the document selector or create a document automatically. Instead, it should show my custom SwiftUI or AppKit window. However, the app should still fully support opening .myapp documents by double clicking from Finder, using the standard File → Open and File → New menu options, also having multiple document windows open at once.
This is my AppDelegate.swift file :-
import AppKit
import SwiftUI
class AppDelegate: NSObject, NSApplicationDelegate {
var panel: Panel?
private var statusItem: NSStatusItem?
func applicationDidFinishLaunching(_ notification: Notification) {
showWindow()
}
// MARK: - Window control
func showWindow() {
if panel == nil {
let root = RecordingViewMain()
let newPanel = Panel(rootView: root)
if let screen = NSScreen.main {
let size = NSSize(width: 360, height: 240)
let origin = NSPoint(
x: screen.visibleFrame.midX - size.width / 2,
y: screen.visibleFrame.midY - size.height / 2
)
newPanel.setFrame(NSRect(origin: origin, size: size), display: true)
}
panel = newPanel
}
panel?.makeKeyAndOrderFront(nil)
}
func hideWindow() {
panel?.orderOut(nil)
}
@objc private func showPanelAction() {
showWindow()
}
@objc private func quitAction() {
NSApp.terminate(nil)
}
}
AppKit
RSS for tagConstruct and manage a graphical, event-driven user interface for your macOS app using AppKit.
Posts under AppKit tag
189 Posts
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
My app has the following UI layout:
NSSplitViewController as the windows contentViewController
NSPageController in the content (right) split item
NSTabViewController as the root items of the NSPageController
NSViewController with a collection view in the first tab of that NSTabViewController
The collection view is using a NSCollectionViewCompositionalLayout in which the sections are set up to have a header using NSCollectionLayoutBoundarySupplementaryItem with pinToVisibleBounds=true and alignment=top
With macOS 26, the pinned supplementary item automatically gets a blurred/semi-transparent background that seamlessly integrates with the toolbar. When the window's title bar has a NSTitlebarAccessoryViewController added, the said semi-transparent background gets a bottom hard edge and a hairline to provide more visual separation from the main content.
During runtime, my NSPageController transitions from the NSTabViewController to another view controller. When transitioning back, the semi-transparent blur bleeds into the entire section. This happens no matter if there's a NSTitlebarAccessoryViewController added or not.
It doesn't happen 100% of the cases, it seems to depend on section size, header visibility and/or scroll position. But it happens more often than not.
Most of the time, a second or so after the back transition - shortly after pageControllerDidEndLiveTransition: of the NSPageControllerDelegate is called - the view updates and the supplementary views are back to normal.
Sometimes, the issue also appears not when transitioning using NSPageController, but simply by scrolling through the collection view.
Anyone has an idea what is happening here? Below are two screenshots of both the "ok" and "not ok" state
I'm on macOS 26.0.1 and I'm using XCode 26.0.1
Hello, I am trying to capture screen recording ( output.mp4 ) using ScreenCaptureKit and also the mouse positions during the recording ( mouse.json ). The recording and the mouse positions ( tracked based on mouse movements events only ) needs to be perfectly synced in order to add effects in post editing.
I started off by using the await stream?.startCapture() and after that starting my mouse tracking function :-
try await captureEngine.startCapture(configuration: config, filter: filter, recordingOutput: recordingOutput)
let captureStartTime = Date()
mouseTracker?.startTracking(with: captureStartTime)
But every time I tested, there is a clear inconsistency in sync between the recorded video and the recorded mouse positions.
The only thing I want is to know when exactly does the recording "actually" started so that I can start the mouse capture at that same time, and thus I tried using the Delegates, but being able to set them up perfectly.
import Foundation
import AVFAudio
import ScreenCaptureKit
import OSLog
import Combine
class CaptureEngine: NSObject, @unchecked Sendable {
private let logger = Logger()
private(set) var stream: SCStream?
private var streamOutput: CaptureEngineStreamOutput?
private var recordingOutput: SCRecordingOutput?
private let videoSampleBufferQueue = DispatchQueue(label: "com.francestudio.phia.VideoSampleBufferQueue")
private let audioSampleBufferQueue = DispatchQueue(label: "com.francestudio.phia.AudioSampleBufferQueue")
private let micSampleBufferQueue = DispatchQueue(label: "com.francestudio.phia.MicSampleBufferQueue")
func startCapture(configuration: SCStreamConfiguration, filter: SCContentFilter, recordingOutput: SCRecordingOutput) async throws {
// Create the stream output delegate.
let streamOutput = CaptureEngineStreamOutput()
self.streamOutput = streamOutput
do {
stream = SCStream(filter: filter, configuration: configuration, delegate: streamOutput)
try stream?.addStreamOutput(streamOutput, type: .screen, sampleHandlerQueue: videoSampleBufferQueue)
try stream?.addStreamOutput(streamOutput, type: .audio, sampleHandlerQueue: audioSampleBufferQueue)
try stream?.addStreamOutput(streamOutput, type: .microphone, sampleHandlerQueue: micSampleBufferQueue)
self.recordingOutput = recordingOutput
recordingOutput.delegate = self
try stream?.addRecordingOutput(recordingOutput)
try await stream?.startCapture()
} catch {
logger.error("Failed to start capture: \(error.localizedDescription)")
throw error
}
}
func stopCapture() async throws {
do {
try await stream?.stopCapture()
} catch {
logger.error("Failed to stop capture: \(error.localizedDescription)")
throw error
}
}
func update(configuration: SCStreamConfiguration, filter: SCContentFilter) async {
do {
try await stream?.updateConfiguration(configuration)
try await stream?.updateContentFilter(filter)
} catch {
logger.error("Failed to update the stream session: \(String(describing: error))")
}
}
func stopRecordingOutputForStream(_ recordingOutput: SCRecordingOutput) throws {
try self.stream?.removeRecordingOutput(recordingOutput)
}
}
// MARK: - SCRecordingOutputDelegate
extension CaptureEngine: SCRecordingOutputDelegate {
func recordingOutputDidStartRecording(_ recordingOutput: SCRecordingOutput) {
let startTime = Date()
logger.info("Recording output did start recording \(startTime)")
}
func recordingOutputDidFinishRecording(_ recordingOutput: SCRecordingOutput) {
logger.info("Recording output did finish recording")
}
func recordingOutput(_ recordingOutput: SCRecordingOutput, didFailWithError error: any Error) {
logger.error("Recording output failed with error: \(error.localizedDescription)")
}
}
private class CaptureEngineStreamOutput: NSObject, SCStreamOutput, SCStreamDelegate {
private let logger = Logger()
override init() {
super.init()
}
func stream(_ stream: SCStream, didOutputSampleBuffer sampleBuffer: CMSampleBuffer, of outputType: SCStreamOutputType) {
guard sampleBuffer.isValid else { return }
switch outputType {
case .screen:
break
case .audio:
break
case .microphone:
break
@unknown default:
logger.error("Encountered unknown stream output type:")
}
}
func stream(_ stream: SCStream, didStopWithError error: Error) {
logger.error("Stream stopped with error: \(error.localizedDescription)")
}
}
I am getting error
Value of type 'SCRecordingOutput' has no member 'delegate'
Even though I am targeting macOs 15+ ( macOs 26 actually ) and macOs only.
What is the best way to achieving the desired result? Is there any other / better way to do it?
Hi everyone,
I’m looking for help with an issue where using insertRows to add a row to an NSTableView requires resizing the window before I can scroll to the newly added rows that extend beyond the visible area of the NSScrollView.
import Cocoa
class ViewController: NSViewController {
var data = Constants.movies
// Table components
var titleField = NSTextField()
var directorField = NSTextField()
var releaseYearField = NSTextField()
var addMovieButton = NSButton(title: "Add Movie", image: NSImage(systemSymbolName: "plus", accessibilityDescription: "")!, target: nil, action: #selector(addMovie))
var table = NSTableView()
var titleColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.titleColumnId))
var directorColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.directorColumnId))
var releaseYearColumn = NSTableColumn(identifier: NSUserInterfaceItemIdentifier(Constants.releaseColumnId))
// Scroll view
let scrollView = NSScrollView()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.black.cgColor
configure()
}
private func configure() {
titleField.translatesAutoresizingMaskIntoConstraints = false
directorField.translatesAutoresizingMaskIntoConstraints = false
releaseYearField.translatesAutoresizingMaskIntoConstraints = false
addMovieButton.translatesAutoresizingMaskIntoConstraints = false
scrollView.translatesAutoresizingMaskIntoConstraints = false
table.translatesAutoresizingMaskIntoConstraints = false
titleField.placeholderString = "Movie Title"
directorField.placeholderString = "Name of Director"
releaseYearField.placeholderString = "Year Released"
// Configure table
table.addTableColumn(titleColumn)
table.addTableColumn(directorColumn)
table.addTableColumn(releaseYearColumn)
titleColumn.title = "Movie Title"
directorColumn.title = "Director"
releaseYearColumn.title = "Year Released"
table.delegate = self
table.dataSource = self
table.focusRingType = .none
// Configure scroll view
scrollView.documentView = table
scrollView.hasVerticalScroller = true
scrollView.hasHorizontalScroller = false
scrollView.autohidesScrollers = true
// Add views to the hierarchy
view.addSubview(titleField)
view.addSubview(directorField)
view.addSubview(releaseYearField)
view.addSubview(addMovieButton)
view.addSubview(scrollView)
// view.addSubview(table)
NSLayoutConstraint.activate([
titleField.widthAnchor.constraint(equalToConstant: 150),
directorField.widthAnchor.constraint(equalToConstant: 150),
releaseYearField.widthAnchor.constraint(equalToConstant: 150),
addMovieButton.widthAnchor.constraint(equalToConstant: 100),
titleField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
directorField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
releaseYearField.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
addMovieButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 20),
directorField.trailingAnchor.constraint(equalTo: view.centerXAnchor, constant: -10),
releaseYearField.leadingAnchor.constraint(equalTo: view.centerXAnchor, constant: 10),
titleField.trailingAnchor.constraint(equalTo: directorField.leadingAnchor, constant: -20),
addMovieButton.leadingAnchor.constraint(equalTo: releaseYearField.trailingAnchor, constant: 20),
scrollView.topAnchor.constraint(equalTo: titleField.bottomAnchor, constant: 20),
scrollView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20),
scrollView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20),
scrollView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20),
// table.widthAnchor.constraint(equalTo: scrollView.contentView.widthAnchor),
// table.heightAnchor.constraint(equalTo: scrollView.contentView.heightAnchor)
])
}
@objc private func addMovie() {
let title = titleField.stringValue
let director = directorField.stringValue
guard let year = Int(releaseYearField.stringValue) else {
return
}
let movie = Movie(title: title, director: director, releaseYear: year)
data.append(movie)
// Approach 1
// table.reloadData()
// Approach 2
let newRow = data.count - 1
table.insertRows(at: IndexSet(integer: newRow), withAnimation: .slideDown)
}
Using table.reloadData works fine and I can scroll to the new rows as I add them, but it doesn't have the smooth animation I want to achieve.
What is the best practice and correct way for using table.insertRows to avoid this issue?
Note: I am using programmatic constraints only.
Overview
Starting with macOS 26 beta 1, a new NSGlassContainerView is added inside NSToolbarView.
This view intercepts mouse events, so any SwiftUI Button (or other interactive view) overlaid on the title‑bar / toolbar area no longer receives clicks.
(The same code works fine on macOS 15 and earlier.)
Filed as FB18201935 via Feedback Assistant.
Reproduction (minimal project)
macOS 15 or earlier → button is clickable
macOS 26 beta → button cannot be clicked (no highlight, no action call)
@main
struct Test_macOS26App: App {
init() {
// Uncomment to work around the issue (see next section)
// enableToolbarClickThrough()
}
var body: some Scene {
WindowGroup {
ContentView()
}
.windowStyle(.hiddenTitleBar) // ⭐️ hide the title bar
}
}
struct ContentView: View {
var body: some View {
NavigationSplitView {
List { Text("sidebar") }
} detail: {
HSplitView {
listWithOverlay
listWithOverlay
}
}
}
private var listWithOverlay: some View {
List(0..<30) { Text("item: \($0)") }
.overlay(alignment: .topTrailing) { // ⭐️ overlay in the toolbar area
Button("test") { print("test") }
.glassEffect()
.ignoresSafeArea()
}
}
}
Investigation
In Xcode View Hierarchy Debugger, a layer chain
NSToolbarView > NSGlassContainerView sits in front of the button.
-[NSView hitTest:] on NSGlassContainerView returns itself, so the event never reaches the SwiftUI layer.
Swizzling hitTest: to return nil when the result is the view itself makes the click go through:
func enableToolbarClickThrough() {
guard let cls = NSClassFromString("NSGlassContainerView"),
let m = class_getInstanceMethod(cls, #selector(NSView.hitTest(_:))) else { return }
typealias Fn = @convention(c)(AnyObject, Selector, NSPoint) -> Unmanaged<NSView>?
let origIMP = unsafeBitCast(method_getImplementation(m), to: Fn.self)
let block: @convention(block)(AnyObject, NSPoint) -> NSView? = { obj, pt in
guard let v = origIMP(obj, #selector(NSView.hitTest(_:)), pt)?.takeUnretainedValue()
else { return nil }
return v === (obj as AnyObject) ? nil : v // ★ make the container transparent
}
method_setImplementation(m, imp_implementationWithBlock(block))
}
Questions / Call for Feedback
Is this an intentional behavioral change?
If so, what is the recommended public API or pattern for allowing clicks to reach views overlaid behind the toolbar?
Any additional data points or confirmations are welcome—please reply if you can reproduce the issue or know of an official workaround.
Thanks in advance!
Cannot find any guidance in the forums and Developer Doc, the WWDC session Meet TextKit2 says this protocol is served for any location type espacially useful when the underlying doc model is not linear. But when I try to subclass the NSTextLocation with my own type to define a more structured location rather than a linear one, also with my own NSTextContentManager subclass implementation, I keep receiving the system internal Location model like NSCountableTextLocation compare to my location which cause the app to crash.
-[NSCountableTextLocation compare:] receiving unmatching type <MarkdownTK2.ChildIndexPathLocation: 0x9b2402aa0>
In my own NSTextContentManager subclass:
public override func offset(
from: any NSTextLocation,
to: any NSTextLocation
) -> Int {
this method will also both receive my own location and some times receiving the system defined location that I can not calculate the offset then just return zero.
The doc only says
If you provide your own implementation of the NSTextLocation protocol to manage locations in your content, subclass NSTextContentManager and implement your own storage object to support those locations.
OS
Development environment: Xcode 26.0, macOS 26.0
Run-time configuration: macOS 26.0
Hello everyone,
Since I installed Xcode 26, I've been encountering issues I've never seen before.
I have Mac OS applications written in Objective-C, some released as far back as 14 years ago.
When compiling them with Xcode 26, I experience efficiency issues related to thread management and interface updates.
There are rendering problems with a simple NSTextView created through Interface Builder.
The issue is not easily reproducible as it occurs randomly on some machines, regardless of their architecture or macOS version. The main thread freezes, and generally after 15-30 seconds, it unfreezes, loading the interface and text. The length of the text is irrelevant to the issue, and no crashes occur.
I spent ten days trying to optimize the code and change the loading order within the class, but the problem persists. However, if I compile the application with Xcode 16.4, everything works like a charm. I also tried using the macOS 15.5 SDK to compile with Xcode 26, but it doesn’t resolve any issues. Additionally, I tried changing the compiler optimization level, but it didn’t solve the problem.
This leads me to believe it’s an issue with the Xcode 26 compiler. If it were a code issue, it would be easily reproducible and would also occur when compiling with 16.4.
The Xcode 26.1 Beta doesn’t resolve the issue. Can anyone tell me if I need to change something related to the compiler?
Are you aware of any issues like this?
Thank you,
Luca
My app displays some text that should appear the same regardless of the container view or window size, i.e. it should grow and shrink with the container view or window.
On iOS there is UILabel.adjustsFontSizeToFitWidth but I couldn't find any equivalent API on macOS. On the internet some people suggest to iteratively set a smaller font size until the text fits the available space, but I thought there must be a more efficient solution. How does UILabel.adjustsFontSizeToFitWidth do it?
My expectation was that setting a font's size to a fraction of the window width or height would do the trick, but when resizing the window I can see a slightly different portion of it.
class ViewController: NSViewController {
override func loadView() {
view = MyView(frame: CGRect(x: 0, y: 0, width: 400, height: 400))
NSLayoutConstraint.activate([view.widthAnchor.constraint(equalTo: view.heightAnchor, multiplier: 3), view.heightAnchor.constraint(greaterThanOrEqualToConstant: 100)])
}
}
class MyView: NSView {
let textField = NSTextField(labelWithString: String(repeating: "a b c d e f g h i j k l m n o p q r s t u v w x y z ", count: 2))
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
textField.translatesAutoresizingMaskIntoConstraints = false
textField.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
addSubview(textField)
NSLayoutConstraint.activate([textField.topAnchor.constraint(equalTo: topAnchor), textField.leadingAnchor.constraint(equalTo: leadingAnchor), textField.trailingAnchor.constraint(equalTo: trailingAnchor)])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func resize(withOldSuperviewSize oldSize: NSSize) {
// textField.font = .systemFont(ofSize: frame.width * 0.05)
textField.font = .systemFont(ofSize: frame.height * 0.1)
}
}
I have a custom object which gets passed back to the main app from XPC.
I whitelist it like so:
NSSet *expectedClass = [NSSet setWithObjects:[NSArray class],
[MyCustomClass class],
nil];
[interface setClasses:expectedClass forSelector:@selector(myMethodNameHere:withCompletion:)
argumentIndex:0
ofReply:YES];
Now my custom class conforms to NSSecureCoding. It does have an array property of another custom class.
@property (nonatomic,readonly) NSArray *arraypropertyOfOtherClass;
Which is decoded in -initWithCoder: using:
-decodeArrayOfObjectsOfClasses:forKey:
Now on macOS Tahoe this is all walking fine. But I just tested on macOS Monterey and I get the following error:
Exception: decodeObjectForKey: too many nested collections when explicitly decoding a single collection.
How should I handle this for earlier versions of macOS?
When I tried this, the app crashed immediately with a requirement to use NSTextContentStorage subclass
Hey everyone. I have a macOS app written in SwiftUI. I have multiple SwiftUI Scenes and Views, but needed to write one specific window in AppKit (an NSPanel, to be specific). The problem I'm facing is- I'm not sure how to incorporate this NSPanel with the rest of my SwiftUI/Observable code. I'm relying on the SwiftUI app cycle.
For example, I have a boolean in my view model (observation tracked). I'd like to use this boolean to hide/unhide my NSPanel. Any way to cleanly hook into the viewmodel, or onto some specific observable variables would be very very helpful. Thank you everyone.
[NSEvent charactersByApplyingModifiers:] not matching NSEvent.characters/charactersIgnoringModifiers
To my surprise [NSEvent charactersByApplyingModifiers:] does not always produce
the same NSString result as the originating NSEvent reflects through characters/charactersIgnoringModifiers, even if passing on the event's own modifierFlags.
For example, when pressing the 'end' key, both characters and charactersIgnoringModifiers return 0x000000000000f72b,
which matches the value of NSEndFunctionKey. But calling [NSEvent charactersByApplyingModifiers:] passing in
NSEvent.modifierFlags produces 0x0000000000000004, which matches the value of kEndCharCode.
(lldb) po [[((NSApplication*)NSApp).currentEvent characters] characterAtIndex:0]
0x000000000000f72b
(lldb) po [[((NSApplication*)NSApp).currentEvent charactersIgnoringModifiers] characterAtIndex:0]
0x000000000000f72b
(lldb) po [[((NSApplication*)NSApp).currentEvent charactersByApplyingModifiers:[(NSEvent*)((NSApplication*)NSApp).currentEvent modifierFlags]] characterAtIndex:0]
0x0000000000000004
(The same can be observed with UCKeyTranslate directly, which charactersByApplyingModifiers seems to use internally).
I would expect [NSApp.currentEvent charactersByApplyingModifiers:NSApp.currentEvent.modifierFlags] to match
either NSApp.currentEvent.characters or NSApp.currentEvent.charactersIgnoringModifiers.
Is there a logic behind this perceived discrepancy that I'm missing? Should I always prefer the
content of NSEvent.characters/charactersIgnoringModifiers in this case if the modifier flags I'm applying
match those of the event itself?
Thanks for any insights!
(Also reported as FB20591338)
My app is a bit of a special case and relies on a custom view in a NSStatusItem. I use a NSHostingView and add it as a subview to my NSStatusItem's .button property.
Since macOS 26 Tahoe, even simple animations like a .frame change of a Circle won't animate smoothly even though the same SwiftUI animates normally in a WindowGroup.
class AppDelegate: NSObject, NSApplicationDelegate {
private let statusItem: NSStatusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
func applicationDidFinishLaunching(_ aNotification: Notification) {
let subview = NSHostingView(rootView: AnimationView())
let view = self.statusItem.button
view?.addSubview(subview)
subview.translatesAutoresizingMaskIntoConstraints = false
guard let view = view else { return }
NSLayoutConstraint.activate([
subview.centerXAnchor.constraint(equalTo: view.centerXAnchor),
subview.centerYAnchor.constraint(equalTo: view.centerYAnchor),
subview.widthAnchor.constraint(equalToConstant: 22),
subview.heightAnchor.constraint(equalToConstant: 22)
])
}
}
struct AnimationView: View {
@State private var isTapped = false
@State private var size: CGSize = .init(width: 4, height: 4)
var body: some View {
Circle()
.fill(.pink)
.frame(width: size.width, height: size.height)
.frame(width: 20, height: 20)
// .frame(maxHeight: .infinity)
// .padding(.horizontal, 9)
// .frame(height: 22)
.contentShape(Rectangle())
// .background(Color.blue.opacity(0.5))
.onTapGesture {
withAnimation(.interactiveSpring(response: 0.85, dampingFraction: 0.26, blendDuration: 0.45)) {
// withAnimation(.spring()) {
if isTapped {
size = .init(width: 4, height: 4)
} else {
size = .init(width: 16, height: 16)
}
}
isTapped.toggle()
}}
}
Example project:
https://app.box.com/s/q28upunrgkxyyd97ovslgud9yitqaxfk
I’ve enabled multiple selection in NSOutlineView. When I collapse a parent item, all of its selected child rows get deselected automatically.
Is there a way to prevent this deselection so that selections remain intact when the parent is collapsed and restored when it’s expanded again?
I want to print the content of a WKWebView. I've done some searching, and many people have struggled with this over the years. Some claimed success, but their solutions don't work for me. One person created images for each pages and printed that, but then if you were to print to PDF, you'd get a PDF containing images rather than text.
If I just call the printView(_:)) method of the view, I get blank pages.
With the following more elaborate code, I get a partial printout, 11 out of what should be about 13 pages.
let info = NSPrintInfo.shared
info.topMargin = 72.0;
info.bottomMargin = 72.0;
info.leftMargin = 72.0;
info.rightMargin = 72.0;
info.isVerticallyCentered = false;
info.isHorizontallyCentered = false;
info.horizontalPagination = .fit;
info.verticalPagination = .automatic;
let printOp = webView!.printOperation( with: info )
printOp.canSpawnSeparateThread = true
printOp.view?.frame = NSMakeRect( 0, 0,
info.paperSize.width, info.paperSize.height )
printOp.runModal(for: webView.window!, delegate: self,
didRun: nil, contextInfo: nil )
When I run the above under the debugger, I see console messages saying
CGContextClipToRect: invalid context 0x0.
Once the print dialog appears, if I touch (but not change) the selected printer, then the page count changes to the correct value.
I am trying to resize a Window Form after it loads and have done quite a bit of searching for code to do it.
Here is one code snippet that works to size the form during the design phase.
self.view.window?.contentMinSize = CGSize(width: 1100, height: 310)
I have tried code like below to increase the window size after the Form loads
if let myWindow = self.view.window ?? NSApplication.shared.mainWindow
{
// Increase window size and position after it loads
let newRect = NSRect(x: 100, y: 100, width: 1400, height: 900)
}
It seems that this code not only changes the Form size after loading, but also changes the size of the Form in Main.swift, which is something I don't want.
I read elsewhere that I had to disable constraints to resize the Form, so I tried code below.
let tableView = NSTableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
let newRect = NSRect(x: 100, y: 0, width: 1100, height: 600)
myWindow?.setFrame(newRect, display: true)
That code did not seem to do anything as well.
Also, the Form displays in the lower left of the screen.
Note that main reason I want to resize the Form after loading is to keep it smaller during design development. The same goes for the NSTableView, which I have not gotten to yet.
When I compiled my legacy project with Tahoe's macOS 26 SDK, NSRulerViews are showing a very different design:
Under prior macOS versions the horizontal and verrical ruler's background were blurring the content view, which was extending under the rulers, showing through their transparency.
With Tahoe the horizontal ruler is always reflecting the scrollview's background color, showing the blurred content view beneath.
And the vertical ruler is always completely transparent (without any blurring), showing the content together with the ruler's markers and ticks.
It's difficult to describe, I'll try to replicate this behavior with a minimal test project, and probably file a bug report / enhancement request.
But before I take next steps, can anyone confirm this observation? Maybe it is an intentional design decision by Apple?
NSHostingSceneRepresentation, introduced in macOS 26, allows calling SwiftUI’s windows and other elements set in a Scene from AppKit. However, while Settings and WindowGroup set in the Scene can be invoked as expected using environment.openSettings() and environment.openWindow(id:) respectively, calling Window or WindowUtility doesn’t work. That is, the app just fails to open the desired window with the provided ID, and no error message or other feedback/crash/freeze appears.
I expect that executing the openUtilityWindow(_:)action in the following code will display the UtilityWindow set in the scene. However, the window does not actually open.
@main
final class AppDelegate: NSObject, NSApplicationDelegate {
private let scene = NSHostingSceneRepresentation {
UtilityWindow("Utility Window", id: "UtilityWindow") {
Text("Utility Window")
.scenePadding()
}
}
func applicationWillFinishLaunching(_ notification: Notification) {
NSApp.addSceneRepresentation(self.scene)
}
@IBAction func openUtilityWindow(_ sender: Any?) {
self.scene.environment.openWindow(id: "UtilityWindow")
}
}
Is there something wrong with my implementation and expectation? Or is this a bug in NSHostingSceneRepresentation?
Just in case, I’ve already filed this issue withFeedback Assistant: FB20310722
This feedback also includes a sample project reproducing this issue.
When scrolling a basic NSScrollView there seems to be a sudden jump after each flick. Scrolling does not appear smooth and is disorientating.
A scroll jump seems to happen directly after letting go of a scroll flick using a trackpad/mouse. Right at that moment the scroll turns into a momentum scroll, slowly decreasing the speed. But the first frame after the gesture the content jumps forward, more than what is expected.
Observations:
Counterintuitively, scrolling appears to be smoother when disabling NSScrollView.isCompatibleWithResponsiveScrolling. If disabled using a custom NSScrollView subclass there is no large jump anymore.
Scrolling also appears to be smoother using a SwiftUI ScrollView. I assume that has the same behaviour as a disabled isCompatibleWithResponsiveScrolling
Ironically a WKWebView scrolls much smoother. No sudden jump is observable. It also seems to scroll with faster acceleration, but the individual frames do appear smoother. Why is this better than a native NSScrollView?
Elastic scrolling at the bounds of the scroll view also appears much smoother for WKWebViews. When pulling to refresh there is a jump for NSScrollView/SwiftUI, but not for WKWebView.
When using an NSScrollView with isCompatibleWithResponsiveScrolling disabled, scrolling appears just as smooth as WKWebView on macOS 13 Ventura and below. On macOS 14 Sonoma scrolling behaviour is suddenly different.
Please see a sample project with 4 different scroll views side by side:
https://github.com/floorish/ScrollTest
Screen recordings show the sudden jumps when scrolling and when elastic scrolling.
Tested on Intel & Arm Macs, macOS 11 Big Sur through 15 Sequoia, built with Xcode 16.
Should isCompatibleWithResponsiveScrolling be disabled on Sonoma+? Are there any drawbacks?
There is also no overdraw anymore since Monterey, as described in https://developer.apple.com/library/archive/releasenotes/AppKit/RN-AppKitOlderNotes/#10_9Scrolling
Even with responsive scrolling disabled, why is WKWebView scrolling much smoother than NSScrollView?
Looking to update one of my apps that uses SKStoreReviewController +requestReview (deprecated) to
AppStore.requestReview(in:)
umm...I have a few of questions...
Why is an NSViewController parameter required? It's really not so uncommon for an AppKit app to just use NSWindowController with a window that does not use NSViewController...
It should be possible to present the review request in a standalone alert (attached to a window is preferred IMO but it still should be possible to ask in separate window).
3)...why Swift..(err nevermind)
Ideally:
AppStore requestReview should take a NSWindow parameter but that parameter should be optional. If nil the request should be presented in a standalone window (like an alert). If non nil..present as a sheet on the window.
Why a view controller? Maybe I'm missing something.