Skip to content

Instantly share code, notes, and snippets.

@steipete
Last active June 1, 2023 18:24
Show Gist options
  • Star 40 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save steipete/30c33740bf0ebc34a0da897cba52fefe to your computer and use it in GitHub Desktop.
Save steipete/30c33740bf0ebc34a0da897cba52fefe to your computer and use it in GitHub Desktop.
Mac Catalyst: Get the NSWindow from a UIWindow (Updated for macOS 11 Big Sur, also works with Catalina)
// Don't forget to prefix your category!
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface UIWindow (PSPDFAdditions)
#if TARGET_OS_UIKITFORMAC
/**
Finds the NSWindow hosting the UIWindow.
@note This is a hack. Iterates over all windows to find match. Might fail.
*/
@property (nonatomic, readonly, nullable) id nsWindow;
#endif
@end
NS_ASSUME_NONNULL_END
#import "UIWindow+PSPDFAdditions.h"
@implementation UIWindow (PSPDFAdditions)
#if TARGET_OS_UIKITFORMAC
- (nullable NSObject *)nsWindow {
id delegate = [[NSClassFromString(@"NSApplication") sharedApplication] delegate];
const SEL hostWinSEL = NSSelectorFromString([NSString stringWithFormat:@"_%@Window%@Window:", @"host", @"ForUI"]);
@try {
// There's also hostWindowForUIWindow 🤷‍♂️
PSPDF_SILENCE_CALL_TO_UNKNOWN_SELECTOR(id nsWindow = [delegate performSelector:hostWinSEL withObject:self];)
// macOS 11.0 changed this to return an UINSWindowProxy
let attachedWin = NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"attached", @"Window"]);
if ([nsWindow respondsToSelector:attachedWin]) {
nsWindow = [nsWindow valueForKey:NSStringFromSelector(attachedWin)];
}
return nsWindow;
} @catch (...) {
NSLog(@"Failed to get NSWindow for %@.", self);
}
return nil;
}
#endif
@end
@polymerchm
Copy link

polymerchm commented May 23, 2020

This works great. just need to be sure to let the UI settle down with delays before you try to access the window. Using these to lock the aspect ratio in a MacCatalyst app:

delay(2) {
    cover.removeFromSuperview()
    #if targetEnvironment(macCatalyst)
    let ns = window.nsWindow
    let frame = ns?.value(forKey: "frame")
    let size = (frame as! CGRect).size
    ns!.setValue(CGSize(1.0, size.height/size.width), forKey: "aspectRatio")
    #endif
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment