CGWindowListCopyWindowInfo 是 macOS Core Graphics 框架中的一个函数,用于获取当前所有窗口的信息,比如窗口标题、应用名称、窗口位置、层级、是否可见、所属进程等。它返回一个包含窗口信息的数组(CFArray),其中每一项是一个描述窗口的 CFDictionary。
基本用法
func CGWindowListCopyWindowInfo(
_ option: CGWindowListOption,
_ relativeToWindow: CGWindowID
) -> CFArray?
1、option: CGWindowListOption类型
这是一个位掩码(OptionSet),用于指定想要列出的窗口类型,可以组合使用多个选项。常用选项包括:
.optionAll:所有窗口(包括后台、隐藏);
.optionOnScreenOnly:仅显示在屏幕上的窗口;
.optionOnScreenAboveWindow:屏幕上,在某个窗口之上的窗口;
.optionOnScreenBelowWindow:屏幕上,在某个窗口之下的窗口;
.optionIncludingWindow:包含指定窗口;
.excludeDesktopElements:排除桌面图标、壁纸等元素。
2、relativeToWindow: CGWindowID
这是参考的窗口 ID,如果用到了 optionOnScreenAboveWindow 或 optionOnScreenBelowWindow,就需要提供该窗口的 ID,否则填 kCGNullWindowID或者0。
kCGNullWindowID实际上就是0,它是一个特殊的窗口 ID,代表「没有特定窗口」或「空窗口引用」。
3、返回一个 CFArray,里面是 CFDictionary 类型的窗口信息,可以转换为 [[String: Any]] 来访问。
使用场景
1、获取所有窗口信息
if let windowInfoList = CGWindowListCopyWindowInfo([.optionOnScreenOnly, .excludeDesktopElements], kCGNullWindowID) as? [[String: Any]] {
for windowInfo in windowInfoList {
if let ownerName = windowInfo["kCGWindowOwnerName"] as? String,
let windowName = windowInfo["kCGWindowName"] as? String,
let bounds = windowInfo["kCGWindowBounds"] as? [String: CGFloat] {
print("App: \(ownerName), 标题: \(windowName), 尺寸: \(bounds)")
}
}
}
输出:
App: 微信, 标题: Item-0, 尺寸: ["X": 992.0, "Width": 38.0, "Y": 0.0, "Height": 36.0]
App: 轻截图片, 标题: Item-0, 尺寸: ["X": 882.0, "Width": 34.0, "Y": 0.0, "Height": 36.0]
App: Xcode, 标题: SnapSlim — StatusBarController.swift, 尺寸: ["X": 72.0, "Width": 1112.0, "Y": 82.0, "Height": 722.0]
App: Google Chrome, 标题: 方君宇, 尺寸: ["X": 160.0, "Width": 898.0, "Y": 302.0, "Height": 630.0]
App: Microsoft Word, 标题: macOS截取屏幕窗口CGWindowListCreateImage, 尺寸: ["X": 369.0, "Width": 1002.0, "Y": 69.0, "Height": 674.0]
CFArray字段
可提取的信息字段(字典 key):
1、kCGWindowOwnerName:String,应用名称;
2、kCGWindowOwnerPID:Int类型,进程 PID;
3、kCGWindowNumber:Int类型,窗口 ID;
4、kCGWindowName:String类型,窗口标题;
5、kCGWindowLayer:Int类型,窗口层级;
6、kCGWindowAlpha:Float类型,透明度;
7、kCGWindowBounds:[String: CGFloat] 类型,窗口位置和大小;
8、kCGWindowIsOnscreen:Bool类型,是否显示在屏幕上。
总结
CGWindowListCopyWindowInfo用于枚举桌面上所有可见窗口,可以获取指定App的前台窗口信息。
可以配合CGWindowListCreateImage,获取截图时窗口位置,辅助窗口管理器或屏幕录制工具。
扩展知识
窗口位置
通过kCGWindowBounds获取的窗口位置,默认是从左上角开始计算,而不是左下角,例如状态栏中控制中心的声音菜单:
App: 控制中心, 进程PID: 828, 窗口ID:17, 标题: Sound, 层级:25, 透明度:1.0, 尺寸: ["X": 1107.0, "Width": 38.0, "Y": 0.0, "Height": 36.0], 是否在屏幕上: true
它的Y轴为0,X轴为1107,表示从左上角开始计算的“声音”状态栏。

窗口层级
在kCGWindowLayer字段获取窗口层级时,常用的层级有:
0:kCGNormalWindowLevelKey,普通窗口,例如大多数 App 主窗口;
3:kCGFloatingWindowLevelKey,比普通窗口高,HUD、浮动面板;
8:kCGModalPanelWindowLevelKey,模态对话框,比如弹出警告框;
19:kCGUtilityWindowLevelKey,工具类窗口,例如颜色选择器;
20:kCGDockWindowLevelKey,Dock 的窗口层;
24、kCGMainMenuWindowLevelKey,菜单栏(但不是菜单内容);
25、kCGStatusWindowLevelKey,状态栏图标菜单,例如微信展开的菜单项;
101、系统内部使用的高层级窗口,例如系统菜单展开窗口、控制中心、Spotlight 等;
1000+:kCGCursorWindowLevelKey 以上,鼠标、拖拽指示器、屏保等特殊层。
0、3、8都是kCGWindowLayer返回的层级,kCGNormalWindowLevelKey、kCGFloatingWindowLevelKey则是层级对应的名称。
示例:
App: Window Server, 标题: StatusIndicator, 层级:2147483630, 透明度:1.0, 尺寸: ["Height": 18.0, "Width": 10.0, "X": 1278.0, "Y": 9.0]
App: 轻截图片, 标题: , 层级:101, 透明度:0.0, 尺寸: ["Height": 120.0, "Width": 127.0, "Y": 37.0, "X": 910.0]
App: 轻截图片, 进程PID: 77392, 窗口ID:218098, 标题: Item-0, 层级:25, 透明度:1.0, 尺寸: ["Height": 36.0, "Width": 34.0, "Y": 0.0, "X": 914.0]
App: Xcode, 标题: SnapSlim — StatusBarController.swift, 层级:0, 透明度:1.0, 尺寸: ["X": 63.0, "Height": 722.0, "Width": 1112.0, "Y": 152.0]
App: Google Chrome, 标题: macOS窗口信息CGWindowListCopyWindowInf – 方君宇, 层级:0, 透明度:1.0, 尺寸: ["Height": 749.0, "Width": 1148.0, "X": 96.0, "Y": 39.0]
Window Server层级2147483630,表示系统层级。
轻截图片有两个,分别是101层级和25层级:
101层级实际上是状态栏的下拉菜单,在截图时被隐藏,所以透明度是0。
25层级则对应的是状态栏的图标菜单。

Xcode和Google Chrome都是0层级,表示普通窗口。