ページ

2008年3月11日火曜日

画面キャプチャその11 - Widgetの取り込み(2)

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

CGWindowListCopyWindowInfo を使って Widgetのウィンドウ情報も取れることが分かった。そこで以前作ったサンプル(FullScreenSample-4.zip)を改良して Widgetのキャプチャも取れるようにする。

以前のサンプルでは Dockという名のプロセスが持つ画面全体をほぼ覆うウィンドウを避ける為に kCGWindowName != nil のウィンドウを対象にしていた。

Widgetなしの場合のウィンドウリスト
2008-03-03 09:09:46.733 ScreenList[13010:10b] 00000019: SystemUIServer, , (1111,0,283,22)
2008-03-03 09:09:46.733 ScreenList[13010:10b] 00000053: Spotlight, , (1394,0,46,22)
2008-03-03 09:09:46.734 ScreenList[13010:10b] 00000020: SystemUIServer, (null), (0,0,1440,22)
2008-03-03 09:09:46.735 ScreenList[13010:10b] 00000006: Window Server, Shared Menubar, (0,0,1440,22)
2008-03-03 09:09:46.735 ScreenList[13010:10b] 00000014: Dock, (null), (0,22,1440,878)
2008-03-03 09:09:46.736 ScreenList[13010:10b] 00030269: Dock, Magic Mirror, (240,851,961,49)
 :


上記の Dock,(null),(0,22,1440,878) というウィンドウがこれにあたる。これは恐らく Dockのアニメーションなどスクリーン上での描画を行う為に存在しているウィンドウだと思われる。

ウィンドウの構成イメージはこんな感じか?


無条件にマウスのヒットテストを行うとこのウィンドウがヒットしてしまう為、弾く処理(kCGWindowName==nil)を行っていた。


ところが Widget も同様に kCGWindowOwnerName が Dock で kCGWindowName が nil となっている。

Widget有りの場合のウィンドウリスト
2008-03-03 09:13:00.245 ScreenList[13012:10b] 00014970: Dock, (null), (10,855,36,36)
2008-03-03 09:13:00.246 ScreenList[13012:10b] 00014973: Dock, (null), (834,53,437,375)
2008-03-03 09:13:00.247 ScreenList[13012:10b] 00014972: Dock, (null), (776,487,172,248)
2008-03-03 09:13:00.247 ScreenList[13012:10b] 00014971: Dock, (null), (177,241,510,473)
2008-03-03 09:13:00.247 ScreenList[13012:10b] 00059707: Dock, (null), (0,0,1440,900)
2008-03-03 09:13:00.248 ScreenList[13012:10b] 00000019: SystemUIServer, , (1111,0,283,22)
2008-03-03 09:13:00.250 ScreenList[13012:10b] 00000053: Spotlight, , (1394,0,46,22)
2008-03-03 09:13:00.257 ScreenList[13012:10b] 00000020: SystemUIServer, (null), (0,0,1440,22)
2008-03-03 09:13:00.260 ScreenList[13012:10b] 00000006: Window Server, Shared Menubar, (0,0,1440,22)
 :


その為、kCGWindowName==nil の処理だけでは Widgetも弾かれてしまう。 画面全体を覆う Dockのウィンドウだけを特定して弾く処理が必要である。CGWindowListCopyWindowInfoで得られる情報では kCGWindowOwnerName と kCGWindowBounds がこの判断に使えそうである(逆に言えば他は使えそうもない)。

CGWindowListCopyWindowInfoの情報
 kCGWindowAlpha = 1;
kCGWindowBounds = {
Height = 22;
Width = 322;
X = 1072;
Y = 0;
};
kCGWindowIsOnscreen = 1;
kCGWindowLayer = 25;
kCGWindowMemoryUsage = 41820;
kCGWindowName = "";
kCGWindowNumber = 19;
kCGWindowOwnerName = SystemUIServer;
kCGWindowOwnerPID = 119;
kCGWindowSharingState = 1;
kCGWindowStoreType = 2;



そこで (1) kCGWindowOwnerNameが "Dock"でかつ (2)サイズがほぼ画面と同じ、という条件で弾くことにする。判断用のメソッドを用意しこれを使う。

MyView.m
- (BOOL)isDockWindow:(CFDictionaryRef)window
{
CGRect rect;
CGRectMakeWithDictionaryRepresentation(CFDictionaryGetValue(window, kCGWindowBounds), &rect);
CFStringRef owner_name;
CFStringRef window_name;
window_name = CFDictionaryGetValue(window, kCGWindowName);
owner_name = CFDictionaryGetValue(window, kCGWindowOwnerName);

if ([@"Dock" isEqualToString:(NSString*)owner_name]) {
NSSize screen_size = [[NSScreen mainScreen] frame].size;
if (screen_size.width <= (rect.origin.x + rect.size.width) &&
screen_size.height <= (rect.origin.y + rect.size.height)) {
return NO;
}
}
return YES;
}


簡易だが実用上は多分これで十分だろう。

実行して Widgetを呼出してみる。


選択できて問題なくキャプチャ画像を取ることができた。



ソース:FullScreenSample-11.zip