NSWindow with NSWindowTitleVisibilityNone saving incorrect frame to user defaults?

1.3k views Asked by At

My app has an option that allows the user to choose between the standard "full-size" window titlebar/toolbar and the "compact" titlebar/toolbar made available in the NSWindow 10.10 API. Specifically, I'm using the -titleVisibility method to set either NSWindowTitleVisible or NSWindowTitleHidden depending on the user's preference. If the user checks the "Compact Titlebar" checkbox, NSWindowTitleHidden is applied to the window, otherwise, the window uses the default style. When the checkbox value changes, the value is stored in the app's user defaults, and the window is updated/redrawn.

Everything works great until the application is relaunched. Each time the app starts up, the window grows by exactly how much space is saved by switching from the default window style (NSWindowTitleVisible) to the new style (NSWindowTitleHidden). So restarting the app 5 – 6 times will make the window flush with the menubar and the dock, depending on how big the window was when the checkbox was initially checked.

In other words, it doesn't seem like the window's frame is being updated in NSUserDefaults when the property is set. Is there a workaround for this, or am I just overlooking something? Any advice would be muy helpful.

Thanks!

4

There are 4 answers

0
rraallvv On

Try setting the titleVisibility property to the number 1 in the User Defined Runtime Attributes

enter image description here

1 is the corresponding value for NSWindowTitleHidden

typedef NS_ENUM(NSInteger, NSWindowTitleVisibility) {
    /* The default mode has a normal window title and titlebar buttons. */
    NSWindowTitleVisible  = 0,
    /* The always hidden mode hides the title and moves the toolbar up into the area previously occupied by the title. */
    NSWindowTitleHidden = 1,
} NS_ENUM_AVAILABLE_MAC(10_10);

However this would print a message to the console complaining that NSWindow is not key value coding-compliant for the key titleVisibility on OS X versions previous to 10.10

0
Nightbirdsevolve On

Simple fix for now is to save and restore the window's frame manually, here's how I do it:

In your app delegate, when application terminates, save the window's frame

- (void)applicationWillTerminate:(NSNotification *)notification
{
    [[NSUserDefaults standardUserDefaults] setObject:NSStringFromRect(self.windowController.window.frame) forKey:@"WindowFrameKey"];
}

In your window controller's -awakeFromNib method, restore the frame

- (void)awakeFromNib
{
    if([NSWindow instancesRespondToSelector:@selector(setTitleVisibility:)])
    {
        // Hide Titlebar
        [self.window setTitleVisibility:NSWindowTitleHidden];

        NSString *winFrameString = [[NSUserDefaults standardUserDefaults] stringForKey:@"WindowFrameKey"];

        if(winFrameString != nil)
        {
            NSRect savedRect = NSRectFromString(winFrameString);

            if(!NSEqualRects(self.window.frame, savedRect))
            {
                [self.window setFrame:savedRect display:YES animate:NO];
            }
        }
    }
0
Václav Slavík On

A better (and confirmed working) solution was posted at https://openradar.appspot.com/18510665 by pointum:

The problem is that window size is restored by the system using -[NSWindow setFrameUsingName:] before titleVisibility is set. Solution:

  1. Remove "Autosave Name" value in Interface Builder.
  2. Set it in code right after setting titleVisibility using -[NSWindow setFrameAutosaveName:].
0
Nickkk On

In my case, in addition to calling setFrameAutosaveName() and setFrameUsingName() at the end of the whole window setup, I also had to make sure that the window's contentView was being initialized with a non-zero size. Using CGRect(x: 0, y: 0, width: 1, height: 1) was enough.