In the below code, I create two windows, and use a window delegate to make sure that whenever the first is fullscreened, its menubar and dock are hidden properly. However, when I fullscreen the first window and go back to the desktop to see my second window, the second window's minimize button is grayed out and using miniaturize on it will not work either. I've tried various things; it seems like if I fullscreen the second window and the unfullscreen it, it then becomes minimizable without additional side effects. Is there any reason why this is happening? This seems like a bug in AppKit... so how do I work around it programmatically?
#import <Cocoa/Cocoa.h>
@interface AppDelegate : NSObject <NSApplicationDelegate, NSWindowDelegate>
@property (strong) NSWindow *mainWindow;
@property (strong) NSWindow *secondaryWindow;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSRect mainRect = NSMakeRect(100, 300, 400, 300);
self.mainWindow = [[NSWindow alloc] initWithContentRect:mainRect
styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable)
backing:NSBackingStoreBuffered
defer:NO];
[self.mainWindow setTitle:@"Main Window (Go Fullscreen Here)"];
[self.mainWindow setDelegate:self];
NSTextField *mainLabel = [NSTextField labelWithString:@"1. Click the green zoom/fullscreen button on THIS window.\n\n2. Look at the other window's yellow minimize button."];
[mainLabel setFrame:NSMakeRect(20, 100, 360, 100)];
[[self.mainWindow contentView] addSubview:mainLabel];
[self.mainWindow makeKeyAndOrderFront:nil];
NSRect secondaryRect = NSMakeRect(550, 300, 400, 300);
self.secondaryWindow = [[NSWindow alloc] initWithContentRect:secondaryRect
styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable)
backing:NSBackingStoreBuffered
defer:NO];
[self.secondaryWindow setTitle:@"Secondary Window (The Victim)"];
NSButton *testButton = [NSButton buttonWithTitle:@"Try code [window miniaturize:]" target:self action:@selector(attemptProgrammaticMinimize:)];
[testButton setFrame:NSMakeRect(80, 130, 240, 40)];
[[self.secondaryWindow contentView] addSubview:testButton];
[self.secondaryWindow makeKeyAndOrderFront:nil];
}
- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions:(NSApplicationPresentationOptions)proposedOptions {
return NSApplicationPresentationFullScreen |
NSApplicationPresentationHideMenuBar |
NSApplicationPresentationHideDock;
}
- (void)attemptProgrammaticMinimize:(id)sender {
[self.secondaryWindow miniaturize:nil];
NSLog(@"[Repro] Minimize attempted");
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender {
return YES;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSApplication *app = [NSApplication sharedApplication];
[app setActivationPolicy:NSApplicationActivationPolicyRegular];
AppDelegate *delegate = [[AppDelegate alloc] init];
[app setDelegate:delegate];
[app activateIgnoringOtherApps:YES];
[app run];
}
return 0;
}
Thanks for the self-contained repro. It builds and reproduces as written here on macOS 26.5.1.
The disabling is application-wide rather than specific to the secondary window. NSApplication.presentationOptions is documented as the options "that should be in effect for the system when this application is the active application". hideDock is documented as "The dock is entirely hidden and disabled". Minimizing places a window in the Dock. So while that flag is in effect, no window in the app can minimize, whether or not it is the full-screen one. window:willUseFullScreenPresentationOptions: is a per-window hook, but what you return from it applies application-wide.
Keeping the menu bar fully hidden requires that flag. The NSApplication.PresentationOptions reference lists the valid combinations, and one of them is that "If you specify hideMenuBar, it must be accompanied by hideDock". Returning the pair without HideDock raises NSInvalidArgumentException during the transition into full screen:
NSApplicationPresentationHideMenuBar specified without NSApplicationPresentationHideDock
So for as long as your main window is in full screen, minimize is unavailable across the app. Nothing I tried re-enabled it while HideDock was in effect.
What does look worth reporting is the state after that. Once the main window leaves full screen, NSApp.presentationOptions returns to NSApplicationPresentationDefault, but the secondary window's minimize button stays disabled. I confirmed it is still disabled several seconds later, and assigning NSApplicationPresentationDefault explicitly does not clear it. Removing and re-adding the miniaturizable style-mask bit does:
- (void)windowDidExitFullScreen:(NSNotification *)notification {
NSWindow *w = self.secondaryWindow;
w.styleMask = w.styleMask & ~NSWindowStyleMaskMiniaturizable;
w.styleMask = w.styleMask | NSWindowStyleMaskMiniaturizable;
}
After that the button is enabled again and -miniaturize: works. That gives you the minimize button back as soon as full screen ends. It is also the part I would file a Feedback report on. The button state does not track presentation options that have already returned to default. Attaching your repro as-is would make it straightforward to look at.
References: