ブログに戻る

macOSでウィンドウを所有しているプロセスを特定する方法

Activity Monitor、QuartzのウィンドウAPI、ターミナル、ProcXrayを使って、macOS上の特定のウィンドウがどのプロセスに属しているかを調べる方法を解説します。

macOSで浮いているダイアログ、反応しないログイン画面、正体不明のポップアップを見て、「このウィンドウはどのプロセスが作っているのか」と疑問に思ったことがあれば、それは珍しいことではありません。FinderやDockからは答えが見えず、Activity Monitorも一部しか助けてくれません。

結論から言うと

macOSで特定のウィンドウを所有しているプロセスを調べる最も信頼できる組み込みの方法は、Quartz Window ServicesのCGWindowListCopyWindowInfoを使ってkCGWindowOwnerPIDを取得し、そのPIDをpsで確認することです。Activity Monitorでも候補は絞れますが、ウィンドウとプロセスを正確に対応付けるならQuartzの方が確実です。

なぜmacOSではこの確認が分かりにくいのか

macOSには「このウィンドウを右クリックしてPIDを表示する」といった分かりやすい機能がありません。1つのアプリが複数のウィンドウ、補助プロセス、バックグラウンドエージェントを持つこともあり、タイトルやDockアイコンだけで判断すると誤解しやすくなります。

Appleのドキュメントを見ると理由が分かります。ウィンドウ情報の辞書ではkCGWindowOwnerPID必須キーですが、kCGWindowOwnerNamekCGWindowName任意キーです。つまり、所有PIDは安定して取得できますが、アプリ名やウィンドウタイトルは欠けている場合があります。

方法1:アプリがだいたい分かっているならActivity Monitorを使う

どのアプリがそのウィンドウを作っているかおおよそ見当が付いている場合、Activity Monitorは確認用の最も手軽なGUIツールです。

候補を絞る手順

  1. /Applications/Utilities/からActivity Monitorを開きます。
  2. View > Windowed Processesを選び、ウィンドウを作成できるプロセスだけを表示します。
  3. 親子関係も見たい場合は、View > All Processes, Hierarchicallyを選びます。
  4. アプリ名で検索し、情報パネルを開くかPIDを控えます。

「このポップアップはSafariなのか、Slackなのか、それともヘルパーアプリなのか」といった場面では十分役立ちます。

Activity Monitorの弱点

Activity Monitorが見せてくれるのはウィンドウを作成できるプロセスであり、「この特定のウィンドウこのPIDに属している」という直接対応ではありません。次のようなケースでは精度が下がります。

正確に調べたいならQuartzを使うべきです。

方法2:Quartz Window ServicesでウィンドウをPIDにマッピングする

AppleのCore Graphics APIであるCGWindowListCopyWindowInfoは、画面上のウィンドウに関するメタデータを返し、その中に所有PIDが含まれます。短いSwiftコマンドから直接呼び出せるので、フルアプリを作る必要はありません。

表示中のウィンドウと所有プロセスを一覧表示する

swift -e '
import Foundation
import CoreGraphics

let query = CommandLine.arguments.dropFirst().joined(separator: " ").lowercased()
let windows = CGWindowListCopyWindowInfo(
  [.optionOnScreenOnly, .excludeDesktopElements],
  kCGNullWindowID
) as? [[String: Any]] ?? []

for window in windows {
  let owner = (window[kCGWindowOwnerName as String] as? String) ?? ""
  let pid = (window[kCGWindowOwnerPID as String] as? Int) ?? 0
  let title = (window[kCGWindowName as String] as? String) ?? ""

  guard !owner.isEmpty else { continue }
  guard query.isEmpty ||
    owner.lowercased().contains(query) ||
    title.lowercased().contains(query) else { continue }

  print("PID: \(pid)\tApp: \(owner)\tWindow: \(title)")
}
' "Safari"

"Safari"の部分を、調べたいアプリ名やウィンドウタイトルの一部に置き換えてください。検索語を省略すれば、列挙できるすべての可視ウィンドウが出力されます。

出力の見方

本当に知りたいことが「このウィンドウはどのプロセスのものか」なら、これが最も有効な組み込み手段です。

PIDが分かった後にやること

PIDを取得したら、psで実行ファイルやコマンドラインを確認します。

ps -p <PID> -o pid,ppid,comm,args

例:

ps -p 1234 -o pid,ppid,comm,args

これで、怪しいウィンドウから具体的なバイナリ、親プロセス、起動引数までたどれます。

注意点

方法3:日常的に調査するならProcXrayを使う

この作業を頻繁に行うなら、生のコマンドだけでは面倒になってきます。**ProcXray**を使うと、正体不明のウィンドウから周辺のプロセス文脈まで素早く追跡できます。

ProcXrayが継続的な調査に向いている理由

アップデータ、helper、短命なバックグラウンドツールが関わる場合、PIDそのものよりもその周辺情報の方が重要になることが多いです。

関連ガイドもあわせてどうぞ。

Activity Monitor vs Quartz vs ProcXray

方法向いている用途強み制限
Activity Monitorざっと目視で確認したいとき標準搭載、使いやすい、PIDが見える任意のウィンドウを所有プロセスに直接対応付けられない
Quartzによるウィンドウ照会ウィンドウからPIDを正確に知りたいとき公式API、スクリプト化できる、正確出力後の追跡は手作業が必要
ProcXray本格的な調査や継続的なデバッグ親子関係、環境変数、署名、短命プロセスまで見える別途インストールが必要

要点: 一度だけ正確に調べるならQuartzで十分です。ウィンドウ、helper、短命プロセスを繰り返し調べるならProcXrayの方が効率的です。

FAQ

Activity Monitorで特定のウィンドウの所有プロセスを直接確認できますか?

直接はできません。Windowed Processesで候補を絞り込んだり、関連しそうなアプリのPIDを調べたりはできますが、1つのウィンドウをそのまま正確なPIDに対応付ける機能はありません。より正確なのはQuartz Window Servicesです。

ウィンドウの所有プロセスを調べるためのApple公式APIは何ですか?

Appleは、ウィンドウのメタデータを取得するCore Graphicsの関数としてCGWindowListCopyWindowInfoを文書化しています。返される辞書には必須キーとしてkCGWindowOwnerPIDが含まれるため、ウィンドウを所有プロセスへマッピングする際の正式な基準になります。

macOSのウィンドウタイトルが空になることがあるのはなぜですか?

kCGWindowNameは任意キーであり、常に存在するわけではないからです。ユーティリティウィンドウ、システムオーバーレイ、保護されたアプリの画面では、所有PIDだけが見えてタイトルは空になることがあります。

PIDを見つけた後は何をすればいいですか?

ps -p <PID> -o pid,ppid,comm,argsを実行して、実行ファイル、親プロセス、コマンドライン引数を確認してください。まだ怪しい場合は、その後にオープンファイル、ネットワーク接続、コード署名を調べるとよいです。

出典・参考資料

ProcXrayを無料でダウンロード → — 不審なウィンドウの背後にあるプロセスを、より速く把握できます。