macOSでウィンドウを指定し、ウィンドウを操作する事を考えている。そのためにウィンドウIDを一覧で表示する方法を調べる事にした。macOSの機能を使って動作するプログラムを作る場合、Objective-CかSwiftで実装する方が公式ドキュメントで説明が記述されているためやりやすい。
そもそも、同じような事をしている人達はいる。GetWindowIDは正にウィンドウIDを取得する機能を実装していた。このコードはとても小さいのだけれ、その小さいコードの中で、更に本質的な部分のみを抽出して動作を確認する。
CocoaとCoreGraphicsを使用して、ウィンドウIDを取得する。
#include <Cocoa/Cocoa.h>
#include <CoreGraphics/CGWindow.h>
int main(int argc, char **argv) {
NSArray *windows = (NSArray *)CGWindowListCopyWindowInfo(kCGWindowListExcludeDesktopElements,
kCGNullWindowID);
for(NSDictionary *window in windows) {
NSString *currentApp = window[(NSString *)kCGWindowOwnerName];
NSString *currentWindowTitle = window[(NSString *)kCGWindowName];
printf("%10d : %-50s : %s\n",
[window[(NSString *)kCGWindowNumber] intValue],
currentApp.UTF8String,
currentWindowTitle.UTF8String);
}
printf("Okay\n");
}
ビルドにはclangを使う。フレームワークにCocoaとCoreGraphicsを使用しているため、オプション引数として渡している。
clang ListWindowId.m -o ListWindowIdObc -framework CoreGraphics -framework Cocoa
これを実行すると ウィンドウID : アプリケーション名 : ウィンドウタイトル
という形式で、一覧を標準出力に出力する。
Objective-C
でできるのであれば、当然Swiftでもできる。Swiftでの実装方法も確認しておく。
import Cocoa
import CoreGraphics
func main() {
let windows = CGWindowListCopyWindowInfo(.optionAll, kCGNullWindowID) as! [[String: Any]]
for window in windows {
let windowId = window[kCGWindowNumber as String] as! Int
let appName = window[kCGWindowOwnerName as String] as! String
let title = (window[kCGWindowName as String] as? String) ?? ""
print(String(format:"%d: %@ : %@", windowId, appName, title))
}
}
main()
バイナリファイルを出力せず実行するには、 swift
コマンドを使う。
swift ListWindowId.swift
この実装をEmacsから確認できるようにしておこう。
(setq macos-window-list-executable
(let ((exec-path (list (expand-file-name "~/ng/symdon/articles/posts/1729078231"))))
(executable-find "ListWindowIdObc")))
(defun macos-window-list ()
(interactive)
(shell-command macos-window-list-executable))
(provide 'macos-window-list)
;; macos-window-list.el ends here