前回スクリーン上にあるウィンドウのリストを表示するプログラムを作ったが、今回全ての情報が表示できるように手を加えた。
こんな感じ。ずいぶんと横幅を取るようになったが全ての情報が一覧できるようになった。ついでに CGWindowListOptionも制御できるようにした。
ソース:WindowList-2.zip
前回は WindowItemなるクラスを用意して、わざわざCGWindowListCopyWindowInfo() から取得した情報をつめ直していた。しかしよくよく考えると、CGWindowListCopyWindowInfo()で得られる結果は CFDictionaryRef であり、CGWindow.h で定義される下記のようなキーを持っている。
/* sample
kCGWindowAlpha = 1;
kCGWindowBounds = {
Height = 439;
Width = 262;
X = 15;
Y = 22;
};
kCGWindowIsOnscreen = 1;
kCGWindowLayer = 0;
kCGWindowMemoryUsage = 510808;
kCGWindowName = "Account Information";
kCGWindowNumber = 21155;
kCGWindowOwnerName = EasyToDo;
kCGWindowOwnerPID = 5452;
kCGWindowSharingState = 1;
kCGWindowStoreType = 2;
kCGWindowWorkspace = 1;
*/
CFDictionaryRef は NSDicrionaryと互換があるし、キーバリュー値コーディングに準拠している。
ということはバインディングが使えるのでは?
そこでやってみた。まずビュー(NSTableViewのカラム)とモデル(CFDictionaryRefの配列)を仲介する NSObjectController を用意し、MyControllerのインスタンス変数 windowList へバインドする。後はすべてのカラムの Key Path にキー名を指定する(下記例では "kCGWindowOwnerName")。
するとあっさりと、できた。
個々のカラムの表示設定はGUI側の設定だけで、コーディングはいっさい行っていない。すごいな。バインディングは。
全体の関係はこんな感じ。
コードも非常に簡単になった。
-(void)reloadList
{
[windowList removeAllObjects];
UInt32 option = ...(略);
CFArrayRef list =CGWindowListCopyWindowInfo(option, [window windowNumber]);
CFDictionaryRef w;
CFIndex i;
for (i=0; i < CFArrayGetCount(list); i++) {
w = CFArrayGetValueAtIndex(list, i);
[windowList addObject:(NSDictionary*)w];
}
[arrayController rearrangeObjects];
}
カラムに関するコードがまったく無い。
- - - -
リストを眺めているといろいろと面白いことがわかる。この辺りはまた別に紹介しよう。
ただ問題があって見ての通り "Bounds" がうまく表示できていない。バインディング値を表示用に変換する仕組みが必要だな。