Currently, I have this to stop resizing window:
#if targetEnvironment(macCatalyst)
windowScene.sizeRestrictions?.minimumSize = CGSize(width: 480, height: 900)
windowScene.sizeRestrictions?.maximumSize = CGSize(width: 480, height: 900)
#endif
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
self.window = window
window.makeKeyAndVisible()
but the fullscreen button makes it full screen anyway.
It's a bit complicated but possible. Here is an approach (I dropped all target macros to simplify post).
Result:
Code:
// on next event after UIWindow has made key it is possible to find NSWindow in runtime
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
...
window.makeKeyAndVisible()
DispatchQueue.main.async { // < wait for NSWindow available
SilentBridge.disableCloseButton(for: self.nsWindow(from: window))
}
}
// added helper function to SceneDelegate to find NSWindow
func nsWindow(from window: UIWindow) -> NSObject? {
guard let nsWindows = NSClassFromString("NSApplication")?.value(forKeyPath: "sharedApplication.windows") as? [NSObject] else { return nil }
for nsWindow in nsWindows {
let uiWindows = nsWindow.value(forKeyPath: "uiWindows") as? [UIWindow] ?? []
if uiWindows.contains(window) {
return nsWindow
}
}
return nil
}
Objective-C part is preferred (it's just simpler to work with non-declared selectors). Add new Objective-C class via Xcode template and confirm creating bridge. Afterwards it is needed to add below class header file in generated *-Bridging-Header.h
and all should work.
// SilentBridge.h
@import Foundation;
@interface SilentBridge : NSObject
+ (void)disableCloseButtonFor:(NSObject * _Nullable)window;
@end
// SilentBridge.m
#import "SilentBridge.h"
@import Foundation;
// Forward declarations to allow direct calls in below method
@interface NSObject(SilentBridge)
- (id)standardWindowButton:(NSInteger)value;
- (void)setEnabled:(BOOL)flag;
@end
@implementation SilentBridge
+ (void)disableCloseButtonFor:(NSObject *)window {
if ([window respondsToSelector:@selector(standardWindowButton:)]) {
id closeButton = [window standardWindowButton:2];
if ([closeButton respondsToSelector:@selector(setEnabled:)]) {
[closeButton setEnabled:NO];
}
}
}
@end