Skip to content

Instantly share code, notes, and snippets.

@usagimaru
Last active January 14, 2026 19:38
Show Gist options
  • Select an option

  • Save usagimaru/9d773f9cc1ec0ee3ec1f52dc01c2a78c to your computer and use it in GitHub Desktop.

Select an option

Save usagimaru/9d773f9cc1ec0ee3ec1f52dc01c2a78c to your computer and use it in GitHub Desktop.
macOSメニューバーの高さをバックグラウンドプロセスから正しく取得するには

macOSメニューバーの高さをバックグラウンドプロセスから正しく取得するには

バックグラウンドに常駐するアプリケーションでメニューバーの高さ値を取得したい場合、各種条件で正確な値を取ることができるシンプルな方法が1つ存在する。ただし、macOSのバージョンによってはこれがうまく動作せず(13.x Ventura)、代替手段でも条件を満たせない可能性がある。

考慮事項

  • バックグラウンドプロセスからメニューバーの高さを正しく取得したい
  • メニューバーを隠す設定が有効な場合、それを考慮する
  • メニューバーの高さはそもそも固定値ではない
  • ノッチ無しMacでは、どの解像度でもメニューバーの高さは24pt固定(常時表示の場合/単位はpxではないことに注意)
  • ノッチ付きMac (MacBookシリーズ) では、メニューバーの高さが可変的になる
    • 設定解像度によってメニューバーの高さが変化する
      • 27pt, 29pt, 34pt (33pt), 37pt, 43pt
      • ディスプレイ解像度「デフォルト」でメニューバー高さが37ptになる
      • 16-inch MacBook Proだと34pt相当は何故か33ptになるらしい
      • 参考:Designing macOS menu bar extras
  • メニューバーはひとつとは限らない(マルチディスプレイ、Spaces)
  • マルチディスプレイ環境
    • 複数個のディスプレイがある環境では、メニューバーを表すウインドウも複数存在する
    • ノッチ付きMacにノッチ無しのディスプレイを接続している環境が考えられる(ディスプレイによってメニューバーの高さが異なる)

前提環境

  • macOS Ventura 13.0, Sequoia 15.7
  • Studio Display (2022), MacBook Air 14-inch (2025)
  • AppKit

😤 NSMenuのmenuBarHeight

結局この方法が一番確実で正確と考えられる。以前確認したmacOS 13.x Venturaにおいてはバックグラウンド時に問題があったが、少なくともmacOS Sequoia 15.7の環境では、これでうまく動作しているように見える。

let height = NSApp.mainMenu?.menuBarHeight

https://developer.apple.com/documentation/appkit/nsmenu/menubarheight

一つ注意点は、NSMenu().menuBarHeightなど別のインスタンスからだと値が取れないので、NSApplicationのシングルトンから得られるmainMenuに対して行うこと。

Sequoia 15.7環境で以下の条件で確認したが、問題はなかった。

  • メニューバーを非表示にする設定が有効
  • アプリがバックグラウンドの状態
  • LSUIElement=true

一方Venturaではアプリがバックグラウンドの状態でメニューバーが非表示だと、高さ値を取れなかった🫠。いつの時点でこのバグが修正されたのかはわからないが、Sequoiaでは問題ないと言える。

メニューバーの可視状態判別メソッドNSMenu.menuBarVisible()は、アプリケーションがフォアグラウンド時のみ正確に機能する

メニューバーを非表示→表示と切り替えた際の表示状態を判別するには次の方法が使えるが、アプリがバックグラウンドにいると正確な値を返さない模様。

let isMenuBarVisible = NSMenu.menuBarVisible()

🫠 NSStatusBar.system.thickness は間違った値を返す

NSStatusBar.system.thickness で得られる値はmacOS Ventura時点で22ptで、これは24ptよりも小さい。昔のmacOSではメニューバーの高さは22ptであったので一致していたが、少なくともBig Sur以降ではずれている。

どうやらAppleは「正しい」としているらしい。 feedback-assistant/reports#140

