11
votes

So right now I have an NSWindow that draws itself like an NSToolbar using INAppStoreWindow, and I was wondering if there was any kind of event or message sent out when the menu bar moves while the app is in full screen, so that I could then move the title bar of the window in response (the way a standard NSToolbar works). Clearly NSToolbar knows something that I don't, and it would save me from making an NSTrackingArea on the upper part of my window.

Here's what it does now:

Before

And here's what I'd like to do:

enter image description here

Unfortunately, KVO'ing a fullScreenAccessoryView does not work as well. Frame events are only generated when entering and exiting fullscreen mode, and not when the toolbar is "moved down" by the status bar.

3
When you say “status bar”, do you actually mean the menu bar?rob mayoff
Yes. It goes by many names (Apple calls it NSStatusBar).CodaFi
In general, the menu bar is fixed at the top of the user's monitor. Is this menu bar at the top of the moving window? Now that I'm doing a 2nd & 3rd read of your question, I'm guessing this is a iTunes / Xcode like toolbar at the top of your window. Maybe append a screenshot to your question so we have a better idea of what you're talking about?Michael Dautermann
I think he's talking about the way the menu bar hides when you put a window in fullscreen mode, and then reappears if you move your mouse pointer to the top edge of the screen. If you do this in Safari or Xcode (for example), the toolbar will slide down to stay fully visible.rob mayoff
Obviously the iTunes team didn't get the memo, because its toolbar doesn't slide down. :)rob mayoff

3 Answers

2
votes

How about this? Create NSStatusBarItem with a custom NSView having width 0 and then track its window's position using NSWindowWillMoveNotification.

UPDATE: I made a fork of the INAppStoreWindow with a custom toolbar attached to the menubar. Check it out.

0
votes

One thing you could try is to use set a fake (i.e. empty) toolbar on the window and then give it a fullScreenAccessoryView. This view is, when moving into fullscreen, removed from the view hierarchy and attached below the toolbar. Dunno, however, how this is works when using a custom window class... :/

0
votes

I was looking to accomplish exactly the same thing. I was able to do it by setting the superview of the titlebar view in a WAYAppStoreWindow (or INAppStoreWindow) to post frame change notifications and then observing frame change notifications on this view. Add the following observer in your setup:

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(windowTitleBarFrameDidChange:)
                                             name:NSViewFrameDidChangeNotification
                                           object:window.titleBarView.superview];

And turn on/off frame change notifications when entered/exiting full-screen:

window.titleBarView.superview.postsFrameChangedNotifications = YES;

Then in the implementation of the windowTitleBarFrameWillChange: method, check to see when the titlebar will show by comparing with the last y position of it’s superview’s frame. Here is the code:

// Window titlebar heights.
#define kWindowTitlebarHeightDefault    22.0
#define kWindowTitlebarHeightStandard   37.0
#define kWindowTitlebarHeightExtended   82.0

- (void) windowTitleBarFrameDidChange:(NSNotification *)notification;
{
    NSView * titleBarView = [notification object];  // view is actually the titlebar container view

    if (NSMinX(_lastTitleBarFrame) == NSMinX(titleBarView.frame) &&
        NSWidth(_lastTitleBarFrame) == NSWidth(titleBarView.frame) &&
        NSHeight(_lastTitleBarFrame) == NSHeight(titleBarView.frame) &&
        NSMinY(_lastTitleBarFrame) == -kWindowTitlebarHeightDefault &&
        NSMinY(titleBarView.frame) > -kWindowTitlebarHeightDefault)                     // titlebar will show
    {
        [self windowTitleBarWillShow];
    }
    else if (NSMinX(_lastTitleBarFrame) == NSMinX(titleBarView.frame) &&
             NSWidth(_lastTitleBarFrame) == NSWidth(titleBarView.frame) &&
             NSHeight(_lastTitleBarFrame) == NSHeight(titleBarView.frame) &&
             NSMinY(_lastTitleBarFrame) == 0.0 && NSMinY(titleBarView.frame) < 0.0)     // titlebar will hide
    {
        [self windowTitleBarWillHide:YES];
    }
    else if (NSWidth(_lastTitleBarFrame) != NSWidth([NSScreen mainScreen].frame) &&
             NSWidth(titleBarView.frame) == NSWidth([NSScreen mainScreen].frame))       // just went full-screen
    {
        [self windowTitleBarWillHide:NO];
    }

    _lastTitleBarFrame = titleBarView.frame;
}

- (void) windowTitleBarWillHide:(BOOL)animate
{
    WAYAppStoreWindow * window = (WAYAppStoreWindow *)[(NSWindowController *)[[self windowControllers] objectAtIndex:0] window];
    NSView * themeFrame = window.titleBarView.superview.superview;    
    if (animate)
        [themeFrame animator].alphaValue = 0.0;
    else
        themeFrame.alphaValue = 0.0;
}

- (void) windowTitleBarWillShow
{
    WAYAppStoreWindow * window = (WAYAppStoreWindow *)[(NSWindowController *)[[self windowControllers] objectAtIndex:0] window];
    NSView * themeFrame = window.titleBarView.superview.superview;
    [themeFrame animator].alphaValue = 1.0;
}

- (void) windowWillEnterFullScreen:(NSNotification *)notification
{
    WAYAppStoreWindow * window = [notification object];
    [self setUpFullScreenTitleBarForWindow:window];
    _lastTitleBarFrame = NSZeroRect;
}

- (void) windowDidEnterFullScreen:(NSNotification *)notification;
{
    WAYAppStoreWindow * window = [notification object];
    window.titleBarView.superview.postsFrameChangedNotifications = YES;
    _fullscreenToolbarView.hidden = NO;
}

- (void) windowWillExitFullScreen:(NSNotification *)notification;
{
    WAYAppStoreWindow * window = [notification object];
    window.titleBarView.superview.postsFrameChangedNotifications = NO;
    [self setUpStandardTitleBarForWindow:window];
}

- (void) setUpNormalTitleBarForWindow:(WAYAppStoreWindow *)window
{
    window.appearance = nil;
    window.showsTitle = NO;
    window.titleBarHeight = kWindowTitlebarHeightExtended;
    window.verticalTrafficLightButtons = YES;
    window.centerTrafficLightButtons = YES;
    window.trafficLightButtonsLeftMargin = 13.0;

    _fullscreenToolbarView.hidden = YES;
}

- (void) setUpFullScreenTitleBarForWindow:(WAYAppStoreWindow *)window
{
    window.appearance = [NSAppearance appearanceNamed:NSAppearanceNameVibrantDark];
    window.showsTitle = YES;
    window.titleBarHeight = kWindowTitlebarHeightStandard;
    window.verticalTrafficLightButtons = NO;
    window.centerTrafficLightButtons = YES;
    window.trafficLightButtonsLeftMargin = 13.0;
    window.verticallyCenterTitle = YES;

    _fullscreenToolbarView.hidden = YES;
    _lastTitleBarFrame = NSZeroRect;
}

NB: I’m using a fork of WAYWindow that adds support for vertically centring the document title in the titlebar.