16

I created an OS/X app that when it runs, I position the window in the center of the screen. In order to do this, it's essential that I include the title bar height in my calculation of the y value.

Is there a way to determine the default title bar? I'd expect (based on my experience with other windowing systems) that I have to query the window manager somehow...

Ky -
  • 30,724
  • 51
  • 192
  • 308
Suppy
  • 161
  • 1
  • 1
  • 5
  • I think you will probably have to do a little mojo to figure out the content view, and figure out where it lives in the window... see https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/index.html#//apple_ref/doc/uid/20000014-SW25 – Grady Player Mar 10 '15 at 03:37
  • You can configure the window to do that in IB. – uchuugaka Mar 10 '15 at 04:12
  • 7
    I'm not using IB. It makes me feel dirty. – Suppy Mar 10 '15 at 05:07
  • By the way, you can also just call [`NSWindow.center()`](https://developer.apple.com/documentation/appkit/nswindow/1419090-center) to accomplish this without complex calculations of frame size and titlebar height – Ky - Aug 22 '18 at 02:49

3 Answers3

17

I've come up with this solution. Note that when the window's styleMask includes fullSizeContentView, this returns 0.0, because in that case the titlebar effectively has no height.

As a Swift extension:

extension NSWindow {
    var titlebarHeight: CGFloat {
        frame.height - contentRect(forFrameRect: frame).height
    }
}

Usage:

let titlebarHeight = someWindow.titlebarHeight

As an Objective-C Category-Extension:

@implementation NSWindow (TitleBarHeight)

- (CGFloat) titlebarHeight
{
    return self.frame.size.height - [self contentRectForFrameRect: self.frame].size.height;
}

@end

Usage:

CGFloat titlebarHeight = someWindow.titlebarHeight;
Ky -
  • 30,724
  • 51
  • 192
  • 308
  • In the case where you want to treat a `fullSizeContentView` window as if it has a title bar, you can infer that height from the size and positions of the window buttons – Ky - May 24 '19 at 16:04
9

Answer for computing the height of the toolbar/titlebar area when using .fullSizeContentView on NSWindow

if let windowFrameHeight = self.view.window?.contentView?.frame.height,
    let contentLayoutRectHeight = self.view.window?.contentLayoutRect.height {
    let fullSizeContentViewNoContentAreaHeight = windowFrameHeight - contentLayoutRectHeight
}

fullSizeContentViewNoContentAreaHeight is the height you want. This is important to compute this value dynamically, because if you have an app using NSDocument and if the user creates a new document, the system might open this new document in a new tab. You might do this in updateViewConstraints() to detect this kind of changes.

Source: https://developer.apple.com/videos/play/wwdc2016/239/

vomi
  • 993
  • 8
  • 18
  • 3
    It's possible I'm missing something, but I changed the `windowFrameHeight` value to `view.window?.frame.height` and this is giving me the correct height *regardless* of whether the window has a full size content view. Super useful. Also works great as an extension on `NSWindow`: `var titleBarHeight: CGFloat { return frame.height - contentLayoutRect.height }` – robotspacer Sep 18 '20 at 19:17
6

It's not clear if you want to center the content rect and then build the frame rect to keep the content rect centered, or if you want to center the frame rect and are interested in the corresponding content rect.

In either case, NSWindow has methods that will help. Before you have an instance, you can use the class methods +frameRectForContentRect:styleMask: and +contentRectForFrameRect:styleMask:. Those take into account the window style as expressed by the style mask, but do not take any toolbar the eventual window may have into account.

If you're working with an existing instance, you can use the methods -frameRectForContentRect: and -contentRectForFrameRect:. Those use the current style of the window and take its toolbar into account, too. (The toolbar is within the frame rect but not the content rect.)

You seem determined to use the actual center of the screen for the window. However, you should consider using the -center method of NSWindow. It positions the window horizontally centered but actually higher than the true vertical center of the screen. It does that deliberately since that's deemed more prominent and immediate for the user.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154