吹き出しウィンドウ最終回。三角を中心に調整し、キャプチャ対象が無い場合のメッセージを表示させるようにした。
これで一段落。
- - - -
今週末に最後のα版(4)をリリースする予定。
2008年12月12日金曜日
2008年12月11日木曜日
吹き出しウィンドウ(8)
ウィンドウリストからステータスバーの位置を割り出すことにした。NSProcessInfo#processIdentifierで自分のPIDを取得して、これとレイヤー(kCGStatusWindowLevel==25)の2つの条件からステータスバーのウィンドウを割り出す。
+ (Window*)statusBarWindow
{
CFArrayRef ar = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
CFDictionaryRef window_ref;
CFIndex i;
int status_bar_pid = [[NSProcessInfo processInfo] processIdentifier];
int owner_pid;
int layer;
for (i=0; i < CFArrayGetCount(ar); i++) {
window_ref = CFArrayGetValueAtIndex(ar, i);
CFNumberGetValue(CFDictionaryGetValue(window_ref, kCGWindowOwnerPID),
kCFNumberIntType, &owner_pid);
CFNumberGetValue(CFDictionaryGetValue(window_ref, kCGWindowLayer),
kCFNumberIntType, &layer);
if (owner_pid == status_bar_pid && layer == kCGStatusWindowLevel) {
break;
}
}
Window* window = [[[Window alloc] initWithWindowDictionaryRef:window_ref] autorelease];
CFRelease(ar);
return window;
}
Windowクラスは CGWindowListCopyWindowInfo から取得した情報を格納するObjective-Cのラッパークラス。
これで位置が取れた。キャプチャ後にファイル名を表示させてみる。

おお、出た。
2008年12月10日水曜日
吹き出しウィンドウ(7)
ステータスバー(NSStatusBar)内の位置を取得したい。NSStatusBar や NSStatusItem のAPIには用意されていない。ネットを調べても決定的な方法を見つけられなかった。
CocoaBuilderではカスタムビューを NSStatusBarへセットし、そこから座標を得る方法が検討されていた。
Cocoabuilder - Position of NSStatusItem
WindowListで調べてみるとステータスバー上のアイコンが一つのウィンドウとして割り当てられているのが分かる。下の図では一番上がステータスバー上の SimpleCapのアイコン領域を表している。
このウィンドウが取得できれば位置が得られる。
正攻法でウィンドウを取る手段がみつからないとなると、ウィンドウリストから得るしかないか。
例えば、自分と同じ PID を持っていて origin.y == 0 のウィンドウ、といった方法で狙い撃ちする。
場当たり的な感じもするが、これで十分かも。
2008年12月9日火曜日
吹き出しウィンドウ(6)
2008年12月8日月曜日
吹き出しウィンドウ(5)
フェードアウト効果を追加する。その為に FukidashiControllerに状態変数を追加する。
状態(0) FUKIDASHI_STATE_HIDE 非表示状態 ※初期状態
状態(1) FUKIDASHI_STATE_SHOW メッセージ表示状態
状態(2) FUKIDASHI_STATE_FADEOUT フェードアウト途中の状態
クライアントコードから showMessage: が送られると状態(0)から状態(1)へ遷移する。しばらくメッセージを表示した後、タイマーによって状態(1)から状態(2)への遷移が起きる。この状態ではウィンドウの透明度が徐々に上がり(すなわちフェードアウトが進み)、最後に何も表示されなくなり状態(0)へ戻る。
下記は状態遷移用メソッド。状態(1) FUKIDASHI_STATE_SHOWへの遷移で NSTimerを起動している。
- (void)changeState:(int)state
{
switch (state) {
case FUKIDASHI_STATE_HIDE:
[_window orderOut:self];
break;
case FUKIDASHI_STATE_SHOW:
if (_state != FUKIDASHI_STATE_HIDE && [_timer isValid]) {
[_timer invalidate];
}
_count = 0;
[_window setContentSize:[_view areaSize]];
[_window setAlphaValue:1.0];
[_window makeKeyAndOrderFront:self];
_timer = [NSTimer timerWithTimeInterval:FUKIDASHI_TIME_INTERVAL
target:self
selector:@selector(callBack:)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
break;
case FUKIDASHI_STATE_FADEOUT:
_count = 0;
break;
default:
break;
}
_state = state;
}
タイマーの処理はこんな感じ。
- (void)callBack:(NSTimer*)timer
{
_count++;
switch (_state) {
case FUKIDASHI_STATE_SHOW:
if (_count >= (int)((float)_showtime/FUKIDASHI_TIME_INTERVAL)) {
[self changeState:FUKIDASHI_STATE_FADEOUT];
}
break;
case FUKIDASHI_STATE_FADEOUT:
if (_count >= (int)(FUKIDASHI_FADEOUT_TIME/FUKIDASHI_TIME_INTERVAL)) {
[self changeState:FUKIDASHI_STATE_HIDE];
[timer invalidate];
} else {
[_window setAlphaValue:(1.0-_count*FUKIDASHI_TIME_INTERVAL/FUKIDASHI_FADEOUT_TIME)];
}
break;
default:
break;
}
}

サンプル:Fukidashi-4.zip
2008年12月7日日曜日
吹き出しウィンドウ(4)
吹き出しの尖った三角を追加した。
三角形は位置決めして NSBezierPathで描く。
NSPoint p = NSMakePoint(OFFSET_X, background_rect.size.height+TRIANGLE_HEIGHT+SHADOW_OFFSET);
[triangle_path moveToPoint:p];
p.x += TRIANGLE_HEIGHT/1.5;
p.y -= TRIANGLE_HEIGHT;
[triangle_path lineToPoint:p];
p.x -= (TRIANGLE_HEIGHT/1.5)*2;
[triangle_path lineToPoint:p];
[triangle_path closePath];
[triangle_path fill];
サンプル:Fukidashi-3.zip
2008年12月6日土曜日
吹き出しウィンドウ(3)
吹き出しの続き。
描画の目処が立ったので、アプリへ組み込める様にクラスを整備する。ビューに加えて新たに2つのクラスを追加した。
FukidashiView
FukidashiWindow
FukidashiController
FukidashiWindowはビュー(FukidashiView)を載せるウィンドウ。FukidashiControllerは名前の通りコントローラで、この機能を使うクライアントコードと、吹き出し表示の間を調整する。
(イメージ)
<<クライアント>>
|
|表示指示
↓
FukidashiContoroller
|
|表示設定・大きさ調整
↓
FukidashiWindow
FukidashiView
位置決め後回しとして今回は渡された文字列をこの仕組みで表示するところまで実装した。コントローラの実装はこんな感じ。
FukidashiController.m
- (id)init
{
self = [super init];
if (self) {
_window = [[FukidashiWindow alloc] init];
_view = [[FukidashiView alloc] init];
[_window setContentView:_view];
}
return self;
}
- (void)showMessage:(NSString*)message
{
[_view setMessage:message];
NSSize window_size = [_view areaSize];
[_window setContentSize:window_size];
[_window makeKeyAndOrderFront:self];
}
#initでウィンドウとビューのインスタンスを作り紐づける。クライアントコードから showMessageメッセージが来たらビューに文字列を渡した後、表示サイズを計算させウィンドウサイズに設定する。
実行結果はこうなる。

サンプル:Fukidashi-2.zip
2008年12月5日金曜日
吹き出しウィンドウ(2)
まずは見た目から。カスタムビューを用意してウィンドウへ貼付けて描画してみた。
こんな感じ。
ビューは渡された文字列を元に黒い背景の大きさを計算して描画している。
サンプル:Fukidashi.zip