The default value of this property is 20.0. The status bar returned by the system has a thickness of 22 pixels, which corresponds to the thickness of the menu bar. https://developer.apple.com/documentation/appkit/nsstatusbar/1534591-thickness

🤔 CGWindowListCopyWindowInfo() でメニューバーっぽいウインドウを探す

以下のようなコードでデスクトップ上のウインドウ一覧の中から、メニューバーっぽいやつを探す。kCGWindowBoundsでフレームが取れるので、heightがそのままメニューバーの高さになると思われる。

if let windowInfo = CGWindowListCopyWindowInfo(.optionAll, kCGNullWindowID) as? [Dictionary<CFString, AnyObject>] {
	windowInfo.forEach {
		if let windowOwnerName = $0[kCGWindowOwnerName] as? String, windowOwnerName == "Window Server",
		   let windowName = $0[kCGWindowName] as? String, windowName == "Menubar" {
			print("\($0)")
		}
	}
}

絞り込み条件:

  • kCGWindowOwnerName … "Window Server"
  • kCGWindowName … "Menubar"
  • kCGWindowBoundswidth … デスクトップの幅と一致

要注意なのは、確実にメニューバーを1つに絞りきれる保証がないことと、どうやらデスクトップスペース(Spaces)の数だけメニューバーが存在するようで、.optionAllだと1つに定まらない。フルスクリーンウインドウのスペースにもメニューバーが1つあると見做される。メニューバーを自動的に非表示にする設定にあると、Y座標がマイナス値になる。MacBookと外部ディスプレイの環境ではメニューバーの高さがディスプレイごとに変わると考えられる。

onScreenOnlyだと現在表示しているスクリーンに絞り込めるが、メニューバーを自動で隠す設定が有効だと(隠れていると)、そもそもメニューバーの情報が含まれなくなる。

kCGWindowName は、Menubarに限っては画面収録のパーミッションがなくても得られる。

😑 NSScreenのフレームから計算

例えば以下のコードでは 25pt の値を取得できるが、 メニューバーを隠すオプションを有効にすると常に 1pt を返す。 (macOS 13.2.1) 1pt を除外すると、それぞれ 24pt, 0pt となり、メニューバーの高さを表しているように見える。余分な 1pt は境界線分?

メニューバーを自動で隠すオプションを有効にして、カーソルを重ねて表示してもその高さは1ptを返すことに注意。つまり、 このオプションが有効だと本来の高さ値を確認することはできない。 惜しい。😩

一応バックグラウンドからも正しく取れているように見える。(macOS 13.2.1) ノッチ付きMacでは未検証。

if let screen = NSScreen.main {
	// Maybe 25pt, or 1pt
	let menubarHeight = screen.frame.maxY - screen.visibleFrame.maxY
	// Maybe 24pt, or 0pt
	let menubarHeightActual = screen.frame.maxY - screen.visibleFrame.maxY - 1
}

マウスカーソルがいるスクリーンを得るには以下のコードを使う。上記コードの NSScreen.main の代わりにすると、操作中スクリーンを絞ったユースケースに対応できて良いかもしれない。

import Cocoa

extension NSScreen {
	
	class func screenThatUnderMouse() -> NSScreen? {
		NSScreen.screens.first {
			NSMouseInRect(NSEvent.mouseLocation, $0.frame, false)
		}
	}
	
}
if let screen = NSScreen.screenThatUnderMouse() {
	// Maybe 25pt, or 1pt
	let menubarHeight = screen.frame.maxY - screen.visibleFrame.maxY
}

😗 AppleScriptで最前面アプリケーションのメニューバーのサイズを取得

この方法だと、Ventura環境でメニューバーを非表示でも正確な高さ値を得られた。AppleEvent (AppleScript) 頼るコストが生じるが、古いOSでは代替手段として検討すると良いかもしれない。

tell application "System Events" to tell (process 1 where frontmost is true)
	set appName to name
	
	tell menu bar 1
		set {menuBarWidth, menuBarHeight} to the size
	end tell
end tell

return {appName, {menuBarWidth, menuBarHeight}}

-- result:
-- {"Script Editor", {2560, 24}}
-- {"Finder", {2560, 24}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment